Figuring out Why Your Access Token is Invalid (OWIN/Katana)

I was doing some consultancy work for a client today and had to integrate with an IDP to secure an API.  Somehow however, the access tokens provided by the IDP couldn’t be validated.  For access token validation I by default use IdentityServer’s AccessTokenValidation middleware as it adds some nifty features to MS’s JWT Bearer Authentication middleware. In this case the IDP wasn’t IdentityServer, but as the middleware essentially wraps MS’s JWT middleware it should work – I’ve successfully integrated with various IDPs in the past, using IdentityServer’s AccessTokenValidation middleware to validate the access tokens.

No such luck this time – at least at first sight.  For reference, I tried this with both the IdentityServer3.AccessTokenValidation & IdentityServer4.AccessTokenValidation middleware versions – both seemed to fail.

My main issue was that I couldn’t identify the exact problem that was causing the validation failure. I didn’t see anything being written to the console output window, so I was completely in the dark.

The middleware uses Katana’s logging infrastructure – yet by default, this isn’t turned on if you start a new project.  To fix it, I added the following few lines to my web config:

<system.diagnostics> 
  <trace autoflush="true" />
  <switches>
    <add name="Microsoft.Owin" value="Verbose" />
  </switches>
</system.diagnostics>

This configures the built-in Microsoft.Owin switch, setting it at level Verbose.  Et voila – I could see the exact cause of the issue in my console output window.  In case you ever find yourself struggling with token validation issues, enabling logging like this really helps.

By the way, to log to a file, add this underneath <system.diagnostics>:

<sources>
  <source name="Microsoft.Owin">
    <listeners>
      <add name="OwinKatanaListener" />
    </listeners>
  </source>
</sources>

<sharedListeners>
  <add name="OwinKatanaListener" type="System.Diagnostics.TextWriterTraceListener"       initializeData="owinkatana.trace.log" traceOutputOptions="DateTime" />
</sharedListeners>

This adds a listener which will write to a file named owinkatana.trace.log.

Oh, and in case you’re curious about what the issue turned out to be: the IDP didn’t include an audience claim in the access token.  Even though it’s not required per se, most modern IDPs fill this out and the middleware by default checks if the value(s) match either the required scopes (IdentityServer3 middleware) or ApiName (IdentityServer4 middleware).  Turning off audience validation and switching to the “older” scope validation approach solved the issue.

Happy coding! :)

 Tweet about this on TwitterShare on LinkedInShare on Facebook

4 Comments

Daniel Archer

Wish I had seen this post days ago, I have had a nightmare of a time trying to integrate Microsoft’s tokens using msal on a react client and a .net core API. Finally got it working using Azure B2C and have just switched to now use the v2 application portal due to B2C bizarre behaviour. But trying to figure out why .net core wasn’t accepting the tokens was like stabbing in the dark, would have been great to have known this logging trick – thanks for sharing.

Reply
Marton Balassa

How did you turn off audience validation? I’m struggling with this, have to use bearer token validation in a .NET framework (not Core) web app.

Reply
Kevin Dockx

Hi Marton,

depends on the middleware version you’re using. If you’re using IdentityServer4.AccessTokenValiation, you can access the underlying jwt handler as such:

ervices.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
.AddIdentityServerAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme,
jwtOptions =>
{
// jwt bearer options
},
referenceOptions =>
{
// oauth2 introspection options
});

With the IdentityServer3 version I didn’t find a way to easily do that, so I reverted to using MS’s underlying middleware directly. Something along these lines:

app.UseJwtBearerAuthentication(new JwtBearerAuthenticationOptions()
{
TokenValidationParameters = new TokenValidationParameters
{
// do not validate the audience
ValidateAudience = false,
… etc
}
});

Reply

Leave a Reply

Your email address will not be published. Required fields are marked *