ID Token Claims — Complete Reference for Standard and Custom OIDC Claims
In this tutorial, you will learn about ID Token Claims. We cover key concepts, practical examples, and best practices to help you master this topic.
ID token claims are key-value pairs in the JWT payload that convey verified information about the authenticated user, the authentication event, and the token itself, following the Openid Connect specification.
What You'll Learn
- All standard OIDC claims and their meanings
- How to use claims for user profiling and security
- Custom claims and provider-specific extensions
Why It Matters
Claims are the primary way your application learns about the user. Understanding each claim helps you build correct authorization logic, prevent security vulnerabilities, and handle provider-specific differences in user data.
Real-World Use
Doda Browser extracts the sub claim as the user's permanent ID, email for communication, email_verified to skip email confirmation, and picture for the avatar. The auth_time claim helps enforce re-authentication for sensitive operations.
flowchart LR
IDToken["ID Token Payload"] --> Required["Required Claims\niss, sub, aud, exp, iat"]
IDToken --> Recommended["Recommended Claims\nauth_time, nonce, at_hash, acr"]
IDToken --> Optional["Optional Claims\nname, email, picture, locale"]
Required --> Verify["Verification Logic"]
Recommended --> Security["Security Checks"]
Optional --> Profile["User Profile"]
style IDToken fill:#dbeafe,stroke:#2563eb
Required Claims
Every ID token must include these claims:
required_claims = {
"iss": "https://accounts.google.com", # Issuer identifier
"sub": "1234567890", # Subject (user ID)
"aud": "your-client-id", # Audience (your client ID)
"exp": 1719561600, # Expiration time
"iat": 1719558000, # Issued at time
}
Recommended Claims
recommended_claims = {
"auth_time": 1719558000, # When user authenticated (Unix timestamp)
"nonce": "abc123", # Anti-replay nonce from auth request
"at_hash": "Hx4Jz...", # Access token hash for binding
"acr": "urn:mace:incommon:iap:silver", # Authentication Context Reference
}
Optional Standard Claims
profile_claims = {
"name": "Alice Smith",
"given_name": "Alice",
"family_name": "Smith",
"middle_name": "Marie",
"nickname": "Ali",
"preferred_username": "alice_s",
"profile": "https://example.com/alice",
"picture": "https://example.com/avatar.jpg",
"website": "https://alice.com",
"email": "alice@example.com",
"email_verified": True,
"gender": "female",
"birthdate": "1990-01-01",
"zoneinfo": "America/New_York",
"locale": "en-US",
"phone_number": "+1-555-0100",
"phone_number_verified": True,
"address": {
"street_address": "123 Main St",
"locality": "Springfield",
"region": "IL",
"postal_code": "62701",
"country": "US"
},
"updated_at": 1719500000,
}
Extracting and Using Claims
def process_id_token_claims(claims):
user = {
"id": claims["sub"],
"provider": claims["iss"],
"email": claims.get("email"),
"email_verified": claims.get("email_verified", False),
"name": claims.get("name"),
"avatar_url": claims.get("picture"),
}
# Check if email is verified before allowing login
if user["email"] and not user["email_verified"]:
print(f"Warning: {user['email']} is not verified")
# Use auth_time for re-authentication policy
auth_time = claims.get("auth_time")
if auth_time:
from datetime import datetime, timezone
auth_datetime = datetime.fromtimestamp(auth_time, tz=timezone.utc)
hours_since_auth = (datetime.now(timezone.utc) - auth_datetime).total_seconds() / 3600
if hours_since_auth > 24:
print("Re-authentication required")
return None
return user
Provider-Specific Claims
Different providers add custom claims:
# Google-specific claims
google_claims = {
"hd": "example.com", # Hosted domain (Google Workspace)
}
# Microsoft-specific claims
microsoft_claims = {
"oid": "00000000-0000-0000-0000-000000000000", # Object ID
"tid": "tenant-id", # Tenant ID
"unique_name": "alice@example.com",
}
# Auth0-specific claims
auth0_claims = {
"https://dodatech.com/roles": ["admin", "user"],
}
Common Mistakes
1. Using email as the User Identifier
Emails change. The sub claim is the stable, permanent identifier. Always use sub for database keys.
2. Trusting email_verified Without Checking
A provider may return email_verified: false. Require verified emails for sensitive operations or skip email verification entirely.
3. Ignoring auth_time for Sensitive Operations
If a user authenticated 30 days ago, allow password changes without re-authentication? Use auth_time to enforce step-up authentication.
4. Relying on Claims That May Be Missing
Not all providers return name, picture, or locale. Always provide fallbacks or mark fields as unavailable.
5. Not Handling Claim Type Changes
Some providers change claim formats (e.g., email_verified from boolean to string). Validate claim types before use.
Practice Questions
- Why should you use
subinstead ofemailas the user identifier? - What is the purpose of
auth_timeand how can it be used? - What does
email_verifiedindicate and why is it important? - Why might some claims be missing from an ID token?
- How do provider-specific claims differ from standard claims?
Answers:
- The
subclaim never changes. Emails can change when a user updates their email at the provider. auth_timerecords when the user last authenticated. Use it to require re-authentication for sensitive operations like password changes.email_verifiedindicates the provider confirmed the user owns the email address. Use it to skip verification emails.- Claims depend on the scopes requested (
profile,email) and what the provider supports. Request specific scopes for desired claims. - Standard claims are defined by the OIDC spec and consistent across providers. Custom claims are provider-specific and may vary.
Challenge: Build a user profile consolidation function that accepts ID token claims from Google, Microsoft, and Auth0, and returns a normalized user object that works regardless of the provider.
FAQ
Mini Project
Create a Python function that validates and normalizes ID token claims from three different providers. Return a standardized user object with fields: id, provider, email, name, avatar, email_verified, and auth_time. Handle missing fields gracefully.
What's Next
Continue with UserInfo Endpoint to learn how to retrieve additional user data, or explore Discovery URL for provider configuration.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro