I am authenticating my Single Page App (Angular4) with Azure AD, and using Adal.js for the same. On the login page, I click a button that redirects to Microsoft AAD and upon successful login it redirects back to application home page, and receives id_token
and user info from JWT.
I need the access_token
for back-end API access, which I am trying to acquire through the the ADAL AuthenticationContext
's getCachedToken()
method, and sending the clientId as parameter:
this.context.getCachedToken(this.configService.AdalConfig.clientId)
But this method returns the same token which is stored in session storage as id_token (adal.idtoken)
. It basically creates a new item in session storage by with a concatenated key, which has same value as id_token
adal.access_token.key + clientId = id_token
ex: adal.access_token.key239f6fc7-64d2-3t04-8gfd-501efc25adkd = <id-token-value>
.
I also tried to fetch access_token
with AuthenticationContext.acquireToken()
method, but it too gave the id_token
back.
Where am I going wrong?
EDIT: posting the code.
I am calling the function login()
, and after successful login, trying to get the access token in home page via get accessToken()
property accessor in adal.config.ts
.
config.service.ts
import { Injectable } from '@angular/core';
@Injectable()
export class ConfigService {
constructor() {}
public get AdalConfig(): any {
return {
tenant: 'common',
clientId: <application-id>,
redirectUri: window.location.origin + '/',
postLogoutRedirectUri: window.location.origin + '/'
};
}
}
adal.service.ts
import { ConfigService } from './config.service';
import { Injectable } from '@angular/core';
import { adal } from 'adal-angular';
let createAuthContextFn: adal.AuthenticationContextStatic = AuthenticationContext;
@Injectable()
export class AdalService {
private context: adal.AuthenticationContext;
constructor(private configService: ConfigService) {
this.context = new createAuthContextFn(configService.AdalConfig);
}
login() {
this.context.login();
}
logout() {
this.context.logOut();
}
handleCallback() {
this.context.handleWindowCallback();
}
public get userInfo() {
return this.context.getCachedUser();
}
public get accessToken() {
return this.context.getCachedToken(this.configService.AdalConfig.clientId);
// return this.context.acquireToken(this.configService.AdalConfig.clientId, function(message, token, response) {
// console.log(message, token, response);
// });
}
public get isAuthenticated() {
return this.userInfo && this.accessToken;
}
}
Actually, after a bit of reading, turned out that connecting SPA's to Azure AD requires OAuth 2.0 Implicit Grant flow. The Microsoft documentation says:
In this scenario, when the user signs in, the JavaScript front end uses Active Directory Authentication Library for JavaScript (ADAL.JS) and the implicit authorization grant to obtain an ID token (id_token) from Azure AD. The token is cached and the client attaches it to the request as the bearer token when making calls to its Web API back end, which is secured using the OWIN middleware.
So, it's the id_token
itself that I need to send to the back-end APIs, which in turn can be validated and used. More info about validation is given here:
Just receiving an id_token is not sufficient to authenticate the user; you must validate the id_token's signature and verify the claims in the token per your app's requirements. The v2.0 endpoint uses JSON Web Tokens (JWTs) and public key cryptography to sign tokens and verify that they are valid.
You can choose to validate the id_token in client code, but a common practice is to send the id_token to a backend server and perform the validation there. Once you've validated the signature of the id_token, there are a few claims you will be required to verify.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With