c_hash (Code Hash) Claim in an ID Token
c_hash is the base64url encoded left half of a hash of the authorization code. It appears in hybrid flows, where the ID token arrives in the front channel next to a code that could otherwise be substituted.
At a glance
- Claim
- c_hash (Code hash value)
- Defined in
- OpenID Connect Core 1.0 section 3.3.2.11
- Value type
- Base64url encoded string, no padding
- Required
- Required when an ID token is issued from the authorization endpoint with a code, which means the code id_token and code id_token token response types.
- How it is computed
- Hash the ASCII octets of the code with the hash of the ID token's alg, keep the left half, base64url encode it.
- In the decoder
- Shown under Custom claims as a raw string. Checking it needs the authorization code, which the decoder never sees.
In detail
The computation matches at_hash exactly, only the input differs: the ASCII octets of the authorization code rather than the access token. Same rule for choosing the hash from the ID token's alg, same truncation to the left half of the digest, same base64url encoding without padding. A relying party that already implements one gets the other for a couple of lines.
Hybrid flows are the reason it exists. In the code id_token response type the browser receives the ID token and the code together in the front channel, where both are exposed to whatever else is running there. Without c_hash an attacker could keep the honest ID token and swap in a code obtained elsewhere, so that the relying party ends up holding tokens for a different account than the one it just authenticated.
The relying party therefore recomputes the hash from the code it received before redeeming it. If the values differ the response was tampered with and the exchange must not happen. This is one of the few checks that has to run early, since the point is to catch the substitution before the code is spent at the token endpoint.
Financial grade profiles add a matching s_hash claim over the state parameter for the same reason, so a deployment carrying c_hash may carry that as well. The decoder treats both the same way: they appear under Custom claims with their raw values, since only the seven RFC 7519 claims get an explanation, and neither can be checked without the value that was hashed.
Examples
{
"iss": "https://auth.example.com",
"aud": "web-dashboard",
"nonce": "n-0S6_WzA2Mj",
"c_hash": "LDktKdoQak3Pk0cnXxCltA",
"at_hash": "xsZZrUssMXjLxaJZFT9NDA"
}Sample values only. Both hashes depend on the exact code and access token that came back with this response.
Things that catch people out
- Redeeming the code before checking c_hash. The check exists to stop the exchange happening, so doing it afterwards misses the point.
- Expecting c_hash in a plain authorization code flow. It is only required when the ID token comes from the authorization endpoint alongside the code.
- Hashing a URL decoded or re-encoded code. Hash the exact ASCII octets of the code string as received.
Try it: JWT Decoder
Paste a token to decode the header and payload, read the claims and expiry, and verify the signature in your browser. Nothing is uploaded.
JWT Decoder
LOCAL · Browser-OnlyDecode and inspect JSON Web Tokens without sending them to a server
Related JWT claims and algorithms
All jwt claims and algorithms →at_hash (Access Token Hash) Claim in an ID Token
The at_hash claim ties an ID token to the access token issued with it. How the left half hash is computed, when it must be checked, and decoder limits.
nonce Claim in an OpenID Connect ID Token
The nonce claim binds an ID token to one authentication request. How the value round trips, why it must be compared, and how the decoder shows it.
azp (Authorized Party) Claim in a JWT
The azp claim names the client an ID token was issued to. When OpenID Connect requires it, how it differs from aud, and what the decoder shows.
sid (Session ID) Claim in a JWT
The sid claim identifies the authentication session at the provider. How single logout uses it, why it is not the user identifier, and decoder behaviour.
scope Claim in a JWT Access Token
The scope claim carries the granted OAuth scopes inside an access token. Why it is one space delimited string, how to check it, and what the decoder shows.
client_id Claim in a JWT Access Token
The client_id claim names the OAuth client an access token was issued to. How it differs from sub and azp, where it is required, and decoder behaviour.
Tools for this
- JWT Decoder Free online JWT decoder - decode and inspect JSON Web Tokens without sending them to a server
- Hash Generator Free online hash generator - generate MD5, SHA-1, SHA-256 hashes from any input text