Introduction
I recently had a specific need at work, to create role based Azure AD security in React. This seemed simple at first but then proved to be more complicated. My next project required me to do exactly the same thing, in Angular JS. The Angular one proved to be a lot simpler because we used .Net Core, and because of libraries that exist there. So I'm going to write articles that build up the solution, in Angular and then in React. Hopefully this saves you some time.
Background
A lot of businesses now use Azure AD, which makes it the perfect security solution, the accounts already exist, and roles (groups) can be assigned to users to manage who can do what in an application. For this first article, we're just going to create an Angular application and make the front end require a user be logged in to Azure AD. The article assumes you're writing the code as you go, but the finished product (with my Azure details removed) is the accompanying code file if you prefer. Of course, I deleted my node_modules to zip this up, so you'll need to restore them.
I prefer to use Webstorm for my Typescript dev, even though the code lives inside a csproj. You are, of course, welcome to use your tool of choice.
Configuring Azure AD
Under 'Azure Active Directory' in your Azure subscription is an option called 'App Subscriptions' and one called 'App Subscriptions (Preview)'. As the preview is the one that will exist long term, I am using that. Selecting to add a new app registration results in a screen like this:
The name here is simply the name you will see in the portal. The default option limits the Application to people in your Azure AD (which seems sensible). The redirect URL is the URL the app runs under, when you log in, you redirect to Azure and the application tells Azure where to redirect back to. You can have a collection of redirect URLs configured but if one is provided that's not in the list, it simply won't work. I'm using localhost:4200 because that's what Webstorm will run under. It's 3000 by default if you run it in Visual Studio. I typically add both later, so both will work,
Once your Application is created, you can view the details as follows:
The important details here are the client and tenant ids. Note these down in Notepad or similar, you'll need them later.
Start the Application
Now go to Visual Studio and create a new .Net Core application. When prompted, choose an Angular application. This will create a .Net Core project which contains an Angular application and knows to run it when it is started.
We need one more library to use Azure AD, it's called microsoft-adal-angular6. So, type this into your console:
npm install microsoft-adal-angular6
This will add the library to your package.json and install it.
Of course, we don't want to hard code config data. Your Angular package has a folder called 'environments'. Go there now and edit both files with the following variables:
tenant: <tenantid>,
clientId: <clientid>,
extraQueryParameter: 'nux=1',
endpoints: {
"http://localhost:4200/api": <clientId>
}
Now go to your app.module.ts file. First we need to import the files we're going to use:
import { MsAdalAngular6Module,AuthenticationGuard } from 'microsoft-adal-angular6';
import { environment } from '../environments/environment';
Now we can configure ADAL for Azure AD:
imports: [
MsAdalAngular6Module.forRoot({
tenant: environment.tenant,
clientId: environment.clientId,
redirectUri: window.location.origin,
endpoints: environment.endpoints,
navigateToLoginRequestUrl: false,
extraQueryParameter: environment.extraQueryParameter,
cacheLocation: 'localStorage'
}),
Note that redirectUri is dynamic and will always be the location the site is running. Note also that 'sessionStorage' is a viable 'cacheLocation', with the obvious results.
This is all you need to do for your application to redirect to Azure AD and require you to log into an account associated with your Azure (by default, this is your Azure login).
You may have noticed that we also imported the ApplicationGuard from the library. This is used to protect routes. If you create them inline or in another file, the syntax is the same:
RouterModule.forRoot([
{ path: '', component: HomeComponent, pathMatch: 'full' },
{ path: 'counter', component: CounterComponent },
{ path: 'fetch-data', component: FetchDataComponent, canActivate: [AuthenticationGuard] },
]),
In this case, the 'fetch-data' route now requires the user to be logged in.
Accessing your token
Naturally, when we get to securing our APIs, we will need to get access to the token that was passed back from Azure AD. We will do this at the top level in our app.component.ts file.
First, we need to import the libraries we use:
import { MsAdalAngular6Service } from 'microsoft-adal-angular6';
Now we can inject this into a constructor and process it there. This code won't be called until the user is logged in.
constructor(private adalSvc: MsAdalAngular6Service) {
console.log(this.adalSvc.userInfo);
this.adalSvc.acquireToken('https://graph.microsoft.com').subscribe((token: string) => {
console.log(token);
});
}
Here we log the user info, which is an object containing a username and a profile. Accessing the username property to show the user is the most logical thing to do with this object. family_name and given_name are also properties of the profile object.
The next thing we do is call a method to acquire a token, which then calls a method that takes the token. We're just logging it to the console, but this is where you'd pass the valid token into a service that then uses it to set a header to use protected API calls.
Points of Interest
At this point, our application is not really secure. We have an integration to Azure AD, but until the APIs that return our sensitive data are protected, all we really have is window dressing. For all that, the ADAL libraries certainly make it trivial to create this initial integration between Angular and Azure AD.
History
1.0 - Initial code