OIDC Claims Request — Requesting Specific User Attributes from the Provider
In this tutorial, you will learn about OIDC Claims Request. We cover key concepts, practical examples, and best practices to help you master this topic.
The claims request parameter in Openid Connect allows your application to request specific user attributes from the provider, giving fine-grained control over which identity data is returned in the ID token and UserInfo response.
What You'll Learn
- What the claims request parameter is and how it works
- How to request essential vs voluntary claims
- How to control which claims appear in the ID token vs UserInfo endpoint
Why It Matters
Without claims requests, your application receives a fixed set of claims based on scopes. If you need a rarely-used claim like phone_number, you either request the broad phone scope or miss the data. The claims parameter gives you precise control, reducing payload size and respecting user privacy by requesting only what you need.
Real-World Use
Doda Browser needs only email and name for authentication but also requires phone_number for SMS-based two-factor authentication. Instead of requesting the broad profile scope, Doda uses a claims request to get exactly these three claims, minimizing data transfer and user consent screens.
flowchart LR
A["Your App"] -->|"Auth Request\n+ claims parameter"| B["OIDC Provider"]
B -->|"ID Token\n(essential claims only)"| A
B -->|"UserInfo Response\n(optional claims)"| A
style A fill:#dbeafe,stroke:#2563eb
style B fill:#fef3c7,stroke:#d97706
Claims Request Format
The claims request is a JSON object in the authentication request that specifies which claims to include in the ID token and which to fetch from the UserInfo endpoint:
{
"id_token": {
"email": {"essential": true},
"email_verified": {"essential": true}
},
"userinfo": {
"phone_number": {"essential": false},
"phone_number_verified": {"essential": false}
}
}
Essential claims with "essential": true must be provided by the provider. If the provider cannot supply them, the authentication request fails.
Implementing Claims Request
import urllib.parse
import secrets
def build_oidc_url(client_id, redirect_uri, claims_request):
params = {
"client_id": client_id,
"redirect_uri": redirect_uri,
"response_type": "code",
"scope": "openid email",
"state": secrets.token_urlsafe(16),
"nonce": secrets.token_urlsafe(16),
"claims": json.dumps(claims_request)
}
auth_url = "https://accounts.example.com/authorize?" + urllib.parse.urlencode(params)
return auth_url
claims_request = {
"id_token": {
"email": {"essential": true},
"email_verified": {"essential": true}
},
"userinfo": {
"phone_number": {"essential": false},
"phone_number_verified": {"essential": false},
"address": {"essential": false}
}
}
url = build_oidc_url(
client_id="doda-browser-123",
redirect_uri="https://doda.example.com/callback",
claims_request=claims_request
)
print(f"Redirect user to: {url}")
Processing Claims from UserInfo
After receiving the authorization code and exchanging it for tokens, fetch the UserInfo endpoint to get the requested claims:
import requests
def fetch_userinfo(access_token, userinfo_endpoint):
response = requests.get(
userinfo_endpoint,
headers={"Authorization": f"Bearer {access_token}"}
)
return response.json()
# After token exchange
access_token = "ya29.a0AfH6S..."
userinfo_url = "https://accounts.example.com/userinfo"
claims = fetch_userinfo(access_token, userinfo_url)
print(f"Email: {claims.get('email')}")
print(f"Email verified: {claims.get('email_verified')}")
print(f"Phone: {claims.get('phone_number', 'Not provided')}")
Expected output:
Email: user@example.com
Email verified: True
Phone: +1-555-0123
Volatile Claims
You can mark claims as volatile to indicate the value might change frequently, preventing the provider from Caching stale data:
{
"id_token": {
"last_login": null
},
"userinfo": {
"last_ip_address": null
}
}
When a claim value is set to null (not an object), the request makes no claim about essentiality but simply requests the claim if available.
Common Mistakes
1. Confusing Claims with Scopes
Scopes like profile bundle multiple claims. The claims parameter requests individual claims. You can use both together.
2. Marking Too Many Claims as Essential
If you mark non-critical claims as essential: true, the authentication flow fails when the provider cannot supply them. Only mark truly required claims as essential.
3. Forgetting Scope Requirements
Some claims require specific scopes. For example, address claims require the profile scope even when requested via the claims parameter.
4. Not Handling Missing Claims
Even with essential: false, always provide fallback behavior when a claim is missing. Never assume all requested claims will be returned.
5. Sending Invalid JSON
The claims parameter must be valid JSON. URL-encode it properly. Use urllib.parse.urlencode or equivalent to avoid encoding errors.
Practice Questions
- What is the difference between
essential: trueandessential: false? - How do claims requested in
id_tokendiffer from those inuserinfo? - Can you request claims without the corresponding scope?
- What happens when a provider cannot fulfill an essential claim?
- How do you URL-encode a claims request parameter?
Answers
- Essential claims must be provided or the request fails; voluntary claims are returned if available. 2. ID token claims are embedded in the token itself; UserInfo claims are fetched via API. 3. Some claims require specific scopes even when using the claims parameter. 4. The authentication request fails with an error. 5. Use
urllib.parse.urlencode()or equivalent library function.
Challenge
Build a claims request Builder that accepts a list of desired claims, automatically categorizes them as essential or voluntary based on a configuration file, generates the proper JSON, and validates that required scopes are included.
FAQ
Mini Project
Build a Flask endpoint that accepts a claims request JSON, validates it against the provider's supported claims list (from the discovery URL), builds the correct authorization URL, and returns a sample UserInfo response with mock data for testing.
What's Next
- Learn about claims distribution mechanisms for cross-domain claims
- Explore pairwise identifiers for privacy-preserving subject identification
- Continue to dynamic client registration for automatic provider onboarding
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro