Flexible Access Token Validation in ASP.NET Core

The ASP.NET Core authentication system went through a couple of iterations, and is pretty good now. For API scenarios, the typical choice is the JwtBearer authentication handler, which can validate bearer JWT access tokens.

There are other access token types that you might want to use, e.g. reference tokens that get validated via introspection. ASP.NET Core does not include an authentication handler for that, but we have one.

In fact, some people decide that certain (risky/public) clients should use reference token (for revocability), whereas others should use JWTs. This was historically not easy to achieve in ASP.NET Core, because the authentication system wasn’t designed for multiple handlers for the same credential type.

I opened an issue describing the problem a long time ago, which was moved to different backlogs and then ultimately closed with wontfix.

There are a couple of ways to solve the problem – e.g. register two authentication handler, e.g. JwtBearer and the OAuth introspection handler. Give them distinct scheme names, and then create an authorization policy that invokes both.

services.AddAuthorization(options =>
{
    options.AddPolicy("tokens", p =>
        p.AddAuthenticationSchemes("jwt", "introspection"));
        p.RequireAuthenticatedUser();
});

Since this invokes both handlers, one would possibly fail, one possibly succeed. This is overhead, especially since the introspection handler will do an outbound network call. So not recommended.

To solve the problem, we created a brand new authentication handler that acts like a decorator over the JWT and introspection handler. When a token comes in, it looks at its shape, invokes some advanced machine learning that checks whether the token contains a dot – and if yes – it must be a JWT. It then internally dispatches to the JWT handler, otherwise to the introspection handler.

While this works – it has quite a bit of complexity (inspect the source code, it’s not pretty). There are other shortcomings:

  • Our handler needs a unified options object that wraps the options of the individual handler under the covers. While, again this works for most parts, you can be sure that there is someone out there that that needs some setting (or event) of some handler, that was not surfaced by our configuration.
  • It really only works for the two specific handlers we decided to wrap. What if you want to bring another handler to the mix?
  • Having dependencies on the handlers makes versioning harder.
  • More code to maintain.

Going forward, we decided that we do not want to maintain this “hack” any longer. There must be a better way. Enter policy schemes.

Policy scheme were added a while ago (I forget the exact version of ASP.NET Core). Think of them as virtual schemes. They don’t really do anything besides forwarding the various security gestures to other schemes. And while doing that, giving you enough flexibility to decide at runtime which other scheme that would be. Sounds like exactly what we need.

In essence you are providing a function that inspects the current HTTP Request, and returns the scheme name of a handler to forward the request to:

public static string SchemeSelector(HttpContext context)
{
    var (scheme, token) = GetSchemeAndCredential(context);

    if (!string.Equals(scheme, "Bearer", StringComparison.OrdinalIgnoreCase))
    {
        return null;
    }
    
    if (token.Contains("."))
    {
        return "Jwt";
    }
    else
    {
        return "Introspection";
    }
}

You would then wire up a policy scheme to the authentication builder to invoke that function.

builder.AddPolicyScheme("token", "token", policySchemeOptions =>
{
    policySchemeOptions.ForwardDefaultSelector = context =>
        SchemeSelector(context) ?? DefaultScheme;
});

With this feature, I planned for quite some time already to deprecate our dedicated handler and replace it with a policy scheme. While prototyping, Brock pointed me into a direction for an even simple solution.

It turns out that every authentication handler is capable of selectively forwarding requests to another handler. IOW – simply extend your default handler with some forwarding logic to be able to handle more token types:

services.AddAuthentication("token")

    // JWT tokens (default scheme)
    .AddJwtBearer("token", options =>
    {
        options.Authority = Constants.Authority;
        options.Audience = "resource1";

        options.TokenValidationParameters.ValidTypes = new[] { "at+jwt" };

        // if token does not contain a dot, it is a reference token
        options.ForwardDefaultSelector = Selector.ForwardReferenceToken("introspection");
    })

    // reference tokens
    .AddOAuth2Introspection("introspection", options =>
    {
        options.Authority = Constants.Authority;

        options.ClientId = "resource1";
        options.ClientSecret = "secret";
    });

The Selector.ForwardReferenceToken is a little helper that I packaged up in the IdentityModel.AspNetCore.AccessTokenValidation nuget package.

Even when you are not using reference tokens, this is a useful technique for dynamically changing the handler at runtime.

This alone doesn’t really justify maintaining another nuget package, so we threw in two other small helpers that come in useful.

The first addition is a shortcut to create a scope-based authorization policy, e.g.:

