{"id":27583,"date":"2018-10-24T00:01:51","date_gmt":"2018-10-24T07:01:51","guid":{"rendered":"http:\/\/devblogs.microsoft.com\/premier-developer\/?p=27583"},"modified":"2019-02-14T20:17:47","modified_gmt":"2019-02-15T03:17:47","slug":"using-adal-js-with-angular4","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/premier-developer\/using-adal-js-with-angular4\/","title":{"rendered":"Using ADAL.js with Angular4+"},"content":{"rendered":"<p>In the following post, App Dev Managers <a href=\"https:\/\/www.linkedin.com\/in\/vsaroopchand\/\" target=\"_blank\" rel=\"noopener\">Vishal Saroopchand<\/a> and Sr. Dev Consultant Hemant Kathuria explain how you can wrap ADAL.js with Angular4+.<\/p>\n<hr \/>\n<p>This is an update post to a previous <a href=\"https:\/\/blogs.msdn.microsoft.com\/premier_developer\/2017\/04\/26\/using-adal-with-angular2\/\">article<\/a> published in April 2017 explaining how to wrap ADAL.js with Angular2+. The previous article is no longer relevant given the changes to the Angular framework. This new post explains a reimplementation which uses the PathLocationStrategy and Angular features such as HttpInterceptor and InjectionToken.<\/p>\n<h4>The project setup<\/h4>\n<p>This new sample was scaffolded with Angular-CLI 7.0.0-rc.1; it uses Bootstrap 3.3.7 to create a very basic layout. The top navbar has a Sign-in\/Sign-out buttons to trigger the OpenID Connect Implicit Flow with ADAL.js. Read more about OpenID Connect and AAD <a href=\"https:\/\/docs.microsoft.com\/en-us\/azure\/active-directory\/develop\/v1-protocols-openid-connect-code\">here<\/a>.<\/p>\n<p><em>Figure 1: Angular tools used in this sample<\/em><\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/31\/2019\/04\/110.png\"><img decoding=\"async\" title=\"1\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/31\/2019\/04\/1_thumb1.png\" alt=\"1\" width=\"480\" height=\"516\" border=\"0\" \/><\/a><\/p>\n<h4>Register applications in Azure Active Directory<\/h4>\n<p>To run this sample, you must register two Azure AD Application.<\/p>\n<p>The first application named <strong>Client-App<\/strong> will be used for OpenID Connect Implicit Flow to fetch User Identity and claims. See the following <a href=\"https:\/\/docs.microsoft.com\/en-us\/azure\/active-directory\/develop\/id-tokens\">link<\/a> for list of claims in the JWT Token.<\/p>\n<p>The second application named <strong>Server-App<\/strong> will used for the WebAPI resource. The <strong>Client-App<\/strong> (Angular SPA) will request an <b>access token<\/b> for <strong>Server-App<\/strong> when route Values is activated. The<strong> access token<\/strong> will be used as the HttpRequest Authorization Header\/Bearer Token for WebAPI Authorization.<\/p>\n<p>Client-App Setup<\/p>\n<ol>\n<li>In the Azure Portal, navigate to Azure Active Directory &gt;App registrations, click\u202f <strong>New application registration<\/strong><\/li>\n<\/ol>\n<ol start=\"2\">\n<li>Set Name to <strong>Client-App<\/strong><\/li>\n<\/ol>\n<ol start=\"3\">\n<li>Set Application-Type to <strong>Web app \/ API<\/strong><\/li>\n<\/ol>\n<ol start=\"4\">\n<li>Set Sign-on URL to <strong>http:\/\/localhost:4200\/frameredirect<\/strong><\/li>\n<\/ol>\n<ol start=\"5\">\n<li>Press the\u202f <strong>Create<\/strong>\u202fbutton<\/li>\n<\/ol>\n<p>Server-App Setup<\/p>\n<ol>\n<li>In the Azure Portal, navigate to Azure Active Directory &gt;App registrations, click\u202f <strong>New application registration<\/strong><\/li>\n<\/ol>\n<ol start=\"2\">\n<li>Set Name to <strong>Service-App<\/strong><\/li>\n<\/ol>\n<ol start=\"3\">\n<li>Set Application-Type to <strong>Web app \/ API<\/strong><\/li>\n<\/ol>\n<ol start=\"4\">\n<li>Set Sign-on URL to <strong>https:\/\/localhost:44351<\/strong><\/li>\n<\/ol>\n<ol start=\"5\">\n<li>Press the <strong>Create<\/strong>\u202fbutton<\/li>\n<\/ol>\n<p>Edit application <strong>Client-App<\/strong>, click Edit Manifest, change property oauth2AllowImplicitFlow to <strong>true<\/strong> and <strong>Save<\/strong><\/p>\n<p>Edit application <strong>Client-App<\/strong>, click Settings &gt; Required permissions &gt; Add &gt; Select an API<\/p>\n<ul>\n<li>Search for \u201cServer-App\u201d and click Select<\/li>\n<li>Click checkbox <strong>Delegated Permissions<\/strong> and Save<\/li>\n<\/ul>\n<ul>\n<li>Finally, click <strong>Grant Permissions<\/strong><\/li>\n<\/ul>\n<p>For more on application registration, see docs below.<\/p>\n<p><a href=\"https:\/\/docs.microsoft.com\/en-us\/azure\/active-directory\/active-directory-app-registration\">https:\/\/docs.microsoft.com\/en-us\/azure\/active-directory\/active-directory-app-registration<\/a><\/p>\n<p><a href=\"https:\/\/docs.microsoft.com\/en-us\/azure\/active-directory\/develop\/quickstart-v1-add-azure-ad-app\">https:\/\/docs.microsoft.com\/en-us\/azure\/active-directory\/develop\/quickstart-v1-add-azure-ad-app<\/a><\/p>\n<h4>Key Implementation Details<\/h4>\n<h4>Configuration for ADAL<\/h4>\n<p>The new implementation uses InjectToken to wrap the configuration which includes ClientID, TenantID, ResourceID and endpoint for the WebAPI. A configuration service is used to construct the bare-minimum settings for ADAL.JS. You will find the complete configuration options <a href=\"https:\/\/github.com\/AzureAD\/azure-activedirectory-library-for-js\/wiki\/Config-authentication-context\">here<\/a>. This is all configured as a value provider in the application module.<\/p>\n<p><em>Figure 2: Define InjectionToken in <strong>app.config.ts<\/strong><\/em><\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/31\/2019\/04\/28.png\"><img decoding=\"async\" title=\"2\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/31\/2019\/04\/2_thumb1.png\" alt=\"2\" width=\"705\" height=\"299\" border=\"0\" \/><\/a><\/p>\n<p><em>Figure 3: Configure APP_CONFIG Token as value provider in <strong>app.module.ts<\/strong><\/em><\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/31\/2019\/04\/37.png\"><img decoding=\"async\" title=\"3\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/31\/2019\/04\/3_thumb1.png\" alt=\"3\" width=\"641\" height=\"330\" border=\"0\" \/><\/a><\/p>\n<p><em>Figure 4: Configuration for ADAL.js in <strong>adal-config.service.ts<\/strong><\/em><\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/31\/2019\/04\/47.png\"><img decoding=\"async\" title=\"4\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/31\/2019\/04\/4_thumb1.png\" alt=\"4\" width=\"653\" height=\"445\" border=\"0\" \/><\/a><\/p>\n<h4>The ADAL.js Wrapper<\/h4>\n<p>Like the original implementation, we wrap ADAL.js AuthenticationContext as an Injectable Service. One change to note is function acquireTokenResilient; we use a simple retry policy to fetch the token.<\/p>\n<p><em>Figure 5: ADAL.js Wrapper service in <strong>adal.service.ts<\/strong><\/em><\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/31\/2019\/04\/55.png\"><img decoding=\"async\" title=\"5\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/31\/2019\/04\/5_thumb1.png\" alt=\"5\" width=\"690\" height=\"559\" border=\"0\" \/><\/a><\/p>\n<h4>Guard for protected routes<\/h4>\n<p>The CanActivate guard remains the same as the original implementation. It will redirect to route AccessDenied if UserInfo is not present.<\/p>\n<p><em>Figure 6: CanActivate Guard using ADAL.js cached userInfo to enforce Authorization<\/em><\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/31\/2019\/04\/63.png\"><img decoding=\"async\" title=\"6\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/31\/2019\/04\/6_thumb.png\" alt=\"6\" width=\"780\" height=\"321\" border=\"0\" \/><\/a><\/p>\n<h4>HttpClient &amp; Bearer Token<\/h4>\n<p>The new implementation uses Angular HttpInterceptor to frame the HttpRequests with Authorization Header for WebAPI calls. Using HttpInterceptor keeps our BaseService HttpClient decoupled from to the AdalService unlike the Angular2 implementation where Http Interception was not yet supported.<\/p>\n<p><em>Figure 7: Frame HttpRequest to WebAPI with Authorization header in <strong>auth-interceptor.ts<\/strong><\/em><\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/31\/2019\/04\/72.png\"><img decoding=\"async\" title=\"7\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/31\/2019\/04\/7_thumb.png\" alt=\"7\" width=\"790\" height=\"508\" border=\"0\" \/><\/a><\/p>\n<h4>Handling Redirect and processing id_token<\/h4>\n<p>Upon successfully authenticating, OpenId Connect will redirect back to our application using the redirect_uri setting in Client-App. Route frameredirect is configured to handle this callback which contains the id_token in the URI hash. The frameredirect component simply calls ADALs AuthenticationContext.handleWindowCallback to extract and cache id_token from URL. You can do additional work here but, in this sample, we simply redirect back to the home route.<\/p>\n<p><em>Figure 8: FramedRedirect HomeComponent invoking ADAL.js handleCallback<\/em><\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/31\/2019\/04\/82.png\"><img decoding=\"async\" title=\"8\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/31\/2019\/04\/8_thumb.png\" alt=\"8\" width=\"800\" height=\"200\" border=\"0\" \/><\/a><\/p>\n<h4>The End Result<\/h4>\n<p><em>Figure 9: Initial State without authentication<\/em><\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/31\/2019\/04\/92.png\"><img decoding=\"async\" title=\"9\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/31\/2019\/04\/9_thumb.png\" alt=\"9\" width=\"749\" height=\"103\" border=\"0\" \/><\/a><\/p>\n<p><em>Figure 10: Authenticated State after user clicks Sign-In<\/em><\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/31\/2019\/04\/102.png\"><img decoding=\"async\" title=\"10\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/31\/2019\/04\/10_thumb.png\" alt=\"10\" width=\"780\" height=\"111\" border=\"0\" \/><\/a><\/p>\n<p><em>Figure 11: Calling WebAPI with Authorization header for Server-App resource<\/em><\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/31\/2019\/04\/113.png\"><img decoding=\"async\" title=\"11\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/31\/2019\/04\/11_thumb.png\" alt=\"11\" width=\"780\" height=\"466\" border=\"0\" \/><\/a><\/p>\n<p>Clone the complete sample <a href=\"https:\/\/github.com\/vsaroopchand\/angular-adal-sample\">here<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This is an update post to a previous article published in April 2017 explaining how to wrap ADAL.js with Angular2+. The previous article is no longer relevant given the changes to the Angular framework. This new post explains a reimplementation which uses the PathLocationStrategy and Angular features such as HttpInterceptor and InjectionToken.<\/p>\n","protected":false},"author":582,"featured_media":27584,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[122],"tags":[84,51,109,3],"class_list":["post-27583","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-angular","tag-adal","tag-angular","tag-javascript","tag-team"],"acf":[],"blog_post_summary":"<p>This is an update post to a previous article published in April 2017 explaining how to wrap ADAL.js with Angular2+. The previous article is no longer relevant given the changes to the Angular framework. This new post explains a reimplementation which uses the PathLocationStrategy and Angular features such as HttpInterceptor and InjectionToken.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts\/27583","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/users\/582"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/comments?post=27583"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts\/27583\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/media\/27584"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/media?parent=27583"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/categories?post=27583"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/tags?post=27583"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}