OIDC ID Token

Cloud Journey
7 min readDec 15, 2022

Overview

In this article, we will discuss OIDC ID token claims, look at some example tokens, check out the standard specification, and learn more about replay attack and secure cookies.

ID Token Example

jwt.ms: Welcome!

{ “typ”: “JWT”, “alg”: “RS256”, “kid”: “1LTMzakihiRla_8z2BEJVXeWMqo” }
.{ “ver”: “2.0”, “iss”: “https://login.microsoftonline.com/9122040d-6c67-4c5b-b112-36a304b66dad/v2.0", “sub”: “AAAAAAAAAAAAAAAAAAAAAIkzqFVrSaSaFHy782bbtaQ”, “aud”: “6cb04018-a3f5–46a7-b995–940c78f5aef3”, “exp”: 1536361411, “iat”: 1536274711, “nbf”: 1536274711, “name”: “Abe Lincoln”, “preferred_username”: “AbeLi@microsoft.com”, “oid”: “00000000–0000–0000–66f3–3332eca7ea81”, “tid”: “9122040d-6c67–4c5b-b112–36a304b66dad”, “nonce”: “123523”, “aio”: “Df2UVXL1ix!lMCWMSOJBcFatzcGfvFGhjKv8q5g0x732dR5MB5BisvGQO7YWByjd8iQDLq!eGbIDakyp5mnOrcdqHeYSnltepQmRp6AIZ8jY” }
.[Signature]

OIDC Spec.

The following Claims are used within the ID Token for all OAuth 2.0 flows used by OpenID Connect:

iss
REQUIRED. Issuer Identifier for the Issuer of the response. The iss value is a case sensitive URL using the https scheme that contains scheme, host, and optionally, port number and path components and no query or fragment components.
sub
REQUIRED. Subject Identifier. A locally unique and never reassigned identifier within the Issuer for the End-User, which is intended to be consumed by the Client, e.g., 24400320 or AItOawmwtWwcT0k51BayewNvutrJUqsvl6qs7A4. It MUST NOT exceed 255 ASCII characters in length. The sub value is a case sensitive string.
aud
REQUIRED. Audience(s) that this ID Token is intended for. It MUST contain the OAuth 2.0 client_id of the Relying Party as an audience value. It MAY also contain identifiers for other audiences. In the general case, the aud value is an array of case sensitive strings. In the common special case when there is one audience, the aud value MAY be a single case sensitive string.
exp
REQUIRED. Expiration time on or after which the ID Token MUST NOT be accepted for processing. The processing of this parameter requires that the current date/time MUST be before the expiration date/time listed in the value. Implementers MAY provide for some small leeway, usually no more than a few minutes, to account for clock skew. Its value is a JSON number representing the number of seconds from 1970-01-01T0:0:0Z as measured in UTC until the date/time. See RFC 3339 [RFC3339] for details regarding date/times in general and UTC in particular.
iat
REQUIRED. Time at which the JWT was issued. Its value is a JSON number representing the number of seconds from 1970-01-01T0:0:0Z as measured in UTC until the date/time.
auth_time
Time when the End-User authentication occurred. Its value is a JSON number representing the number of seconds from 1970-01-01T0:0:0Z as measured in UTC until the date/time. When a max_age request is made or when auth_time is requested as an Essential Claim, then this Claim is REQUIRED; otherwise, its inclusion is OPTIONAL. (The auth_time Claim semantically corresponds to the OpenID 2.0 PAPE [OpenID.PAPE] auth_time response parameter.)
nonce
String value used to associate a Client session with an ID Token, and to mitigate replay attacks. The value is passed through unmodified from the Authentication Request to the ID Token. If present in the ID Token, Clients MUST verify that the nonce Claim Value is equal to the value of the nonce parameter sent in the Authentication Request. If present in the Authentication Request, Authorization Servers MUST include a nonce Claim in the ID Token with the Claim Value being the nonce value sent in the Authentication Request. Authorization Servers SHOULD perform no other processing on nonce values used. The nonce value is a case sensitive string.
acr
OPTIONAL. Authentication Context Class Reference. String specifying an Authentication Context Class Reference value that identifies the Authentication Context Class that the authentication performed satisfied. The value "0" indicates the End-User authentication did not meet the requirements of ISO/IEC 29115 [ISO29115] level 1. Authentication using a long-lived browser cookie, for instance, is one example where the use of "level 0" is appropriate. Authentications with level 0 SHOULD NOT be used to authorize access to any resource of any monetary value. (This corresponds to the OpenID 2.0 PAPE [OpenID.PAPE] nist_auth_level 0.) An absolute URI or an RFC 6711 [RFC6711] registered name SHOULD be used as the acr value; registered names MUST NOT be used with a different meaning than that which is registered. Parties using this claim will need to agree upon the meanings of the values used, which may be context-specific. The acr value is a case sensitive string.
amr
OPTIONAL. Authentication Methods References. JSON array of strings that are identifiers for authentication methods used in the authentication. For instance, values might indicate that both password and OTP authentication methods were used. The definition of particular values to be used in the amr Claim is beyond the scope of this specification. Parties using this claim will need to agree upon the meanings of the values used, which may be context-specific. The amr value is an array of case sensitive strings.
azp
OPTIONAL. Authorized party - the party to which the ID Token was issued. If present, it MUST contain the OAuth 2.0 Client ID of this party. This Claim is only needed when the ID Token has a single audience value and that audience is different than the authorized party. It MAY be included even when the authorized party is the same as the sole audience. The azp value is a case sensitive string containing a StringOrURI value.
ID Tokens MAY contain other Claims. Any Claims used that are not understood MUST be ignored. See Sections 3.1.3.6, 3.3.2.11, 5.1, and 7.4 for additional Claims defined by this specification.

ID Tokens MUST be signed using JWS [JWS] and optionally both signed and then encrypted using JWS [JWS] and JWE [JWE] respectively

(https://openid.net/specs/openid-connect-core-1_0.html#IDToken)

Replay Attack

What’s a replay attack?

The attacker sniffs data packets being sent from one IP address to another. They are a form of a man-in-the-middle attack.

Even when the data is encrypted in transit, it still has value to the attacker. Say that person A wishes to login into a website. They send their authentication data, which might consist of a session ID, login credentials, and password hash — all of which are encrypted. If our attacker, person B, intercepts this data and then forwards it to the intended server, they can sit back and receive whatever information that person A’s authentication data has unlocked.

Here is an example for the OIDC flow:

  1. The client application redirects the user agent to the auth server with a response_type of id_token.
  2. The user establishes identity with the auth server, i.e. logs in.
  3. The auth server redirects the user agent back to the client application with an id_token. The response looks something like this: https://yoursite/authz#token_type=bearer&state=some&id_token=some
  4. An attacker obtains that response, possibly via packet sniffing, client-server logs (e.g the web server that’s hosting your SPA), the browser’s developer tools, shoulder surfing, or some other means.
  5. It ends up that the client application serves the attacker and sends the response back to the attacker.

Nonce

OIDC spec defines nonce claim in the ID token.

From OIDC spec:
15.5.2. Nonce Implementation Notes

The nonce parameter value needs to include the per-session state and be unguessable to attackers. One method to achieve this for Web Server Clients is to store a cryptographically random value as an HttpOnly session cookie and use a cryptographic hash of the value as the nonce parameter. In that case, the nonce in the returned ID Token is compared to the hash of the session cookie to detect ID Token replay by third parties. A related method applicable to JavaScript Clients is to store the cryptographically random value in HTML5 local storage and use a cryptographic hash of this value.

To recap:

  • A cryptographic random value is in the session cookie(HttpOnly), the hash value of it is stored as a nonce parameter in the OIDC ID token.
  • The attacker can not run JavaScript to get the HttpOnly session cookie, so that can not get the clear text nonce or the value that is used to generate a nonce.
  • When the attacker gets authenticated from OIDC, the attacker couldn’t provide the correct cryptographic random value in session cookie
  • So when the client application received this ID token, the hash value does not match, so reject the request.

(My interpretation is that the attacker couldn’t send the correct clear text nonce cookie along with the request to the client application because the attacker does not know the clear text nonce.

  • HttpOnly cookie does not allow JavaScript(running from a browser) to access the cookie, another protection on data leakage)

About Cookies

when you make requests to the website you’re signed in to, your browser sends your cookie (could be a session id cookie or other cookies) back to the server. The server checks for your session using your session id or other cookies, then returns data for your request.

  • To secure cookies, add the Secure attribute to your cookies so that data is encrypted in transit.
document.cookie = 'my_cookie_1=false; Secure';

The Secure attribute doesn't actually encrypt any data in your cookie – it just ensures that the cookie can't be sent over an HTTP connection. Encrypt your cookie data at rest if the data is sensitive.

However, a bad actor could still possibly intercept and manipulate the cookie. To prevent this from happening, use the HttpOnly cookie:

document.cookie = 'my_cookie_2=abc; Secure; HttpOnly';

Cookies with HttpOnly can only be accessed by the server, and not by the browser's Document.cookie API.

References

https://openid.net/specs/openid-connect-core-1_0.html#NonceNotes

Final: OpenID Connect Core 1.0 incorporating errata set 1

Everything You Need to Know About Cookies for Web Development (freecodecamp.org)

“https://security.stackexchange.com/questions/147529/openid-connect-nonce-replay-attack

https://ashend.medium.com/openid-connect-session-management-d0c8e7dc252b

https://technospace.medium.com/managing-sessions-with-openid-connect-d3b6fb4f552b

https://hiranamarasinghe.medium.com/openid-connect-back-channel-logout-ef20fe8fe600

https://hiranamarasinghe.medium.com/open-id-connect-session-management-53b01ce75f9c

https://openid.net/specs/openid-connect-session-1_0.html

What is a replay attack and how can you prevent one? (comparitech.com)
https://learn.microsoft.com/en-us/azure/active-directory/develop/id-tokens

--

--

Cloud Journey

All blogs are strictly personal and do not reflect the views of my employer. https://github.com/Ronnie-personal