2

I have 2 web applications.

  • Site A is both front end (Angular) and a web API written in .NET core.
  • Site B is a web API written in .NET core.

The web APIs in both sites are the same. The authentication is the same.


Test 1: When I ask Site A to use its own API to get the data (with Site A's authentication turned on) it works great.

Test 2: When I ask Site A to use Site B to get the data (with Site B's authentication turned OFF) it works great.

Test 3: When I ask Site A to use Site B to get the data (with Site B's authentication turned ON) it fails with unauthorised error 401.

Here is the code I am using to authenticate...

services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(o =>
{
    o.MetadataAddress = String.Format("https://login.microsoftonline.com/{0}/v2.0/.well-known/openid-configuration", Configuration["AzureAd:TenantId"]);
    o.Audience = Configuration["AzureAd:ClientId"];
});

So...

I know the tokens are getting passed correctly (because of Test A).

I know the Site B API being called is accessible and correct (because of Test B).

Therefore, I assume, the issue is with the values being passed to Azure AD. I assume Azure doesn't think the tokens being obtained in Site A and validated in Site B (that have different URIs) are not "the same" and therefore not authorised.

What do I need to pass to Azure to get it to work?

Thanks

Beakie
  • 1,948
  • 3
  • 20
  • 46

1 Answers1

1

There are 3 bits of validation that will happen against the token

1) It will validate that it was signed by the public keys of the open id provider (e.g. retrieved from here https://login.microsoftonline.com/common/discovery/keys)

2) It will validate the issuer of the token (the iss claim) is valid for the API

3) It will validate the audience of the token (the aud claim) is valid for the API

(there's some additional lifetime validation as well, but these 3 are important at configuration time)

Likely, the token you are sending to the API isn't passing either issuer or audience validation. Use a JWT decoder like http://jwt.ms/ to inspect the token and understand the claims that are being sent to the API.

Does the aud claim of your token match the audience you are specifying in Configuration["AzureAd:ClientId"]?

If it's the same issuer for both tokens and you are happy for 'Site B' to accept tokens from 'Site A', then you can amend token validation parameters to accept multiple options here, have a look at this answer for an example

https://stackoverflow.com/a/47072385/1538039

Investigate the claims in the token, then amend the config of Site B to validate the claims accordingly, by allowing the audiences/issuers you want to be able to communicate with it.

Dylan Morley
  • 1,656
  • 12
  • 21
  • Thanks for this for very clear feedback. I will look into this and report back. Also, the JWT decoder will be very useful. – Beakie Jul 03 '19 at 16:04
  • So, I have checked the JWT token generated by Site A, and it looks like the iss and aud values are correct (and the same as Site B) is comparing against. – Beakie Jul 04 '19 at 10:56
  • Is it possible to get some info about what the authentication failure is caused by? The event log just says the authentication failed. Not the most useful debugging insight. – Beakie Jul 04 '19 at 11:02
  • If I debug both API requests, Site A has a populated ClaimsIdentity, Site B doesn't. This doesn't appear to be an issue with the Azure token claim values at all. Ummm. I'll accept your answer for now (as it answers my original hypothesis). – Beakie Jul 04 '19 at 11:42
  • You won't have a ClaimsIdentity if it's failed token validation parameters. Have a look at OnAuthenticationFailed event, which you can wire up like so https://stackoverflow.com/a/48890853/1538039. The context passed to that method should have the Exception details after doing token validation (as per https://github.com/aspnet/Security/blob/a0b704efbdf924099de908c57087de49c9d12d17/src/Microsoft.AspNetCore.Authentication.JwtBearer/JwtBearerHandler.cs#L113). – Dylan Morley Jul 04 '19 at 11:48
  • You can also get a description in the response by setting IncludeErrorDetails to true on JwtBearerOptions (https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.authentication.jwtbearer.jwtbeareroptions.includeerrordetails?view=aspnetcore-2.2), whatever works best for you – Dylan Morley Jul 04 '19 at 12:08
  • I'll try it now. Thanks for all your help with this. – Beakie Jul 04 '19 at 12:09