services.AddAuthorization(options =>
{
    options.AddScopePolicy("admin", "scope1");
}

…and the other is a way to normalize incoming scope claims. This is useful if your token service uses the new JWT profile for access tokens, where the scope claim is a space delimited string. This does not play nicely with .NET claims, hence we included a little claim transformer, that turns that string into individual claims:

services.AddScopeTransformation();

HTH

Posted in ASP.NET Core, OAuth | 4 Comments

Refresh Tokens in IdentityServer4 v4

I already wrote about the hardening of refresh tokens in this post. I would recommend reading this first.

The upcoming OAuth 2.1 spec is pretty clear about refresh token handling:

  • If the client is confidential, the refresh token must be bound to the client via the client secret.
  • If the client is public, the refresh token must be rotated.

We have always supported client-binding, rotation and also sliding expiration, but we made a couple of changes in v4 to make customization of refresh token handling easier.

First of all we consolidated all refresh token related code in a single extensible place – the IRefreshTokenService with a default implementation called DefaultRefreshTokenService.

Next, we don’t delete consumed refresh tokens anymore from the database. Instead we record the consumed time. This allows for auditing as well as custom handling of refresh token replays of rotated tokens.

The reason you need to be able to implement custom policies is, that receiving a rotated refresh token more than once, is not necessarily always an attack. Faulty client logic like race conditions could be a reason for that, also unstable network connectivity could be the cause.

Depending on your system you might want to tweak the behavior, e.g. implementing a grace period to accomodate network failures, or you might also want to take additional steps if you see a refresh token replay, e.g. revoking other tokens or send notifications.

All of this is now easily possible – check the updated docs.

Posted in IdentityServer, OAuth | Leave a comment

Announcing IdentityServer4 v4.0

OK – it’s finally done. I published v4 to Nuget earlier today. You can find the complete set of changes/bug fixes/breaking changes here.

We had to cut some features which were originally on our roadmap – we’ll revisit them for the next release, which is planned for end of this year.

Let’s have a look at the big new features that we added for this release.

Updates to the Mutual TLS support
MTLS is an important enabler for strong client authentication and proof-of-possession access tokens. We added support for more flexible MTLS endpoint hosting and emitting the cnf claim for ephemeral (or session) X.509 certificates. See this post and docs here.

Private key JWT authentication and JWT secured Authorization requests (JAR)
These both features often go together because they allow authentication of clients on both front- and back-channel using asymmetric keys.

New features include support for JWK formatted key material, updated validation checks to conform with JAR and replay cache support. See this post, docs here.

Conformance with the JWT Profile for OAuth Access Tokens
See this post for more information.

Re-worked API resource and scope handling/validation
See this post for more information.

Updated handling around Refresh Tokens
We consolidated all handling into a single place now, and added support to implement custom replay detection and revocation logic. See this post.

Support for multiple signing Keys and Algorithms
This allows configuring the signing algorithm and thus the key used per client and API resource. See post here.

More features around Session Management and Back-channel Logout Notifications
Going forward, back-channel logout notifications is the only mechanism that will work reliably across domain boundaries. That’s why we polished the feature to be more flexible. Docs soon.

Please give it a try! Have fun!

PS. Our friends from RSK are planning to publish a database migration script. I will let you know once it is available.

Posted in IdentityServer | 2 Comments

Resource Access in IdentityServer4 v4 and going forward

In my last post I alluded to the tension between real-world token-based security architectures, the OAuth 2.0 scope model, JWT access tokens and the audience claim.

We went through a couple of iterations in IdentityServer how we deal with those concepts.

IdentityServer3
By that time OAuth/OIDC and the usage of JWTs was very new, so everybody made their own sense of these technologies – especially how they are supposed to work together.

We decided that the audience claim in JWTs doesn’t really map to OAuth and its scope concept, so we didn’t really use the aud claim. Instead we emitted the granted scopes in the scope claim.

Mostly to make JWT libraries happy, we also emitted a static aud claim. The format was issuer_name/resources and was a way in APIs to make sure that this is an access token coming from a certain issuer.

IdentityServer4 v1-v3
In IdentityServer4 we introduced the ApiResource abstraction to make it easier to structure the API surface. In our configuration model, you could add named APIs that could act as a container for scopes and other settings. If an API resource did not define an explicit scope, we added one under the covers with the same name as the API.

We continued to emit the granted scopes in the scope claim, but also started emitting the API names as the aud claim. We also made the static aud claim optional.

This led to many scenarios where the aud and scope claims were identical, and it felt wrong to force everyone into the resource abstraction – and certainly against the original spirit of OAuth.

IdentityServer4 v4
With the advent of the resource indicator spec, we finally have a more formalized way how resources relate to scopes – and this is also a perfect match for our resource configuration model.

But at the same time, we’ve done a lot of consulting for very different types of OAuth-based installation over the last years to know, that not everyone needs the resource concept.

That’s why we decided to give you more control – you can either model scopes as a flat list, or hierarchical. Which means you can go from a very simple model like read/write/update scopes to very complex namespaced resource/scope combinations. Also sharing scopes between resources is now possible as well.

We made the aud claim optional again (for a scopes only model) – or static – or based on the requested resource. It’s up to you now.

While we were at it, we also enabled easy support for parameterized scopes like e.g. transaction:id since they are used for some recent APIs specs like FAPI of FHIR.

These changes will require some minor migration steps when upgrading to v4, but allows for more flexibility.

Also, the work we did is foundational for the next step in IdentityServer’s resource access story, which is supporting resource isolation – or IOW resource indicators. This will ship in the next major update – which will be around end of this year, so stay tuned.

I wrote up the conceptional bits in our updated docs. Please give it a try!

Posted in IdentityServer, OAuth | 4 Comments

I don’t like Identity Tokens

…or rather the name ;)

I bet that if you wake up most “identity professionals” in the middle of the night and ask them what an identity token is, the answer would be “a token about the identity of the user”.

This is not wrong – but it is definitely not the rightest answer.

In OIDC, the token service needs to send data about “what happened during authentication” back to the client applications, e.g. authentication method, authentication time, some protocol information and a unique identifier for the user that was authenticated. And – yes this might also include other identity information about the user, but this is optional.

This data must be sent in a format that is both tamper proof and that allows the client to authenticate the issuer. In OIDC this format is JSON – and the way how you add the above security properties to a JSON object is by wrapping it in a JWT (along with JWS, JWA and JWK) – hence the name identity token. I would prefer “authentication response” instead – because that’s exactly what it is.

Also, some people are confused and think you can also use the identity token to act like an “access token”, which is wrong. Not using the word “token” at all, would be much clearer.

Posted in OpenID Connect | Leave a comment

The JWT Profile for OAuth 2.0 Access Tokens (and IdentityServer)

As part of creating our new Advanced OAuth training, I created a whole lecture on the evolution of access tokens and resource access.

It’s fascinating – since the original OAuth 2.0 spec does not have any information about the token format, content or semantics – everybody kind of made up something that works for them (including us).

As you can see on the timeline, JWTs were not even a thing when OAuth 2.0 was released, and to be honest, also the JWT spec is just a framework for how a JWT might look like, and is not always the best natural match for OAuth semantics.

Still JWTs won because simplicity, and if you look at various vendors’ JWT format, you can see different interpretations of how OAuth might map to it.

Fast forwarding to 2020, our good friend Vittorio made an effort of trying to formalize JWTs for OAuth and has been working on an official profile. There have been discussions going back and forth, we are not always in agreement, but nevertheless the document will be released soon-ish.

Let’s have a look at the proposed JWT format, and how IdentityServer conforms to it.

Header
One of the best features of the spec IMO is the introduction of a type header. This allows resource server to make sure they actually deal with an access token. The value is at+jwt and we support this for a while now – I wrote about it here.

iss (issuer) and exp (expiration) claim
These are pretty much no brainers and have been supported in IdentityServer since ever.

client_id claim
Represents the client ID of the OAuth client. Present since day 1 in IdentityServer.

jti (JWT identifier) claim
A unique identifier for the token. Allows implementing replay detection. This is a per-client setting in IdentityServer, but we changed the default value to emit jti in v4.

scope claim
If the scope request parameter is used, the access token should contain the granted scopes as a claim. Makes total sense, but there might be some variations with the actual format. The spec says it must be a space delimited list. IdentityServer has historically been using a string array for that, because it played nicer with the .NET claims infrastructure.

As of v4 you can switch from the array format to the string format by setting the EmitScopesAsSpaceDelimitedStringInJwt option – be aware that this will probably break existing consumers.

aud (audience) claim
This is a more complicated story – but to make it short: pure OAuth has no concept of an audience. The closest thing is the scope parameter, which is spectacularly under-defined and more abstract. IOW – everyone came up with their own interpretation of that.

