Migrating to AspNet.Security.OpenIdConnect.Server RC1

Earlier today, I released the RC1 version of the OpenID Connect server middleware, alongside the other aspnet-contrib packages.

This version – the latest before RTM – includes a few design changes that will directly impact your own code:

The built-in claims mapping feature was removed

Starting with RC1, ASOS no longer includes a built-in claims mapping feature, which means claims like ClaimTypes.NameIdentifier, ClaimTypes.Name or ClaimTypes.Role are no longer mapped to their OpenID Connect/JWT equivalents (sub, name, role).

Concretely, if you have code like that in your authorization provider class, you should update it to use the OpenID Connect claims instead of the legacy claims exposed by the static ClaimTypes class:

1
2
3
4
5
6
7
8
9
10
11
var identity = new ClaimsIdentity(OpenIdConnectServerDefaults.AuthenticationScheme);

identity.AddClaim(ClaimTypes.NameIdentifier, "[unique identifier]");

identity.AddClaim(ClaimTypes.Name, "Bob",
OpenIdConnectConstants.Destinations.AccessToken,
OpenIdConnectConstants.Destinations.IdentityToken);

identity.AddClaim(ClaimTypes.Role, "Administrator",
OpenIdConnectConstants.Destinations.AccessToken,
OpenIdConnectConstants.Destinations.IdentityToken);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Configure ClaimsIdentity to use the OpenID Connect claims instead of
// the legacy ClaimTypes claims to populate the ClaimsIdentity.Name property
// and determine how roles are resolved when calling ClaimsPrincipal.IsInRole(...).
var identity = new ClaimsIdentity(
OpenIdConnectServerDefaults.AuthenticationScheme,
OpenIdConnectConstants.Claims.Name,
OpenIdConnectConstants.Claims.Role);

identity.AddClaim(OpenIdConnectConstants.Claims.Subject, "[unique identifier]");

identity.AddClaim(OpenIdConnectConstants.Claims.Name, "Bob",
OpenIdConnectConstants.Destinations.AccessToken,
OpenIdConnectConstants.Destinations.IdentityToken);

identity.AddClaim(OpenIdConnectConstants.Claims.Role, "Administrator",
OpenIdConnectConstants.Destinations.AccessToken,
OpenIdConnectConstants.Destinations.IdentityToken);

You're actually free to keep using the ClaimTypes claims, but the OpenID Connect server middleware will throw an exception if you don't (at least) add the sub claim:

InvalidOperationException: The authentication ticket was rejected because it doesn't contain the mandatory subject claim.

If you use the JWT bearer middleware, you'll also want to disable its own claims mapping feature and update the token validation parameters to use the dedicated JWT name/role claims:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
JwtSecurityTokenHandler.DefaultOutboundClaimTypeMap.Clear();

app.UseJwtBearerAuthentication(new JwtBearerOptions
{
Authority = "http://localhost:58795/",
Audience = "resource_server",
RequireHttpsMetadata = false,
TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = OpenIdConnectConstants.Claims.Name,
RoleClaimType = OpenIdConnectConstants.Claims.Role
}
});

The introspection middleware now uses name and role as the default claim types

In the same vein, the introspection middleware was updated to use name and role as the default claim types (instead of ClaimTypes.Name and ClaimTypes.Role):

1
2
3
4
5
6
7
8
9
10
11
app.UseOAuthIntrospection(options =>
{
options.Authority = new Uri("https://openid.yourapp.com/");
options.Audiences.Add("resource_server");
options.ClientId = "resource_server";
options.ClientSecret = "875sqd4s5d748z78z7ds1ff8zz8814ff88ed8ea4z4zzd";

// Override the default claim types used by the introspection middleware:
options.NameClaimType = "custom_name_claim";
options.RoleClaimType = "custom_role_claim";
});

The token format was improved

To support multi-valued authentication properties containing spaces, we had to tweak the token format to store these complex properties as JSON strings.

Unfortunately, this change makes old authorization codes, access and refresh tokens incompatible with the new format (and vice versa). In practice, this means that you can't use tokens issued by ASOS RC1 with old versions of the validation middleware (or with the OpenID Connect server middleware itself): such tokens will be automatically rejected.

To make sure everything runs smoothly, migrate to the latest version of the validation middleware (1.0.0-beta1-final).

Registering a signing key is no longer required when using the default access token format

Starting with RC1, ASOS now includes a "degraded mode" that allows you to use it without registering a signing key or a signing certificate (ephemeral or not) if you don't opt for JWT access tokens and don't use the implicit or hybrid flows.

Concretely, using AddEphemeralKey() or AddCertificate() is no longer mandatory if you use non-interactive flows like password or client credentials AND the default access token format.

And voilà, that's all. For the complete changelist, feel free to take a look at the GitHub issues page.


What's next?

No new release candidate is currently planned, which means the next version will be the RTM package.

The next (and last) step is to rework the XML documentation. Depending on how well this work item goes, the RTM bits should be published at the end of the month or in April. If you're willing to contribute to this stask, don't hesitate to ping me.