How to configure and consume explicitly typed ID tokens and UserInfo JWTs

Applications that deal with JSON Web Tokens (JWT) meant for different purposes can potentially become vulnerable to accidental mix ups of JWTs and even to attacks that try to pass one type of JWT for another. The claims structure of JWTs minted for different purposes would normally differ, however not all JWT consuming logic may be robust enough to do this correctly and this may become a security issue.

To prevent such mix ups the JSON Web Token standard (RFC 7519) defines an optional "typ" (type) header parameter to give the JWT an explicit type. Consuming logic needs only to probe this header to find out the JWT purpose, without resorting to further analysis of the claims in the JWT payload.

OpenID Connect does not specify an explicit type for ID tokens and for signed UserInfo responses, relying on the fact that their claims sets differ substantially. Clients also obtain them at different endpoints - ID tokens at the token endpoint and signed UserInfo responses at the UserInfo endpoint.

Example ID token claims set:

{
  "iss"   : "https://c2id.com",
  "aud"   : "123",
  "sub"   : "alice",
  "iat"   : 1648547159,
  "exp"   : 1648547759
}

Example UserInfo JWT claims set:

{
  "iss"   : "https://c2id.com",
  "aud"   : "123",
  "sub"   : "alice",
  "iat"   : 1648547159,
  "email" : "[email protected]"
}

Notice how the ID token differs only by the presence of the "exp" (expiration) claim (the email UserInfo claim is optional).

In scenarios like token exchange the lack of explicit typing can however turn into an issue. That's why more recent specifications coming out of the the OAuth working group and the OpenID Foundation started making use of the explicit JWT typing. For example, at+jwt for access tokens compliant with RFC 9068.

In this new release Connect2id server deployments will be able to set explicit type headers for the ID tokens and UserInfo JWTs. This is made possible by two new configuration properties:

  • op.idToken.jwtType -- Sets the type header of issued ID tokens, if set the recommended value is id_token+jwt. Disabled by default.
  • op.userinfo.jwtType -- Set the type header of issued UserInfo JWTs, if set the recommended value is userinfo+jwt. Disabled by default.

Note, typed back-channel logout tokens are supported by default since Connect2id server v12.10.

Sample ID token without explicit typing:

  • JWS Header:

    {
       "kid" : "CXup",
       "alg" : "RS256"
    }
    
  • Claims:

    {
       "iss"   : "https://c2id.com",
       "aud"   : "123",
       "sub"   : "alice",
       "iat"   : 1648547159,
       "exp"   : 1648547759
    }
    

Sample ID token with explicit typing (note the id_token+jwt header):

  • JWS Header:

    {
       "kid" : "CXup",
       "alg" : "RS256",
       "typ" : "id_token+jwt"
    }
    
  • Claims:

    {
       "iss"   : "https://c2id.com",
       "aud"   : "123",
       "sub"   : "alice",
       "iat"   : 1648547159,
       "exp"   : 1648547759
    }
    

The IDTokenValidator was updated in v9.32 of the OAuth 2.0 / OpenID Connect SDK to support explicitly typed ID tokens. Note, since this is a non-standard feature, other libraries may not be able to observe the "typ" header or may simply reject explicitly typed ID tokens.