Aurelia and Azure AD B2C Authentication

Using hello.js with Azure Active Directory B2C Tenant to authenticate Api calls within Aurelia application

Identity as a service allows web applications to use fully featured, well maintained and secure service to handle user authentication. With Azure AD B2C, customer-facing applications can improve user experience by providing single sign-on (SSO) with social media platforms like Facebook, Google and Twitter, as well as email / username based sign-up.

In this article, I will go through setting up the AD tenant in Azure and using hello.js within Aurelia application to sign in users. Microsoft offers a comprehensive documentation for Azure AD B2C, but there is quite a lot to go through, and I found the guides and samples missing some key details that took way too long for me to find out by trial-and-error. This article aims to provide an easy start for setting up the authorization provider (Azure AD B2C Tenant) and the client application (Aurelia SPA).

The source code for the application created in this article is open-source (MIT) and available in GitHub at https://github.com/vuorinem/aurelia-azureadb2c.

Setting up Azure AD B2C Tenant

Creating directory

If you don’t have an existing AD B2C directory to use, you can get started by creating a new resource in Azure portal and searching for “b2c”. The directory will have a unique url such as myadb2ctenant.onmicrosoft.com.

Creating new Azure AD B2C Tenant in Azure portal

When you are logged in in Azure with an account that has access to the directory, it will show up in the user menu on the right hand side of the portal.

Directories in Azure portal user menu

Azure AD B2C Settings

The page for configuring the AD B2C resource is different from the AD B2C Settings page (below). To access the settings page, you might need to switch the directory from the user menu.

Azure AD B2C Settings page in Azure portal

In the settings page, you can select the identity providers that can be used to log in to your application. Adding a provider in Azure is simple, but setting up the application on the provider side (such as Facebook for developers or Google developer console) usually requires few extra steps. Luckily Azure documentations has step-by-step instructions how to set up the providers, currently for Facebook, Google+, Microsoft Account, Amazon, and LinkedIn.

User attributes

The user attributes page (or “blade” as they are called in Azure documentation) shows all the attributes that can be collected from users on sign-up or sign-in. You can also add custom attributes if you need to collect data that is not available as a built-in attribute. Available attributes can be restricted by application and policy.

List of User attributes in AD B2C Tenant settings

Registering application

To use Azure AD as the identity provider for your application, the application needs to be registered in the portal. This will create an unique application ID that is needed when requesting user to sign in.

For web applications, a reply URL is required so that the user can be securely redirected to the application after the sign-in. I will set up the sample application to run locally, so the return URL will be on localhost, on port 9000. The application will need to be built to handle the sign-in response in https://localhost:9000/login-redirect.

Registering AD B2C application in Azure portal

For more details, see the Azure documentation page Register your application.

Scopes

For the authentication to work properly, you will need to define at least one scope for the application in Published scopes blade in the application configuration.

Scope configuration for application

You can select the name and value of the scope however you like. Note that when using the scope, it needs to be prefixed with the App ID URI in application properties. The final scope value will be something like:

https://my-ad-tenant-name.onmicrosoft.com/my-app-name/scope-value

If the scope defined in the login request is anything else, the login will fail.

When you have added the scopes, the application needs to be allowed access to those scopes. This is done from the API access blade, just above the Published scopes. Just add a new access specification for your application and select the scopes from the list.

Adding API access to selected scopes for the application

Policies

Policies define different authentication scenarios that are supported by the AD tenant, such as creating a new account, signing in with an existing account, or editing profile details. These are described in the Built-in policies documentation.

A sign-up or sign-in policy can be used as a simple solution for both sign-up and sign-in purposes. The policy itself is easy to set up by selecting the identity providers that can be used, attributes that are required from the user (in case of a new user sign-up), and the claims that are available in the token to be read by the application.

Note that when referring to the policy with its full name, it should be prefixed by B2C_1_, so for example the full name of the policy below will be B2C_1_signupsignin.

Setting up a new sign-up or sign-in policy in Azure portal

The Page UI customization section can be used to change the sign-up/sign-in page layout and how the user attribute form fields are displayed. These are worth going through especially if you use custom sign-up attributes.

Aurelia application and hello.js

The client application is responsible for requesting the user to sign in and adding the access token to all the authenticated API requests. In our case, this will be a JavaScript application built on Aurelia. As a starting point, I will create a new application using Aurelia CLI.

Installing hello.js package

Hello.js is a JavaScript OAuth client library that works with any standard authentication provider. It takes care of redirecting the browser (or opening a pop-up window) to prompt the user to log in, and stores the access token when the user is redirected to the application.

Microsoft also has it’s own library, MSAL (Microsoft Authentication Library), but MSAL port to JavaScript is still in preview (although “suitable for use in a production environment” as mentioned on the repository readme), and importing it as a module doesn’t quite work as expected. I also had some trouble trying to keep the user logged in when refreshing the page, so I ended up choosing hello.js which seemed to be much easier to get working.

Microsoft also provides a sample application that demonstrates how to use hello.js for Azure AD B2C authentication. The application is a good starting point, but it doesn’t show all the necessary set up.

Npm can be used to install hello.js and it’s type definitions:

npm i hellojs
npm i @types/hellojs

Unfortunetely the type definitions are currently for an older version, and for example the sample application from Microsoft is not compatible with the older typings. This means that the code from the sample app will not transpile when using TypeScript. I have created a pull request in DefinitelyTyped repository to update hello.js typings. It will probably be a while until/if the pull request will be merged in, so meanwhile you can either use the old definitions, or get the updated hello.js definition from my sample application.

Azure AD B2C configuration

First step in using hello.js is to configure your AD tenant to be used as an authentication provider. In hello.js modules documentation, there is a list of currently supported provider modules and instructions for writing your own. To set up Azure AD B2C you can call the init()-method with following parameters:

