Validating an OpenID Connect ID Token
On this page
About ID Token Validation
This article describes how to validate an OpenID Connect ID Token. What each part of the token means and how to use them after user authentication.
The ID Token is a JWT with specified contents, defined by the OpenID Foundation in the OpenID Connect Core Specification. The ID token provides proof of the authentication event to OpenID Connect clients. It contains information about how and when the user authenticated. Clients can also use ID Tokens to receive additional attributes about the user identity.
The ID Token JWT
The ID Token is an encoded and signed JSON Web Token (JWT). The JWT format is specified in RFC7519 . A JSON Web Token is a compact and URL-safe way of passing a JSON message between two parties.
The ID token contains claims issued by the OpenID Connect Provider (the Curity Identity Server). The ID Token is always a JWT. It cannot be issued as an opaque reference token.
The ID token consists of three main parts:
header
- Metadata about the token and its cryptographic algorithmpayload
- Claims about the issuer, the user and user authorizationsignature
- For verification of the integrity of the token
The parts are separated with a .
period in the encoded token:
Example:
eyJraWQiOiItMzgwNzQ4MTIiLCJ4NXQiOiJNUi1wR1RhODY2UmRaTGpONlZ3cmZheTkwN2ciLCJhbGciOiJSUzI1NiJ9.eyJhdF9oYXNoIjoiQ2djcDVvaWtzdDM4M2NBYl9KNU1WUSIsImRlbGVnYXRpb25faWQiOiI4MDkxZDEzMi02OGRkLTQ2YzMtYWRiZC0xYzgzNjQzYzRhNTciLCJhY3IiOiJ1cm46c2U6Y3VyaXR5OmF1dGhlbnRpY2F0aW9uOmh0bWwtZm9ybTpodG1sU3FsIiwic19oYXNoIjoiYXFpRFYxQ3k2U0NzZmEyQXlOcjVfUSIsImF6cCI6ImNsaWVudC1vbmUiLCJhdXRoX3RpbWUiOjE1NTA4MzMxNDgsIm5vbmNlIjoiMTU1MDgzMzExODA5Ni1IVm0iLCJleHAiOjE1NTA4MzY4MDcsIm5iZiI6MTU1MDgzMzIwNywianRpIjoiZTc1ZmQ0ZTctNjVjNC00ZmVlLWJjYjYtZGUxZjI5OTYwMTViIiwiaXNzIjoiaHR0cHM6Ly9leGFtcGxlLmN1cml0eS5pbyIsImF1ZCI6ImNsaWVudC1vbmUiLCJzdWIiOiJqb2huZG9lIiwiaWF0IjoxNTUwODMzMjA3LCJwdXJwb3NlIjoiaWQifQ.kKq2h2x20K-eXtoAeTFsjOIFzmfTjR8zP5F48qTQAkAK9qLKJCQkJ9UkAmHUw9BVgfb2zxLiRG6e5ACTpmxR_Mqv4mFeGyBR1faLJTXwdmiuJqqBcCKWS48KmhE-7XkxoF9nuiU_aaQArVn-Cx3qI2pQ945qUcXa47J2vn0xxGpm82VLQNfCsttT4M7HU-SjvTHOqS439bKl4gIcg-MIxmog08J5GdQpmyt7p2-cGvwd4iQVcd5t6sL0hcw5Q36sLSRnms4e8F9xWLZS2cD6ppdv4h8nr9whQB5NtIbw10f8rgy6o6vODu91JoxrAodTyu6QlVtN6uugicAR4OWs5w
OAuth Tools
You can use Curity's OAuth Tools to decode and analyze JWTs to try them out.
Decode the ID Token
To decode the token, you need to do a base64url decode
of each part. The decoded parts will be represented as JSON content data. Split the token on the .
period.
Header
The header contains metadata, such as and the hash algorithm used for the token contents, and (somewhat redundantly for our purposes) the type of token.
Example:
{"kid": "-38074812","x5t": "MR-pGTa866RdZLjN6Vwrfay907g","alg": "RS256"}
The header should be used to figure out what key to use when validating the token. There are a few options but the most common ones are:
kid : The key id. The key is found on the Json Web Key Set (JWKS) endpoint of the issuer.
x5t or x5t#256 : The fingerprint of the certificate to use hashed with SHA1 or SHA256.
alg : The algorithm used when signing the token. This should be a strong enough algorithm. Do not rely on this solely. Libraries should block algorithms such as none to prevent attacks.
x5t
is commonly used when the certificate is pre-distributed to the clients, and kid
when JWKS is used.
For more information, see the Registered Header Parameter Names section of RFC7515 - JSON Web Signature.
Payload
The Payload contains the claims for use by the client. When decoding the first thing to look for is the iss
issuer field. It shows who issued the token and must be an HTTPS url. This is important for the following reasons:
- Only trust tokens from known issuers
- Use the issuer to find the JWKS endpoint via the OpenID Connect Metadata
Example:
{"at_hash": "Cgcp5oikst383cAb_J5MVQ","delegation_id": "8091d132-68dd-46c3-adbd-1c83643c4a57","acr": "urn:se:curity:authentication:html-form:htmlSql","s_hash": "aqiDV1Cy6SCsfa2AyNr5_Q","azp": "client-one","auth_time": 1550833148,"nonce": "1550833118096-HVm","exp": 1550836807,"nbf": 1550833207,"jti": "e75fd4e7-65c4-4fee-bcb6-de1f2996015b","iss": "https://example.curity.io","aud": "client-one","sub": "johndoe","iat": 1550833207,"purpose": "id"}
Signature
The last part of the ID Token is the signature, which you use to to verify that the token was issued by the trusted issuer and not tampered with in route.
kKq2h2x20K-eXtoAeTFsjOIFzmfTjR8zP5F48qTQAkAK9qLKJCQkJ9UkAmHUw9BVgfb2zxLiRG6e5ACTpmxR_Mqv4mFeGyBR1faLJTXwdmiuJqqBcCKWS48KmhE-7XkxoF9nuiU_aaQArVn-Cx3qI2pQ945qUcXa47J2vn0xxGpm82VLQNfCsttT4M7HU-SjvTHOqS439bKl4gIcg-MIxmog08J5GdQpmyt7p2-cGvwd4iQVcd5t6sL0hcw5Q36sLSRnms4e8F9xWLZS2cD6ppdv4h8nr9whQB5NtIbw10f8rgy6o6vODu91JoxrAodTyu6QlVtN6uugicAR4OWs5w
Validate the ID Token
After initial decoding the token can be validated.
Signature
The signature is generated using the hashing algorithm from the token header.
To verify the signature, you must:
- Check the signing algorithm
- Verify signature with a public key
Check Algorithm
The alg
value for the signature should be of the expected type. (Whitelist the types your organization allows)
Verify signature
To verify the signature you should:
- Retrieve the public key by using the
x5t
orkid
parameter. - Break off the signature from the message leaving the
header.payload
encoded - Convert the header+payload segment to an ASCII array
- Base64Url decode the signature
- Use the decoded signature to validate the header+payload ASCII byte array
Verifying Standard Claims
Once the token has been received and decoded, you can validate the claims it contains, to make sure that they match the expected values:
Claim | Description | Comment |
---|---|---|
acr | Authentication method used | Should match the acr_values request parameter (if it was sent in the request). |
iss | Issuer | Identifier for the creator of the token. Must be a plain https:// URL. |
sub | Subject | Identifier for the authenticated user. |
aud | Audience | Expected recipient(s). Must contain some identifier for client, for example the Client ID or domain. |
iat | Issued At | When the ID Token was issued. |
auth_time | Authentication Time | When the user last was logged in without SSO. |
jti | Token identifier | A unique identifier for this token. Can be used to prevent replays |
nonce | Nonce | If the client passed in a nonce when requesting the token it must be present here |
ID Tokens vs Access Tokens
ID tokens and access tokens have different audiences. The ID token provides proof of the authentication event, to inform the client how and when the user authenticated. The ID token can also provide other identity values to the client. ID tokens are private to the client and should never be sent to APIs.
Access tokens are also received by clients, who treat them as opaque strings and send them as message credentials when calling APIs. Access tokens are received by APIs in a JWT format. They contain secure values used for authorization, and are validated in a similar way to ID tokens. Access tokens include scopes and have short lifetimes, unlike ID tokens.
For more information about JWTs, and how to overcome potential risks when working with them, see the JWT Security Best Practices article.
Jacob Ideskog
Identity Specialist and CTO at Curity
Join our Newsletter
Get the latest on identity management, API Security and authentication straight to your inbox.
Start Free Trial
Try the Curity Identity Server for Free. Get up and running in 10 minutes.
Start Free Trial