{"id":8564,"date":"2021-12-05T06:00:43","date_gmt":"2021-12-05T06:00:43","guid":{"rendered":"https:\/\/blogs.aaddevsup.xyz\/?p=8564"},"modified":"2021-12-08T20:41:00","modified_gmt":"2021-12-08T20:41:00","slug":"msal-js-spa-client-performing-authorization-code-grant-flow-to-adfs-2019","status":"publish","type":"post","link":"https:\/\/blogs.aaddevsup.xyz\/2021\/12\/msal-js-spa-client-performing-authorization-code-grant-flow-to-adfs-2019\/","title":{"rendered":"MSAL.JS SPA client performing Authorization Code Grant flow to ADFS 2019"},"content":{"rendered":"\n

This blog walks through how to set up MSAL.JS to authenticate directly to ADFS 2019 Server using Authorization Code Grant flow to get an Access Token and then call a Web API with that Access Token. We will go over the following steps to get this the samples working:<\/p>\n\n\n\n

  1. App Registrations for both the Single Page Application (SPA) client app and the web API app<\/li>
  2. Enable Cross-origin Request Sharing (CORS) on ADFS 2019 Server<\/li>
  3. Construct a SPA client application project<\/li>
  4. Construct a web API application project<\/li><\/ol>\n\n\n\n

    Let’s get into the detail for each of the above steps.<\/p>\n\n\n\n

    App Registrations<\/h3>\n\n\n\n

    Follow steps 1 – 8 In the App Registration in ADFS<\/a> Documentation to add a new Application Group. We will register a Native Public App type and a web API type in this Application Group:<\/p>\n\n\n\n

    Note<\/strong>: unlike Azure AD, ADFS does not have a concept of Single Page Application client (platform type) so we will treat a SPA app as a generic native client app. In order for one application to call another application with an Access Token, both of these applications have to be in the same Application Group.<\/p>\n\n\n\n

    I use the following settings in my App Registration:<\/p>\n\n\n\n

    Native application Redirect URI: http:\/\/localhost:3000<\/p>\n\n\n\n

    Take note of the Native application’s Client Id. We will need it later for our client project.<\/p>\n\n\n\n

    \"\"<\/figure>\n\n\n\n

    Web API Relying Party identifier: https:\/\/localhost:44320. Take note of this value since we will use it for both the web API sample and the SPA client app sample below.<\/p>\n\n\n\n

    \"\"<\/figure>\n\n\n\n

    Enable CORS feature<\/h3>\n\n\n\n

    Refer to Customize HTTP security response headers with AD FS 2019<\/a> for more info.<\/p>\n\n\n\n

    CORS is disabled by default on ADFS 2019 Server. We need to enable CORS in order for our MSAL.JS V2 SPA application to authenticate to ADFS 2019 Server. Run the following PowerShell Command on the ADFS Server to enable CORS and set the trusted origin value to the domain of the application making the CORS request (http:\/\/localhost:3000 in this case for our SPA client app).<\/p>\n\n\n\n

    Set-AdfsResponseHeaders -EnableCORS $true\nSet-AdfsResponseHeaders -CORSTrustedOrigins http:\/\/localhost:3000<\/pre>\n\n\n\n

    SPA client app sample using MSAL.JS V2<\/h3>\n\n\n\n

    The code for this application is derived from this<\/a> sample. The complete sample is here <\/a>on github. Modify the project’s App\/AuthConfig.js file to put in your app registration info:<\/p>\n\n\n\n

    The values for msalConfig’s auth’s (below) clientId and redirectUri comes from Native App registration above. Fill in the authority and knownAuthorities values with your ADFS environment. For apiConfig’s scopes, the web API scope should be in this format: <web API Relying Party Identifier>\/<scope name><\/strong>, so I set this value to https:\/\/localhost:44320\/openid (we enabled openid for permission during registration).<\/p>\n\n\n\n

    const msalConfig = {\n    auth: {\n        clientId: \"<Native application client ID>\",\n        authority: \"https:\/\/<FQDN_OF_ADFS_Server>\/adfs\/\", \/\/ e.g https:\/\/contoso.com\/adfs\/\n        knownAuthorities: [\"https:\/\/<FQDN_OF_ADFS_Server>\/adfs\/\"], \/\/ e.g https:\/\/contoso.com\/adfs\/\n        redirectUri: \"<Native Application's redirect URI>\", \/\/ \"http:\/\/localhost:3000\" for this sample\n        protocolMode: \"OIDC\"\n    },\n    cache: {\n        cacheLocation: \"localStorage\", \/\/ This configures where your cache will be stored\n        storeAuthStateInCookie: false, \/\/ Set this to \"true\" if you are having issues on IE11 or Edge\n    },\n};\n\n\/\/ Add here the endpoints and scopes for the web API you would like to use.\nconst apiConfig = {\n    uri: \"https:\/\/localhost:44321\/api\/values\", \/\/ e.g. http:\/\/localhost:5000\/api\n    scopes: [\"<fully qualified scope name for web API>\"] \/\/ e.g. [\"https:\/\/localhost:44320\/openid\"]\n};\n\n\/**\n * Scopes you add here will be prompted for user consent during sign-in.\n * By default, MSAL.js will add OIDC scopes (openid, profile, email) to any login request.\n * For more information about OIDC scopes, visit: \n * https:\/\/docs.microsoft.com\/en-us\/azure\/active-directory\/develop\/v2-permissions-and-consent#openid-connect-scopes\n *\/\nconst loginRequest = {\n    scopes: [\"openid\", \"profile\"]\n};\n\n\/**\n * Scopes you add here will be used to request a token from Azure AD to be used for accessing a protected resource.\n * To learn more about how to work with scopes and resources, see: \n * https:\/\/github.com\/AzureAD\/microsoft-authentication-library-for-js\/blob\/dev\/lib\/msal-browser\/docs\/resources-and-scopes.md\n *\/\nconst tokenRequest = {\n    scopes: [...apiConfig.scopes],\n};<\/pre>\n\n\n\n

    ASP.Net Web API sample<\/h3>\n\n\n\n

    This sample project is derived from this<\/a> ADFS Web API project. The Web API project was extended to support CORS request for the SPA client. Guidance for enable CORS is here<\/a>. The complete web API sample is here<\/a>. Find the following entries in the web.config file and replace it with your web API registration info. Use the web API’s Relying party Identifier for the “ida:Audience” value and fill in the FQDN name of your ADFS Server for the “ida:AdfsMetadataEndpoint” value.<\/p>\n\n\n\n

        <add key=\"ida:Audience\" value=\"https:\/\/localhost:44320\" \/>\n    <add key=\"ida:AdfsMetadataEndpoint\" value=\"https:\/\/[Enter your AD FS hostname]\/federationmetadata\/2007-06\/federationmetadata.xml\" \/><\/pre>\n\n\n\n

    The sample uses ActiveFederationServicesBearerAuthentication<\/a> middleware to integrate with ADFS Authentication.<\/p>\n\n\n\n

    using Microsoft.Owin.Security.ActiveDirectory;\nusing Owin;\nusing System.Configuration;\nusing System.IdentityModel.Tokens;\n\nnamespace TodoListService\n{\n    public partial class Startup\n    {\n        \/\/ For more information on configuring authentication, please visit http:\/\/go.microsoft.com\/fwlink\/?LinkId=301864\n        public void ConfigureAuth(IAppBuilder app)\n        {\n            app.UseActiveDirectoryFederationServicesBearerAuthentication(\n                new ActiveDirectoryFederationServicesBearerAuthenticationOptions\n                {\n                    MetadataEndpoint = ConfigurationManager.AppSettings[\"ida:AdfsMetadataEndpoint\"],\n                    TokenValidationParameters = new TokenValidationParameters()\n                    {\n                        SaveSigninToken = true,\n                        ValidAudience = ConfigurationManager.AppSettings[\"ida:Audience\"]\n                    }\n\n                });\n        }\n    }\n}<\/pre>\n\n\n\n

    I decorate the controller with the following attribute to enable CORS request for the controller’s methods:<\/p>\n\n\n\n

        [Authorize]\n    [EnableCors(origins: \"http:\/\/localhost:3000\", headers: \"*\", methods: \"*\")]\n    public class ValuesController : ApiController\n    {<\/pre>\n\n\n\n

    Running the sample projects<\/h3>\n\n\n\n
    1. Build and run the web API. It will open a browser and navigate to https:\/\/localhost:44321\/ <\/li>
    2. Run the SPA application: npm install<\/strong> followed by npm start<\/strong> to start the node server<\/li>
    3. Open a web browser and navigate to http:\/\/localhost:3000\/<\/li>
    4. Click ‘Sign-in’ button on top right to sign in with your account at the ADFS sign in page<\/li>
    5. If sign in is successful the page should display the signed-in name, id token, and access token (this is not the web API access token)<\/li>
    6. Click the ‘Call API’ button and it should display the Access Token for the web API and the response from the web API as followed:<\/li><\/ol>\n\n\n\n
      \"\"<\/figure>\n","protected":false},"excerpt":{"rendered":"

      This blog walks through how to set up MSAL.JS to authenticate directly to ADFS 2019 Server using Authorization Code Grant flow to get an Access Token and then call a Web API with that Access Token. We will go over the following steps to get this the samples working: App Registrations for both the Single Page Application (SPA) client app and the web API app Enable Cross-origin Request Sharing (CORS)…<\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3,4,179],"tags":[255,222,180],"class_list":["post-8564","post","type-post","status-publish","format-standard","hentry","category-authentication","category-authentication-flows","category-msal","tag-adfs","tag-auth-code-pkce","tag-msal-js"],"_links":{"self":[{"href":"https:\/\/blogs.aaddevsup.xyz\/wp-json\/wp\/v2\/posts\/8564"}],"collection":[{"href":"https:\/\/blogs.aaddevsup.xyz\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.aaddevsup.xyz\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.aaddevsup.xyz\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.aaddevsup.xyz\/wp-json\/wp\/v2\/comments?post=8564"}],"version-history":[{"count":26,"href":"https:\/\/blogs.aaddevsup.xyz\/wp-json\/wp\/v2\/posts\/8564\/revisions"}],"predecessor-version":[{"id":8603,"href":"https:\/\/blogs.aaddevsup.xyz\/wp-json\/wp\/v2\/posts\/8564\/revisions\/8603"}],"wp:attachment":[{"href":"https:\/\/blogs.aaddevsup.xyz\/wp-json\/wp\/v2\/media?parent=8564"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.aaddevsup.xyz\/wp-json\/wp\/v2\/categories?post=8564"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.aaddevsup.xyz\/wp-json\/wp\/v2\/tags?post=8564"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}