Creating your own OpenID Connect server with ASOS: adding custom claims and granting scopes


Attaching a destination to custom claims using AddClaim or SetDestinations

Unlike OAuthAuthorizationServerMiddleware, ASOS doesn't assume that access tokens are always consumed by your own resource servers and refuses to serialize claims that don't explicitly specify a destination to avoid leaking confidential data to unauthorized parties.

Two destinations are currently supported by ASOS: access_token and id_token. There's no equivalent for authorization codes or refresh tokens as they are always encrypted and only readable by the authorization server itself.

Concretely, this means that all your claims won't be returned to the client application, unless you explicitly call the AddClaim overload taking one or more destinations or use SetDestinations to attach the appropriate destination(s) to your claims.

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

// When access_token and id_token are specified,
// the claim will be serialized in both tokens.
identity.AddClaim("username", "Pinpoint",
OpenIdConnectConstants.Destinations.AccessToken,
OpenIdConnectConstants.Destinations.IdentityToken);

// If only access_token is specified, the language
// claim won't be added in the identity token.
var claim = new Claim("language", "fr-FR");
claim.SetDestinations(OpenIdConnectConstants.Destinations.AccessToken);

identity.AddClaim(claim);

Specifying a list of resources using ticket.SetResources()

By default, the access tokens issued by ASOS are not constrained to a specific audience and can be used with virtually any API accepting the tokens issued by your authorization server.

When creating an authentication ticket, you can specify a list of resource servers (i.e APIs) the client application is allowed to access using ticket.SetResources(), which will limit the audiences of the access tokens serialized by ASOS.

Specifying a list of resources can be particularly useful when using JWT tokens, as many implementations (like the JWT bearer middleware developed by Microsoft) are designed to reject access tokens that don't have an explicit aud (audience) claim, though it's not a mandatory claim according to the JWT specification.

1
2
3
4
5
6
7
8
9
// Create a new authentication ticket holding the user identity.
var ticket = new AuthenticationTicket(
new ClaimsPrincipal(identity),
new AuthenticationProperties(),
OpenIdConnectServerDefaults.AuthenticationScheme);

// Set the resource servers the access token should be issued for.
// Multiple values can be specified, but they can't contain space characters.
ticket.SetResources("resource_server", "http://localhost:12345/");

Specifying a list of scopes using ticket.SetScopes()

Starting with ASOS beta5, request scopes are no longer automatically attached to the authentication ticket: it's now up to you to list the scopes you want to grant.

If you don't explicitly grant the offline_access scope, no refresh token will be returned to the client application. Similarly, if you don't include openid as a granted scope, the caller won't get back an identity token.

1
2
3
4
5
6
7
8
9
10
11
12
// Create a new authentication ticket holding the user identity.
var ticket = new AuthenticationTicket(
new ClaimsPrincipal(identity),
new AuthenticationProperties(),
OpenIdConnectServerDefaults.AuthenticationScheme);

// Set the list of scopes granted to the client application.
ticket.SetScopes(
/* openid: */ OpenIdConnectConstants.Scopes.OpenId,
/* email: */ OpenIdConnectConstants.Scopes.Email,
/* profile: */ OpenIdConnectConstants.Scopes.Profile,
/* offline_access: */ OpenIdConnectConstants.Scopes.OfflineAccess);

Next part: Testing your authorization server with Postman.