Skip to content

OIDC Response Types — How Tokens Are Delivered in Authentication Responses

DodaTech Updated 2026-06-28 5 min read

In this tutorial, you will learn about OIDC Response Types. We cover key concepts, practical examples, and best practices to help you master this topic.

Response types in OIDC determine how authentication results are returned to the client, whether through an authorization code exchanged server-side, tokens delivered directly in the URL fragment, or a hybrid of both approaches.

What You'll Learn

  • The three main OIDC response types: code, id_token, and token
  • Hybrid response types combining multiple delivery methods
  • Security considerations for each response type

Why It Matters

Choosing the wrong response type exposes tokens to the browser URL, enables interception attacks, or requires unnecessary server-side complexity. Each response type has specific security properties and use cases.

Real-World Use

Doda Browser uses response_type=code for all web logins. The authorization code is exchanged server-side for tokens, keeping ID tokens and access tokens out of the browser URL. For native mobile apps, it uses response_type=code with PKCE for additional security.

flowchart LR
    subgraph "Authorization Code Flow"
        Client1["Client"] -->|"code"| Provider["Provider"]
        Provider -->|"code"| Client1
        Client1 -->|"code + secret"| TokenEP["Token Endpoint"]
        TokenEP -->|"ID + Access Token"| Client1
    end
    subgraph "Implicit Flow"
        Client2["Client"] -->|"id_token + access_token"| Provider2["Provider"]
        Provider2 -->|"fragment"| Client2
    end
    style TokenEP fill:#dbeafe,stroke:#2563eb

Authorization Code Flow (response_type=code)

The client receives an authorization code, which is exchanged server-side for tokens:

import requests

# Step 1: Redirect user to authorization endpoint
auth_params = {
    "client_id": "my-app",
    "response_type": "code",
    "redirect_uri": "https://app.com/callback",
    "scope": "openid profile email",
    "state": "random-state",
}
# User redirected to provider...

# Step 2: Exchange code for tokens (server-side)
token_resp = requests.post("https://provider.com/token", data={
    "code": "authorization-code-from-callback",
    "client_id": "my-app",
    "client_secret": "my-secret",
    "redirect_uri": "https://app.com/callback",
    "grant_type": "authorization_code",
})
tokens = token_resp.json()
print(f"ID Token: {tokens.get('id_token')[:50]}...")
print(f"Access Token: {tokens.get('access_token')[:50]}...")

Implicit Flow (response_type=id_token token)

Tokens are returned directly in the URL fragment. No server-side exchange needed:

Redirect URL:
https://app.com/callback#id_token=eyJhbGciOiJSUzI1...&access_token=ya29.a0AfH6S...&state=random-state&expires_in=3600&token_type=Bearer

The browser reads tokens from the fragment. This flow is less secure because tokens are exposed in the browser URL.

Hybrid Flow (response_type=code id_token)

Combines both approaches: the client receives an authorization code and an ID token simultaneously:

from flask import Flask, request
import requests
import jwt

app = Flask(__name__)

@app.route("/callback")
def callback():
    # Hybrid flow returns both code and id_token
    code = request.args.get("code")
    id_token_from_fragment = request.args.get("id_token")

    # Immediately verify ID token for user identity
    claims = jwt.decode(id_token_from_fragment, options={"verify_signature": False})
    print(f"User identified: {claims.get('name')}")

    # Exchange code for additional tokens
    tokens = requests.post("https://provider.com/token", data={
        "code": code,
        "client_id": "my-app",
        "client_secret": "my-secret",
        "redirect_uri": "https://app.com/callback",
        "grant_type": "authorization_code",
    }).json()

    access_token = tokens["access_token"]
    return f"Hello {claims['name']}! Access token: {access_token[:30]}..."

Response Type Comparison

Type Tokens Returned Server Exchange Needed Token Exposure
code Authorization code Yes Minimal
id_token ID token only No URL fragment
token id_token ID + Access token No URL fragment
code id_token Code + ID token Partial URL fragment
code token Code + Access token Partial URL fragment
code id_token token Code + ID + Access token Partial URL fragment

PKCE with Authorization Code Flow

For public clients (SPA, mobile), add PKCE for protection:

import hashlib
import secrets
import base64

def generate_pkce_pair():
    code_verifier = secrets.token_urlsafe(64)
    code_challenge = base64.urlsafe_b64encode(
        hashlib.sha256(code_verifier.encode()).digest()
    ).rstrip(b"=").decode()
    return code_verifier, code_challenge

# In auth request
code_verifier, code_challenge = generate_pkce_pair()
auth_params = {
    "response_type": "code",
    "code_challenge": code_challenge,
    "code_challenge_method": "S256",
    # ... other params
}

# In token exchange
token_resp = requests.post("https://provider.com/token", data={
    "code": authorization_code,
    "client_id": "my-app",
    "code_verifier": code_verifier,
    "grant_type": "authorization_code",
})

Common Mistakes

1. Using Implicit Flow in SPAs

Implicit flow exposes tokens in the URL. Use authorization code flow with PKCE for SPAs. Most providers have deprecated implicit flow.

2. Storing Tokens from URL Fragments in Logs

URL fragments may be logged by web servers, exposing tokens. Filter fragment data from server logs.

3. Not Validating at_hash in Hybrid Flow

The at_hash claim in the ID token binds it to the access token. Verify it matches to prevent token swapping.

4. Exposing Client Secret in Implicit Flow

Implicit flow cannot use client secrets because the secret would be exposed in the browser. Use PKCE instead.

5. Mixing Response Types Without Understanding

Not all providers support all hybrid types. Check response_types_supported in the discovery document.

Practice Questions

  1. What is the difference between response_type=code and response_type=id_token token?
  2. Why is the authorization code flow more secure than implicit flow?
  3. What is PKCE and why is it important for public clients?
  4. What does hybrid flow (code id_token) give you?
  5. How does at_hash protect hybrid flow tokens?

Answers:

  1. code returns an authorization code exchanged server-side for tokens. id_token token returns tokens directly in the URL fragment.
  2. The code flow keeps tokens off the browser URL. Codes are single-use and exchanged server-side with a client secret.
  3. PKCE (Proof Key for Code Exchange) prevents authorization code interception attacks by binding the code to a cryptographic verifier.
  4. Hybrid flow provides immediate user identity (ID token) while also delivering a code for server-side token exchange.
  5. at_hash is a hash of the access token embedded in the ID token, proving they belong together and preventing token substitution.

Challenge: Implement both authorization code flow (with PKCE) and implicit flow for the same OIDC provider. Compare the security properties and explain why code + PKCE is recommended.

FAQ

Is implicit flow deprecated?

: The OAuth2 Security BCP recommends against implicit flow. Authorization code with PKCE is the recommended replacement.

What response type should a mobile app use?

: response_type=code with PKCE. Mobile apps are public clients and cannot securely store a client secret.

Can I use `response_type=none`?

: Yes. It returns no tokens and is used for logout or checking if the user is logged in without issuing tokens.

What is `response_mode` and how does it relate to response types?

: response_mode specifies how tokens are delivered: query (URL query), fragment (URL hash), or form_post (HTTP POST).

Does the provider always return the requested response type?

: Only if it is supported. Check response_types_supported in the provider's discovery document.

Mini Project

Create three Python scripts demonstrating each OIDC flow: authorization code flow with PKCE, implicit flow (handling fragment tokens), and hybrid flow (processing both code and ID token). Document the security differences.

What's Next

Continue with OIDC Flows Deep Dive to explore the authorization code, implicit, and hybrid flows in detail, or work on the OIDC Implementation Project.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro