Skip to content

OIDC Claims Request — Requesting Specific User Attributes from the Provider

DodaTech Updated 2026-06-28 5 min read

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

  1. What is the difference between essential: true and essential: false?
  2. How do claims requested in id_token differ from those in userinfo?
  3. Can you request claims without the corresponding scope?
  4. What happens when a provider cannot fulfill an essential claim?
  5. How do you URL-encode a claims request parameter?

Answers

  1. 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

What is the claims request parameter?

A JSON object in the authentication request that specifies which claims to include in the ID token and UserInfo response.

Is the claims parameter required for OpenID Connect?

No. It is an optional feature that gives finer control over claim selection beyond basic scopes.

Can claims be requested without the openid scope?

No. The openid scope is always required for any OIDC request, including claims requests.

What does essential mean in a claims request?

Essential means the provider MUST return this claim. If unavailable, the authentication request fails.

Can I request claims in both id_token and userinfo?

Yes. The id_token object specifies claims for the ID token; the userinfo object specifies claims for the UserInfo response.

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