I'm trying to create an Angular 10 front end that accesses a .NET Core 3.1 Web Api back end. Both of them secured under Azure AD using the MSAL Libraries. I created and SPA app usign Visual Studio 2019's SPA Angular Template for Web Apps. On the client app, I'm using msal-angular to log in and get an access token. I followed both the Quickstart, the Tutorial and finally I've tried withe the Single Page App Scenario (using the implicit flow). For the Web API, I followed what is explained in the Single Page App Scenario and also I've tried with the Protected web API Scenario and Web App that calls web APIs Scenario, but when I try to access any Web API endpoint that has an Authorize decorator, I get the following error: System.UnauthorizedAccessException: IDW10201: Neither scope or roles claim was found in the bearer token
.
Anyone else has successfully created something like what I'm trying to do (SPA template, Angular 10, .NET Core 3.1 web API)? What am I doing wrong or missing?
For the purposes of my question, my apps registration data are as follows:
Tenant:
Tenant Id: 'tttttttt-tttt-tttt-tttt-ttttttttttt'
Domain: 'notrealdomain.onmicrosoft.com'
Client App:
Client Id: 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'
API App:
Client Id: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
App Id: 'api://xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/access_as_user'
My token looks something like the following:
{
"aud": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
"iss": "https://login.microsoftonline.com/tttttttt-tttt-tttt-tttt-ttttttttttt/v2.0",
"iat": 1595531437,
"nbf": 1595531437,
"exp": 1595535337,
"aio": "ATQAy/8QAA01PbjYzolbeAAE6rlHrUQ5ndpD/CDAxneSI8BsXSdm3Sl7CBYWqoS+jyBUNtJ/Ovwe",
"groups": [
"gggggggg-gggg-gggg-gggg-gggggggggggg",
"ffffffff-ffff-ffff-ffff-ffffffffffff"
],
"name": "John Doe",
"nonce": "hhhhhhhh-hhhh-hhhh-hhhh-hhhhhhhhhhhh",
"oid": "iiiiiiii-iiii-iiii-iiii-iiiiiiiiiiii",
"preferred_username": "john@notrealdomain.onmicrosoft.com",
"sub": "hrhuh3UtYWRmuT-JnNWuFhFYvWjbJFmegz7k2ay0RbI",
"tid": "tttttttt-tttt-tttt-tttt-ttttttttttt",
"uti": "PAkaSoPlaWi_vBYklUKtAA",
"ver": "2.0"
}
app.module.ts
@NgModule({
declarations: [
... code ommited ...
],
imports: [
... code ommited ...
MsalModule.forRoot({
auth: {
clientId: 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
authority: 'https://login.microsoftonline.com/tttttttt-tttt-tttt-tttt-ttttttttttt/',
postLogoutRedirectUri: "https://localhost:44000/signout",
redirectUri: "https://localhost:44000/",
},
cache: {
cacheLocation: 'localStorage',
storeAuthStateInCookie: isIE, // Set to true for Internet Explorer 11
},
framework: {
unprotectedResources: ['https://localhost:44000/api/Unsecured'],
protectedResourceMap: new Map([
['https://localhost:44375', ['api://xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/access_as_user']],
['https://graph.microsoft.com/v1.0/me', ['user.read']],
['api://xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', ['access_as_user']],
])
},
}, {
popUp: false,
consentScopes: [
'user.read',
'openid',
'profile',
'api://xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/access_as_user',
],
extraQueryParameters: {}
}),
... code ommited ...
providers: [
... code ommited ...
{
provide: HTTP_INTERCEPTORS,
useClass: MsalInterceptor,
multi: true
},
I'm logging in using the following method in one of my components where this.msalService
is injected as private msalService: MsalService
:
this.msalService.loginRedirect({
scopes: [
'api://xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/access_as_user',
]
});
On my Web API, I have the following configuration on my appsettings.json file:
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "notrealdomain.onmicrosoft.com",
"TenantId": "tttttttt-tttt-tttt-tttt-ttttttttttt",
"ClientId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"Audience": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
},
... code ommited ...
}
And finally, my StartUp.cs looks like this:
public void ConfigureServices(IServiceCollection services)
{
// Autenticación
services.AddMicrosoftWebApiAuthentication(Configuration, "AzureAd");
... code ommited ...
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
... code ommited ...
app.UseRouting();
// Autorización
app.UseAuthentication();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}");
});
app.UseSpa(spa =>
... code ommited ...
}