manishrasrani / ms-adal-angular6

This is a wrapper library for Angular 6+ (Angular 6.X.X and Angular 7.X.X) modules over Microsoft ADAL (Azure Active Directory Authentication Library)
https://www.npmjs.com/package/microsoft-adal-angular6
MIT License
34 stars 13 forks source link

Surprisingly I'm getting same code for access_token and id_token. #13

Open srinuhamps opened 5 years ago

srinuhamps commented 5 years ago

I have angular app version 6 and I'm trying to integrate Azure AD authentication and the micro services are in AWS.

Surprisingly I'm getting same code for access_token and id_token. are they supposed to be different? my architect thinks so and asked me to tweak library to send responseType as 'id_token+token'.

What am I doing wrong and is there any way I can get access_token for sending as headers for api calls? I have also attached the screenshot of the console errors of api c microsoftadal-api fails alls.

Below is my piece of code where I was trying to read access token for authenticating api calls.

export class AppComponent { loading: boolean; constructor(private adalSvc: MsAdalAngular6Service, private router: Router, private http: HttpClient) { this.adalSvc.acquireToken('https://api.test.test.com/Dev') .subscribe((resToken: string) => { console.log(this.adalSvc.userInfo); console.log('get resToken -->', resToken); console.log('get oid -->', this.adalSvc.userInfo.profile.oid); console.log('get accessToken -->', this.adalSvc.accessToken); localStorage.setItem('accessToken', this.adalSvc.accessToken); console.log('get token -->', this.adalSvc .getToken('https://api.test.test.com/test?userId=111111')); this.configureRoutes(); this.loading = true; this.http.get('https://api.test.test.com/test?userId=11111', { headers: { 'Authorization': 'Bearer ' + this.adalSvc.accessToken, 'userid': this.adalSvc.userInfo.profile.oid, 'username': 'username', 'userrole': 'somerole' } }).subscribe(console.log); this.postCall(); }, error => { console.log(error); }); } postCall() { const data = { 'dealerId': '111111' }; const headers = new Headers(); headers.append('Authorization', 'Bearer ' + this.adalSvc.accessToken); headers.append('userid', this.adalSvc.userInfo.profile.oid); headers.append('username', 'username'); headers.append('userrole', 'somerole'); return this.http.post( 'https://api.test.test.com/test', data, { headers: { 'Authorization': 'Bearer ' + this.adalSvc.accessToken, 'userid': this.adalSvc.userInfo.profile.oid, 'username': 'username', 'userrole': 'somerole' } }).subscribe((response: Response) => { console.log(response.json()); }); } configureRoutes() { this.router.navigate(['/dealer/home']); } }

aharris commented 5 years ago

I am having the same issue.

    this.adalSvc.acquireToken('https://graph.microsoft.com').subscribe((token: string) => {
      console.log('token:', token);
    });

    console.log(this.adalSvc.accessToken);

I would expect the first one to log an id token and the second to log an access token but they are identical.

dannycornelisseMT commented 5 years ago

@aharris I have the same problem, do you figure it's maybe a configuration issue?

aharris commented 5 years ago

@dannycornelisseMT I did not get it to work with this library. I ended up getting the access token directly in API on the server. This seemed more secure anyways as it seems (in my set up at least) since I need to send a client secret. I did not want this exposed to the front end.

So I use adal to get an id token that I use to authenticate with my API and then my API calls https://login.microsoftonline.com to get an access token.

The access token expires every hour so i need to request a new one every hour.

Here is the service I wrote to get the token. (I am using NestJS):

import { Injectable, HttpService } from '@nestjs/common';
import { BehaviorSubject } from 'rxjs';

@Injectable()
export class TokenService {
  public accessToken$: BehaviorSubject<string>;

  constructor(private http: HttpService) {
    this.accessToken$ = new BehaviorSubject('');

    this.getToken();

    setInterval(() => {
      this.getToken();
    }, 1000 * 59 * 60);
  }

  private getToken() {
    // Setting environemnt variables
    const clientId = process.env.APPSETTING_CLIENT_ID;
    const clientSecret = process.env.APPSETTING_CLIENT_SECRET;
    const grantType = 'client_credentials';
    const scope = 'https%3A%2F%2Fgraph.microsoft.com%2F.default';
    const tenant = process.env.APPSETTING_TENANT;

    return this.http.post(
      `https://login.microsoftonline.com/${tenant}/oauth2/v2.0/token`,
      `grant_type=${grantType}&client_id=${clientId}&scope=${scope}&client_secret=${clientSecret}&tenant=${tenant}`,
      {
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
          'cache-control': 'no-cache'
      }
    }).subscribe(async (result) => {
      this.accessToken$.next(result.data.access_token);
    }, (err) => {
      console.log(err);
    });
  }
}
manishrasrani commented 5 years ago

Could you please check in your localStorage / sessionStorage if both the id token and access token(for each resource) are stored there and let me know?

anudr01d commented 5 years ago

@manishrasrani They are both the same.

Screen Shot 2019-04-09 at 6 50 59 PM
jemeshjoseph commented 5 years ago

You can refer a similar issue here. I have tried to explain the case in this issue #19 Please refer the link for detailed information on how to get id_token, authorization code and access_token from authentication APIs. https://docs.microsoft.com/en-us/azure/active-directory/develop/v1-protocols-openid-connect-code#get-access-tokens

anudr01d commented 5 years ago

The following solution worked for me.

Just add https://graph.microsoft.com within the endpoints as follows and then call acquireToken with the same url. You can then test out the new access token with the graph explorer - Graph Explorer

MsAdalAngular6Module.forRoot({
      tenant: '', 
      clientId: '',  
      redirectUri: window.location.origin,
      endpoints: {
        "https://graph.microsoft.com": "https://graph.microsoft.com"
      },
      navigateToLoginRequestUrl: false,
      cacheLocation: 'localStorage',
    })
this.adalSvc.acquireToken('https://graph.microsoft.com').subscribe((token: string) => {
// new token
});
chrislangston commented 5 years ago

@anudr01d How does your suggestion of adding "https://graph.microsoft.com" help?

We are receiving this same issue as the point of this issue. It doesn't matter what value I pass to "aquireToken()" the call always returns me the already acquired Bearer Token from my initial login request.

this.adalSvc.acquireToken('https://bogus-url-that-doesnot-exist.com').subscribe((token: string) => { //token received is the same token I already had from login to my SPA Azure App Registration });

@manishrasrani Do you know what I'm doing wrong? Essentially we have a front-end Angular SPA app that has an App Registration.

We have a .net CORE Web API that the front-end calls to perform CRUD operations.

I need to get the correct Bearer Token in order to make Authorize calls to the WebAPI.

In our package.json file were are have:

"microsoft-adal-angular6": "^1.3.0",

The node_modules microsoft-adal-angular6 package.json has the following entries:

"dependencies": { "@types/adal": "^1.0.29", "adal-angular": "^1.0.15", "tslib": "^1.9.0" },

chrislangston commented 5 years ago

I found how to resolve this issue.

When I configure my endpoints, I do the following:

adalConfig.endpoints = { "http://localhost:64553": "${WEB-API-AZURE-AD-CLIENTID}" }

Then in my interceptor code,

` return this.adal.acquireToken(req.url).pipe( mergeMap((token: string) => { const authorizedRequest = req.clone({ headers: req.headers.set("Authorization", "Bearer ${token}"), }); return next.handle(authorizedRequest); }));

`

If you trace through teh code for "acquireToken", you will see that if it doesn't find a match for the "req.url", it defaults back to the adalConfig.clientId (which in my case is the ClientId to my front-end SPA and not the ClientId for my Azure AD WebAPI

ralphwillgoss commented 4 years ago

@chrislangston yes, this solution works for me. I traced the code too, to understand what is happening.

I think part of the problem comes from the first search result for using this library and an interceptor.

The result which is the Microsoft Premier Developer article, suggests getting the resource using GetResourceForEndpoint and passing this resource to the acquireToken method this.adal.acquireToken(resource).

This won't work, you will get back the resource guid of the endpoint you are trying to access which is not what you want to pass to acquireToken.

The call to acquireToken, will call GetResourceForEndpoint on your behalf and then pass the resource id of the endpoint you are trying to access, to the adal.AuthorisationContext.acquireToken(guid).

I've notified the author of the MS blog, to see if we are missing something.