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: 'mon',
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;
}
}
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: 'mon',
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;
}
}
Share
Improve this question
edited Nov 11, 2017 at 5:19
Rishabh
asked Nov 11, 2017 at 4:58
RishabhRishabh
90011 silver badges31 bronze badges
5
- you should post your entire authentication code... – Shawn Tabrizi Commented Nov 11, 2017 at 5:03
-
For authentication I am just creating an
AdalConfig
object with all the required info such astenant
,clientId
,redirectUri
etc, and then initializing a newAuthenticationContext
using theAdalConfig
, and then using the initialized context's methods. I have posted the method call. Please let me know what else is required. – Rishabh Commented Nov 11, 2017 at 5:08 - Where are you specifying the resource you want to call? You need to post your code or no one is going to be able to help you. – Shawn Tabrizi Commented Nov 11, 2017 at 5:09
-
Posted the
config.service.ts
andadal.service.ts
code, that's where I am specifying all the required info by AAD. Hope this will help :) – Rishabh Commented Nov 11, 2017 at 5:21 - 2 I think Shawn is on the right track :) I had a similar problem with ADAL.JS when I somehow specified the resource wrong so it got a token for itself (id token). – juunas Commented Nov 11, 2017 at 15:09
2 Answers
Reset to default 4Actually, 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 mon 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.
I've faced an issue like yours when I was trying to send the token to a .Net Core API endpoint. It worked for me when I sent the token from the adal.access.token.key node, on sessionStorage.
Using adal.access.token.key or adal.idtoken token values (they are the same) didn't work for me.
Valid token on adal.access.token.key node.