In IdentityServer3 we emitted a static audience claim, and we changed that in IdentityServer4 to use the name of the request API resource(s). We were not happy with both approaches.

In the new v4 we give you more control – you can set a static audience; you can omit the audience altogether – or you can use the API resource name (and this will become even more interesting when you mix in resource indicators). I have a more detailed post in the making to discuss the various options and will post it soon.

The JWT profile spec makes aud mandatory and I don’t fully agree with this decision. Either way, IdentityServer conforms to it, if you want to.

iat (issued_at) claim
The profile favours iat over nbf. The practical intent is similar enough. The .NET library prefers nbf historically and will emit both now in v4.

sub (subject identifier) claim
This is the really big elephant in the room.

Since we designed IdentityServer to be an OpenID Connect and OAuth 2.0 system (strong emphasis on the ‘and’) – we decided to use the OIDC definition of the sub claim for both identity and access tokens. The main motivation was to make it very explicit to every token consumer: the sub claim represents the unique identifier of an end-user. This also meant that, when no sub claim is present, there is no user involved – which e.g. would apply to a pure machine to machine communication.

This is where the JWT profile differs. It gives the sub claim a dual semantic. If an end-user is involved, the sub claim uses the OIDC definition (aka the user ID). If no end-user is involved, the sub claim represents the client ID of the OAuth client.

I personally (and tbh none of our customers) don’t like that ambiguity and the best explanation I have is, that this unifies the sub claim to be the target of authorization rules in the consumer (either a user or a client). But this is only what I came up with, to make a little bit more sense out of that. I had situations where this was actually useful – but I prefer the freedom to decide how I want to model that. The profile does not motivate this besides: sub is mandatory (which btw is not true according to the JWT specification).

In IdentityServer we always supported emitting static claims per client, so you can easily emit a static sub claim, and e.g. make that the same value as client_id.

Other claims
The profile allows for other (user-centric) claims, e.g. auth_time, amr or acr. Again, this has always been the case in IdentityServer, and makes total sense.

Summary
It’s a lot of work to write and discuss a new specification – so thanks Vittorio for taking on that task. The main goal of the profile is to give us a common language when talking about access token content and semantics – and to help with interop.

Given the type of changes we had to make to IdentityServer to conform with it (and I suppose we are one of the more agile OAuth implementations), I doubt if (or when) the major vendors will switch to this format. But still it is a useful start.

My final comment would be that I would prefer the profile to make the aud and sub claims optional, because I just don’t agree with the conclusions made here. But that’s just my personal opinion. We made sure that you can be compliant in IdentityServer, if you want to.

Posted in IdentityServer, OAuth, OpenID Connect | Leave a comment

Updates on our Workshops

I am pleased to announce that we are now offering two workshops. I was mentioning that on Twitter already, and got a lot of questions. So I thought it would make sense to summarise them all in one place.

You can find descriptions for both workshops on our training page: https://identityserver.io/training/

Identity & Access Control for modern Applications using ASP.NET Core
This is our flagship training that we are running now for many years.

This workshop is an introduction to modern security architecture, OpenID Connect and OAuth 2.0 from the perspective of an ASP.NET Core developer or architect.

When you start building applications using token-based security, there are a lot of moving parts around the protocols and the concrete APIs of your application framework – and you also have to put these blocks together to create meaningful architectures. That’s what this workshop is all about.

The workshop is always very well attended and very often the biggest workshop when run at conferences. This tells us that there is definitely a need for this type of content. We keep evolving it constantly to keep up with ASP.NET Core changes and the industry best practices.

See here for a detailed agenda and watch this video for a sneak peak into some of the topics we cover in this two or three day workshop.

We run this workshop either as in-house versions or open enrolments. Either contact us to discuss an in-house version, or check our page for upcoming open enrolments.

Advanced OAuth
This is our new 1-day course covering all the new specs and everything you need to know to create high security OAuth architectures.

We’ve been involved for the last couple of years implementing OpenID Connect and OAuth in the health sector in Norway. As you can imagine this is subject to many strict laws and regulations. Other highly regulated industries like finance and e-gov had similar pushes, and this resulted in various “higher security” profiles for OAuth and OpenID Connect.

Though pioneered in these high security environments, the specs and guidance is now being consolidated and make their way into “normal” applications that need more security than plain RFC 6749 has to offer.

This workshop starts, where our introduction workshop ends and talks about the latest specs and best practices for securing OAuth and adding additional features like stronger authentication of front- and back-channels, proof-of-possession, sender and audience constraints and much more.

