Skip to main content

Enabling the OAuth2 authorization code flow (PKCE) for single-page (SPA) apps in Azure Active Directory

·928 words·5 mins

Background #

Recent enhancements to browser security, such as Apple Safari’s Intelligent Tracking Protection have meant that third-party cookies are being blocked on requests that cross domains. This can be a real pain if you are developing a single-page application (SPA) and need to sign your users into Azure Active Directory. This will only get worse in the future as Chromium (the platform behind Google Chrome and Microsoft Edge) has announced that they will also stop supporting third-party cookies at some point.

If you have implemented authentication using Azure Active Directory for a SPA app in the past you’ll probably have used the Implicit grant flow but you’ll now need to switch to using the Authorization code flow instead. This configuration was previously only accessible by editing the app manifest but is now available a first-class experience in the Azure Portal .

Creating a new SPA App Registration #

You create a new App registration in Azure Active Directory by selecting App Registrations:

App Registrations
Figure: Showing the location of App Registrations in an Azure Active Directory blade in the Azure Portal.

Click on New registration:

New App Registration
Figure: Showing the New App Registration screen with the Single-page application (SPA) option available.

You need to give the App a name such as My Awesome App, select the account types allowed to access the application (e.g. if you just want any AAD account to be able to access your app, select the middle “multi-tenant” option), then under Redirect URI select Single-page application (SPA) and enter your login URL. The URL is going to differ depending on which library or module and configuration you have used to build your SPA. In my case it’s http://localhost:3000/auth

After pressing the Register button you’ll be taken to the Overview page where you can retrieve your Client ID. You’ll need that Client ID in order to configure your SPA.

App Registration (Overview)
Figure: Showing the App Registration (Overview) so the client ID can be retrieved

If you need to add other Redirect URIs (for example for your production app) to the configuration, you can click on Authentication and add them here under Single-page application:

New App Registration
Figure: Showing the App Registration to add further Redirect URIs to the configuration

JavaScript and Microsoft Authentication Library (MSAL) #

From the client side, the older Microsoft Authentication Library for JavaScript (MSAL.js) v1 JavaScript library will not work with the Authorization Code flow. You need to use the preview MSAL.js 2.0 library instead.

A complete set of sample JavaScript applications using the MSAL.js v2 library is available here: https://github.com/Azure-Samples/ms-identity-javascript-v2

Nuxt.js Sample application #

I’m also seeing PKCE and Authorization Code flow support being added to various OAuth2 auth modules out there for popular SPA frameworks. One of these frameworks I’ve been playing with recently is Nuxt.js , a great framework based on Vue.js . Nuxt has a concept of middleware that intercepts every page call and I’ve been using a preview of the next version (5.0.0) of nuxt-auth-module to get a basic auth flow working.

The full working example can be cloned from: https://github.com/stuartpreston/nuxt-auth-azuread-example

You’ll need to do (at least) the following steps to get Nuxt.js auth module working with Azure AD:

  • Add the module to your project:
npm install @nuxtjs/auth-next @nuxtjs/axios
  • Add the module configuration to your nuxt.config.js:
modules: [
  '@nuxtjs/axios',
  '@nuxtjs/auth-next'
],
router: {
  middleware: ['auth']
},
  • Create an empty store/index.js file to initialize the Vue store.

  • Add the Authorization Code (PKCE) configuration to the nuxt.config.js. You will need to substitute the clientId with your own Client ID from your AAD tenant:

  auth: {
    redirect: {
      login: '/',
      callback: '/auth'
    },
    strategies: {
      aad: {
        scheme: 'oauth2',
        endpoints: {
          authorization: 'https://login.microsoftonline.com/organizations/oauth2/v2.0/authorize',
          token: 'https://login.microsoftonline.com/organizations/oauth2/v2.0/token',
          userInfo: '',
          logout: '/'
        },
        token: {
          property: 'access_token',
          type: 'Bearer',
          maxAge: 1800
        },
        refreshToken: {
          property: 'refresh_token',
          maxAge: 60 * 60 * 24 * 30
        },
        responseType: 'code',
        grantType: 'authorization_code',
        accessType: 'offline',
        // ******** change this for your Application (Client) ID ********
        clientId: '37014aa9-a961-47ce-bb9e-868cba98a0b2',
        codeChallengeMethod: 'S256',
        scope: ['openid', 'profile'],
        autoLogout: true
      }
    }
  }

Note that we are only requesting the openid and profile scopes. This gives us enough access to authenticate and receive profile information only. If you need access to Microsoft Graph or another API, this will require additional configuration here.

In our case we’re only looking to work with all Azure AD tenants (authentication occurs against the organizations endpoint). If you just want to sign users into your tenant, or use a Microsoft Account then other endpoint options are available .

The nuxt-auth-module provides a global $auth object so once the above steps are complete you should be able to use $auth.loginWith('aad') in order to trigger the auth flow from within your SPA, and $auth.logout('aad') to logout and redirect to the specified page. I wired up my Navbar with the following:

<a v-if="!this.$auth.loggedIn" @click="$auth.loginWith('aad')">Sign in with Microsoft</a>
<a v-else="" @click="$auth.logout('aad')">Sign out</a>

A full working example can be found on my GitHub page: https://github.com/stuartpreston/nuxt-auth-azuread-example

Figure: The “logged out” page from the Nuxt.js AAD sample app

The first time you sign in, you will be requested to accept the permissions being requested:

Figure: Permissions requested page on first time sign-in

When you sign in to the sample app, you will be shown some basic profile information available from the JWT token:

Figure: Logged In page demonstrating how to access profile information and decoded bearer token information

Hopefully this information helps someone starting down the same path with Nuxt.js in order to support Azure Active Directory authentication for their SPA.

Further reading, tutorials and sample apps #