Optimizing Identity Tokens for size

Generally speaking, you want to keep your (identity) tokens small. They often need to be transferred via length constrained transport mechanisms – especially the browser URL which might have limitations (e.g. 2 KB in IE). You also need to somehow store the identity token for the length of a session if you want to use the post logout redirect feature at logout time.

Therefore the OpenID Connect specification suggests the following (in section 5.4):

The Claims requested by the profile, email, address, and phone scope values are returned from the UserInfo Endpoint, as described in Section 5.3.2, when a response_type value is used that results in an Access Token being issued. However, when no Access Token is issued (which is the case for the response_type value id_token), the resulting Claims are returned in the ID Token.

IOW – if only an identity token is requested, put all claims into the token. If however an access token is requested as well (e.g. via id_token token or code id_token), it is OK to remove the claims from the identity token and rather let the client use the userinfo endpoint to retrieve them.

That’s how we always handled identity token generation in IdentityServer by default. You could then override our default behaviour by setting the AlwaysIncludeInIdToken flag on the ScopeClaim class.

When we did the configuration re-design in IdentityServer4, we asked ourselves if this override feature is still required. Times have changed a bit and the popular client libraries out there (e.g. the ASP.NET Core OpenID Connect middleware or Brock’s JS client) automatically use the userinfo endpoint anyways as part of the authentication process.

So we removed it.

Shortly after that, several people brought to our attention that they were actually relying on that feature and are now missing their claims in the identity token without a way to change configuration. Sorry about that.

Post RC5, we brought this feature back – it is now a client setting, and not a claims setting anymore. It will be included in RTM next week and documented in our docs.

I hope this post explains our motivation, and some background, why this behaviour existed in the first place.

This entry was posted in .NET Security, IdentityServer, OpenID Connect, WebAPI. Bookmark the permalink.

5 Responses to Optimizing Identity Tokens for size

  1. Alex says:

    May be this is stupid question, but what is the point of ID token that is empty, meaning no any user related info?

  2. Thank you for this article. I am sending it to our developers when ever they ask me to add yet another claim to our token.

  3. daiplusplus says:

    Even with a minimal id_token, the size of the JWT is still about 1KB in size – that doesn’t leave much room for many user claims and also results in difficulties when keeping the id_token around for passing to logout actions (when the id_token JWT did contain my application-specific claims, the total size was about 1400 bytes). I reasoned the the added complexity of using the user-info endpoint and reduced performance (from the server having to make a second HTTP request) didn’t justify saving 400 bytes in JWT size so I stuck with the old behaviour.

    Side note: I wrote my own ASP.NET Core Cookie Ticket serializer which uses DEFLATE to compress ASP.NET Core’s Auth cookie before encryption down from ~7000 bytes to ~1800 bytes. There is a LOT of redundant data in ASP.NET Core’s auth cookies :(

    Using https://jwt.io with the “minimal” id_token that contains only “sub” and no custom claims, I see that a lot of space is still used by the signature portion of the JWT as IS4 still only supports RS256 (which uses a lot of space, around 300 bytes) compared to ~90 bytes for ES256). A large chunk of the Claims section is used by the nonce claim and other protocol claims – given that id_token isn’t sensitive (and the client should be able to trust it given it knows where it came from), can’t we remove many of these claims? (and if so, how?)

Leave a comment