This course is currently only offered for in-house/remote deliveries. If you are a company and are interested in this contact, please contact us. We are thinking about running open-enrolments later this year – so if you are an individual, please also contact us, so we can get a better feeling for the demand.

Here’s the overview page for this training, and here you can find a recent recording covering an excerpt of the security best practices content.

Hopefully see you soon in some training room around the world – virtual or in-person!

Posted in OAuth, OpenID Connect | Leave a comment

Automatic Token Management for ASP.NET Core and Worker Services 1.0

After a pretty long preview period, I am happy to announce that IdentityModel.AspNetCore 1.0 is now on Nuget.

This library solves a problem that we have with every single OIDC/OAuth client we are creating: token management.

Requesting and using a token is the easy part – managing the token and its lifetime is the hard part. But also boilerplate.

The library helps with access token lifetime management for pure machine to machine communication and user-centric applications with refresh tokens.
For user-centric it provides:
  • storage abstraction for access and refresh tokens (default implementation using the ASP.NET Core authentication session)
  • automatic refresh of expired access tokens
  • refresh token revocation
  • token lifetime automation for HttpClient
For worker services it provides:
  • caching abstraction for access tokens (default implementation using IDistributedCache)
  • automatic renewal of expired access tokens
  • token lifetime automation for HttpClient
I’ve been holding back with releasing, because I wanted to get some feedback from more people and customers, and I also wanted to make sure it is ready for all of the advanced scenarios I am using for our new Advanced OAuth workshop.

 

Best part – it also has docs. See here for workers, see here for web applications – and here for some more info on plugging in your own configuration and storage abstractions.
HTH
Posted in .NET Security, ASP.NET Core, IdentityServer, OAuth, OpenID Connect | 1 Comment

Major Update to IdentityModel.OidcClient

I just pushed Preview 3 of the 4.0 version of IdentityModel.OidcClient – this includes some major updates (that you might or might not have asked for):

  • Removal of OpenID Connect Hybrid Flow.
    The codebase does Authorization Code Flow + PKCE only now. This is inline with RFC8525 and the AppAuth reference implementations. Also – this reduced the complexity of the codebase dramatically
  • Support for pure OAuth-based request.
    Before this change, the openid scope was mandatory, which always meant OpenID Connect compliance on the server. You can now omit openid and do pure OAuth 2.0 as well.
  • Removing JWT signature validation from the core codebase.
    The signature validation is now a pluggable component. I provide a default implementation using Microsoft’s JWT handler in a separate Nuget package. This allowed to remove that dependency from OidcClient.
  • Removed dependency on NewtonSoft.Json
    Still IdentityModel uses it, this will change as well at some point.

All in all, this make OidcClient slimmer and thus hopefully easier to integrate into existing applications.

Please give it a try.

Posted in IdentityModel, OAuth, OpenID Connect | 2 Comments

SPAs are dead!?

clickbait isn’t it? But this was Brock’s immediate reaction when we saw (and I recommend you read this first):

Full Third-Party Cookie Blocking and More

What this basically means is, that browser are getting more and more strict with how they handle their cookies. The reasons are security (see the recent SameSite changes) and in this case – privacy. Cookies have been exploited for a long time one way or the other – and this is now the reaction of browser vendors.

What does that mean to application architectures? Well – first of all – all these changes only affect cross-site scenarios. But if you are in that situation the immediate consequences will be:

  • front-channel logout notifications do not work anymore (used in pretty much every authentication protocol – like SAML, WS-Fed and OpenID Connect)
  • the OpenID Connect JavaScript session notifications don’t working anymore
  • the “silent renew” technique that was recommended so far to give your application session bound token refreshing don’t work anymore

Safari and Brave are the first browser implementing those changes. Chrome will follow in 2022 (hopefully sooner) etc…

Some things can be fixed, e.g. you can replace front-channel notifications with back-channel ones. Some people recommend replacing silent renew with refresh tokens. This is dangerous advice – even if your token service has implemented countermeasures.

If all the security concerns around storing tokens in browsers did not worry you so far, maybe this is a good reason to consider the BFF architecture for your SPAs (if you are looking for less fancy name – it’s what the BCP calls “JavaScript Applications with a back-end“).

So are SPAs dead? Well – SPAs as in the UI/UX concept certainly not. SPAs as in “browser-based standalone applications that do cross-site authentication and API calls in the context of a modern identity and SSO architectures” – yes.

(and they should be unless we fix some fundamental problems)

my 2c.

Posted in OAuth, OpenID Connect | 23 Comments