Goal: Sign in Azure AD user on frontend with Microsoft login dialog. Append token to backend request. Validate token on backend to ensure only authorized users can access the code. Tricky part: validate by hand because its not the only authentication in place.
I've managed to login and send the token but on validation I get errors like: IDX10511: Signature validation failed. Keys tried: ...
Here is what I have so far:
app.module.ts
@NgModule({
declarations: [
AppComponent,
RestrictedPageComponent
],
imports: [
HttpClientModule,
MsalModule.forRoot({
auth: {
clientId: '<CLIENT ID>',
}
}, {
consentScopes: [
'user.read',
'openid',
'profile',
],
protectedResourceMap: [
['https://localhost:44323/v1/login', ['user.read']], // frontend
['https://localhost:5001/api/Login', ['user.read']] // backend
]
}),
BrowserModule,
AppRoutingModule
],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: MsalInterceptor,
multi: true
},
],
bootstrap: [AppComponent]
})
export class AppModule { }
login.component.ts
login() {
const loginRequest = { scopes: ['https://graph.microsoft.com/User.ReadWrite'] };
this.authService.loginPopup(loginRequest);
}
And this seems to work just fine. I can login via Microsoft login and the MsalInterceptor adds the bearer token to the backend request header.
On the backend I now just want to verify that the token is valid and the user is authenticated corretly.
private JwtSecurityToken Validate(string token)
{
var stsDiscoveryEndpoint = "https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration";
// also tried "https://login.microsoftonline.com/<TENANT ID>/v2.0/.well-known/openid-configuration"
var openIdConnectConfigurationRetriever = new OpenIdConnectConfigurationRetriever();
var configManager = new ConfigurationManager<OpenIdConnectConfiguration>(stsDiscoveryEndpoint, openIdConnectConfigurationRetriever);
var config = configManager.GetConfigurationAsync().Result;
var validationParameters = new TokenValidationParameters
{
IssuerSigningKeys = config.SigningKeys,
// just for now
ValidateAudience = false,
ValidateIssuer = false,
ValidateLifetime = false
};
var tokenHandler = new JwtSecurityTokenHandler();
IdentityModelEventSource.ShowPII = true;
token = token.Replace("Bearer ", string.Empty); // weird - the token starts with "Bearer " and is not valid like this
var result = tokenHandler.ValidateToken(token, validationParameters, out var jwt);
return jwt as JwtSecurityToken;
}
In the call of tokenHandler.ValidateToken(...
I always get an error like IDX10511: Signature validation failed. Keys tried: ...
.
I'm not sure anymore if I understood and use the whole concept correctly.
The more I read about the usage of Azure Bearer token and validation the more it confuses me.
I can parse the token on http://jwt.io but the signature is always invalid.
Can the backend validate the token without passing any shared secret or client id? Is this the right approach to begin with?
edit: I'm not sure if I used the right endpoints to call on frontend and backend and which role the different endpoints play (e.g.: with tenant id or without). Would be great if someone could explain.
BR Matthias
stsDiscoveryEndpoint
tohttps://login.microsoftonline.com/<TENANT ID>/v2.0/.well-known/openid-configuration
– Matthias