2
votes

I built an Angular application following this example: https://github.com/microsoftgraph/msgraph-training-angularspa

I'm able to login and even authenticate to MS Graph from the Angular app.

I'm trying to pass the token to an API service that I have created as well. However I keep getting the below error:

WWW-Authenticate: Bearer error="invalid_token", error_description="The signature is invalid"

I've tried everything possible so far was no luck. I continue to get this error. I've tried the AzureADBearer library:

services.AddAuthentication(AzureADDefaults.BearerAuthenticationScheme)
    .AddAzureADBearer(options => Configuration.Bind("AzureAd", options));

services.Configure<JwtBearerOptions>(AzureADDefaults.JwtBearerAuthenticationScheme, options => 
{
    options.Authority += "/v2.0";
    options.TokenValidationParameters.ValidAudiences = new string[]
    {
        options.Audience, $"api://{options.Audience}"
    };

    options.TokenValidationParameters.ValidateIssuer = false;
    options.TokenValidationParameters.IssuerValidator = AadIssuerValidator.GetIssuerValidator(options.Authority).Validate;
});

I've also tried the Microsoft.Identity.Web library but I'm getting the same error:

services.AddProtectedWebApi(Configuration);

I've been searching for few days now, I've found others with the same problem but so far no clear solution. Any help would be appreciated.

EDIT

I'm trying to build an application for my organization that uses our AzureAD for authentication. The application has Angular frontend with aspnetcore webapi as backend. I'm not too particular on how to get this achieved. Just looking for away to get it done.

1
How does the token you are sending look like? It is possible your API in AAD is configured to get v1 tokens. In that case the signing keys might be different. You can tell if it is a v1 token by looking at the issuer claim (iss); v1 tokens have https://sts.windows.net/guid. You can inspect the token at e.g. jwt.ms.juunas
It's a v1 token. Although my endpoint is pointing to v2 and app manifest is set to return v2 tokens, the token that I'm receiving is v1.spider913
Okay, that's odd 🤔 How are you acquiring the token? What are you using as the scope?juunas
Okay, the audience in the token your API is receiving should match the API client id or app id URI. Otherwise you may be sending a MS Graph API token to your API, which is not correct.juunas
@juunas thank you your respond on another post has also helped me find the answerspider913

1 Answers

1
votes

So after some assistance from Junnas and NanYu and few old posts, I figured out the issue. In my previous setup I had the scopes for my Api and MS Graph together, but the problem is that the token returned for each is different. I needed to acquire different tokens when reaching the different Api (mine vs Graph). After splitting the scopes and acquiring the token independently, I was able to authenticate with both. Also the MsalInterceptor work very well if setup correctly and saves me from writing separate calls to acquire the tokens. Here's my code:

oauth.ts

export const OAuthSettings = {
    appId: '{client Id}',
    authority: 'https://login.microsoftonline.com/{tenant Id}',
    apiScopes: [
        'api://{api id}/access_as_user'
    ],
    graphScopes: [
        'user.read'
    ]
}

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { MsalModule, MsalInterceptor } from '@azure/msal-angular';
import { LogLevel } from 'msal';

import { AppComponent } from './app.component';
import { OAuthSettings } from '../oauth';

// this is only for logging and tracing
export function msalLogCallBack(level: LogLevel, message: string, containsPii: boolean) {
  console.log('[MSAL]:' + message);
}

@NgModule({
  declarations: [
    AppComponent,
  ],
  imports: [
    BrowserModule,
    HttpClientModule,
    MsalModule.forRoot({
      clientID: OAuthSettings.appId,
      authority: OAuthSettings.authority,
      unprotectedResources: ['{angular app uri}'],
      protectedResourceMap: [
        ['{api endpoint}', OAuthSettings.apiScopes],
        ['https://graph.microsoft.com/v1.0/me', OAuthSettings.graphScopes]
      ],
      level: LogLevel.Verbose,
      logger: msalLogCallBack
    })
  ],
  providers: [ {
    provide: HTTP_INTERCEPTORS,
    useClass: MsalInterceptor,
    multi: true
}],
  bootstrap: [AppComponent]
})
export class AppModule { }

From this point any calls made to the Api will be intercepted and the correct token will be attached in the header of the call by the MsalInterceptor.