hello.init({
azureAD: {
oauth: {
version: 2,
auth: AD_URL + '/authorize',
grant: AD_URL + '/token',
},
scope_delim: ' ',
}
});

The property key azureAD is just an arbitrary name for the hello.js module. Subsequent calls to the AD provider should use that name.

AD_URL is the base URL of the two OAuth2 endpoints. The URL is in the following format:

https://login.microsoftonline.com/te/[AD]/[POLICY]/oauth2/v2.0

where AD is the full name of the tenant (e.g. my-ad-tenant-name.onmicrosoft.com) and policy is the full name of the policy (e.g. B2C_1_signupsignin). You can check the URL’s from the OpenID “well-known configuration” page for your policy . The configuration is a .json formatted file, with properties authorization_endpoint and token_endpoint, that can be used in auth and grant configuration respectively. (See for example Akana OpenID documentation)

A link to the well-known configuration page is shown on the top of the policy details page in Azure. At the bottom of the page there is also a link and a button to open the login-page for the currently selected application and scopes.

Policy details in Azure portal

Note that the selected token issuer in Token compatibility settings (see below) changes the link. When the issuer is set to the one starting https://login.microsoftonline.com/tfp…, the configuration will show OAuth url’s with /te and the policy name in the path. For the issuer without /tfp, the policy name will be added as a query string. Either URL’s should work fine, but I’m using the ones with /te in the sample application.

Policy token configuration in Azure portal

Once the Azure AD provider has been set up, we need to set the application ID that our application uses. This a simple call to init() with an object that has providers as keys and application ID’s as values:

hello.init({
azureAD: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx',
});

Sign-in

Finally, it’s time to add the code to actually sign in the user. Or to be exact, open a sign-in page and handle the response. With hello.js, most of this happens automatically in the background as long as the hello.js script is being loaded when loading the page.

Calling login() with the following parameters will redirect user to the AD login page, and redirect back to the application once done. If the user has already signed in, the redirect will happen immediately without user interaction. The display parameter with the value ‘page’ tells hello.js to use browser redirect instead of a pop-up window, to avoid problems if the user has blocked pop-ups.

hello.login('azureAD', {
redirect_uri: 'https://localhost:9000',
scope: 'openid https://my-ad-tenant-name.onmicrosoft.com/my-app-name/scope-value',
response_type: 'token',
display: 'page',
});

Default login parameters can also be set in a the hello.init() call when setting application ID.

Sign-out

When using single sign-on, there are different types of sign-out functionality. To end user session — instead of just removing authentication details from the client — we need to tell hello.js to call the end session endpoint. The URL for that is in the OpenID well-known configuration page with the key end_session_endpoint, but in AD B2C it is just the same as auth and grant URL’s except with /logout at the end.

Unfortunately this is not quite enough, as you can see if you try to set this as the logout-option in the first hello.init() call. The first problem, and the easier one to fix, is that the logout endpoint also requires a post_logout_redirect_uri parameter in the logout request. The parameter can be simply added as a query string to the logout URL.

The more tricky issue is that hello.js tries to use iframe to make the request to the logout endpoint, and Azure AD B2C does not allow this in any of the OAuth endpoints. The solution is to make the call ourselves, by setting the logout-configuration to be a function. The function gets called whenever hello.logout() for that provider is called with the force-option. It is not really a well documented feature, the best documentation is in the built-in Facebook module in hello.js repository, but it get’s the job done. Another option would be just to forget hello.js on log-out and just redirect to the URL, and use hello.util.store to clear authentication data from the client.

You can check the sample application to see the code for implementing sign-out.

Aureliaize!

There’s nothing fancy in the client-side code pasted here so far, and most of it is pretty close to the Microsoft’s sample application. The real fun starts when we start to integrate it with an Aurelia application.

As with most of the non-UI code, I decided to put the authentication code with all the hello.js references into a service class. That simply means that the class has Service at the end of its name, and it doesn’t have a template or implement any interfaces. The class is only used through dependency injection, which (by default) creates a singleton instance of the class.

The AuthService class handles all the calls to hello.js and initializing the provider with Azure AD configuration. Constructor can handle all the initialization because it is all handled synchronously. (If something asynchronous needs to be called before initializing hello.js, all that would need to be handled in some other way as constructors cannot be asynchronous.) Configuration for the specific AD is held in a the auth-config.ts file.

All the options that can be set beforehand have been set in the constructor, so the actual calls to login() and logout() are simple. We’ll only need to make sure to update authentication status whenever it might change. This might happen when the page is loaded (in case of a sign-in or sign-out response), so the first check should be in the constructor. Also after login and logout, the status should be updated. Hello.js has also some events that could be used to track changes in authentication status, by attaching event handlers with hello.on().

AuthService can be used simply by injecting it into any class. In the sample application, the main functionality is in app.ts and the UI in app.html. Log-in and log-out buttons call the respective AuthService methods, and their visibility is dictated by the authentication status.

Make authenticated API call

The final step is to make use of all the hard work we have done. From all the set up and code above, the most important artefact we get is the authentication token. Using the token we can call the API that requires authentication, by adding the token in the Authorization-header in the request.

With Aurelia, the simplest way to add a request header is to use an interceptor. Interceptors can be used to modify HTTP requests and responses. The implementation for authorization-header interceptor simply adds the header if there is a token available. When making the API call, the HTTP client is configured to use interceptor.

That’s it! The next stage would be to implement the API that receives the token and reads the user claims from it, but that will be a topic of another article.

-end-

Thank you for reading! I hope the article was useful, saved you some time or gave an inspiration to try something out. Any feedback is welcome, so feel free to comment or send a message!