Skip to content

OIDC Hybrid Flow — Combining ID Token and Access Token in One Request

DodaTech Updated 2026-06-28 5 min read

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

The OIDC hybrid flow combines aspects of the authorization code and implicit flows by returning an ID token (and optionally an access token) directly from the authorization endpoint alongside the authorization code.

What You'll Learn

  • How the hybrid flow works and its three response type variants
  • When to use the hybrid flow vs authorization code flow
  • Security considerations specific to the hybrid flow

Why It Matters

In the standard authorization code flow, you must exchange the code for tokens before seeing any user identity. The hybrid flow provides an ID token immediately, allowing your app to display the user's name or avatar during the token exchange, improving perceived performance.

Real-World Use

Doda Browser uses the hybrid flow with response_type=code id_token during login. The ID token arrives directly in the front channel, so the browser can immediately greet the user by name while the backend exchanges the authorization code for a refresh token in the background.

sequenceDiagram
    participant Browser
    participant OIDC as OIDC Provider
    participant Backend

    Browser->>OIDC: Auth Request (response_type=code id_token)
    OIDC-->>Browser: ID Token + Authorization Code
    Browser->>Browser: Verify ID Token (immediate)
    Browser->>Backend: Send Authorization Code
    Backend->>OIDC: Code + Secret -> Tokens
    OIDC-->>Backend: Access + Refresh Token
    Backend-->>Browser: Session Established

Hybrid Flow Response Types

The hybrid flow has three variants based on which tokens are returned from the authorization endpoint:

# response_type=code id_token
# Returns: Authorization Code + ID Token
params_code_id_token = {
    "response_type": "code id_token",
    "client_id": "doda-browser",
    "redirect_uri": "https://doda.example.com/callback",
    "scope": "openid profile email",
    "state": "abc123",
    "nonce": "xyz789"
}

# response_type=code token
# Returns: Authorization Code + Access Token
params_code_token = {
    "response_type": "code token",
    "client_id": "doda-browser",
    "redirect_uri": "https://doda.example.com/callback",
    "scope": "openid profile email",
    "state": "abc123",
    "nonce": "xyz789"
}

# response_type=code id_token token
# Returns: Authorization Code + ID Token + Access Token
params_full = {
    "response_type": "code id_token token",
    "client_id": "doda-browser",
    "redirect_uri": "https://doda.example.com/callback",
    "scope": "openid profile email",
    "state": "abc123",
    "nonce": "xyz789"
}

Handling the Hybrid Flow Callback

// Client-side handling of hybrid flow callback
function handleHybridFlowCallback() {
  const urlParams = new URLSearchParams(window.location.hash.substring(1));
  const idToken = urlParams.get('id_token');
  const accessToken = urlParams.get('access_token');
  const code = urlParams.get('code');
  const state = urlParams.get('state');

  // Verify state matches
  const storedState = sessionStorage.getItem('oidc_state');
  if (state !== storedState) {
    console.error('State mismatch');
    return;
  }

  // Decode ID token (client-side validation only)
  const payload = JSON.parse(atob(idToken.split('.')[1]));
  console.log('User:', payload.name);

  // Send code to backend for token exchange
  fetch('/api/auth/exchange', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ code, state })
  }).then(res => res.json()).then(data => {
    console.log('Session established:', data.sessionId);
  });
}

Server-Side Token Exchange

from flask import Flask, request, session
import requests

app = Flask(__name__)

@app.route('/api/auth/exchange', methods=['POST'])
def exchange_code():
    code = request.json.get('code')
    token_response = requests.post(
        "https://accounts.example.com/token",
        data={
            "grant_type": "authorization_code",
            "code": code,
            "redirect_uri": "https://doda.example.com/callback",
            "client_id": "doda-browser",
            "client_secret": "your-client-secret"
        }
    )
    tokens = token_response.json()
    session['access_token'] = tokens['access_token']
    session['refresh_token'] = tokens.get('refresh_token')
    return {"status": "ok", "sessionId": session.sid}

Common Mistakes

1. Trusting Client-Side ID Token Verification

The ID token returned in the fragment is visible to JavaScript. Verify it on the server side after token exchange for critical operations.

2. Using Hybrid Flow Without PKCE

The hybrid flow exposes tokens in the URL fragment. Use PKCE to prevent authorization code interception even though the code is also in the front channel.

3. Choosing the Wrong Response Type

response_type=code id_token token returns the most data but exposes the access token in the URL fragment. Use code id_token if you only need immediate identity.

4. Ignoring the Fragment Encoding

Tokens in the URL fragment are not sent to the server. Handle fragment Parsing on the client side and send the authorization code to the server programmatically.

5. Not Clearing the Fragment

After processing the callback, clear the URL fragment to prevent tokens from being visible in the browser history.

Practice Questions

  1. What three response types are available in the hybrid flow?
  2. What is the advantage of receiving an ID token immediately?
  3. Why should you still exchange the code on the server side?
  4. Does the hybrid flow support PKCE?
  5. What security risk is specific to the hybrid flow?

Answers

  1. code id_token, code token, code id_token token. 2. Immediate user identity display during token exchange. 3. To get a refresh token and verify identity server-side. 4. Yes, PKCE is recommended. 5. Tokens appear in the URL fragment, visible in browser history and JavaScript.

Challenge

Build a hybrid flow implementation that demonstrates all three response types and logs the timing difference between when the ID token is available (front channel) vs when the access token is available (back channel).

FAQ

What is the OIDC hybrid flow?

A flow that returns an ID token and/or access token from the authorization endpoint alongside the authorization code.

When should I use the hybrid flow?

When you need immediate user identity information before the backchannel token exchange completes.

Does the hybrid flow use the front channel or back channel?

The ID token comes via the front channel (URL fragment); the code exchange happens via the back channel (server-to-server).

Is the hybrid flow more secure than the implicit flow?

Yes, because it still uses a backchannel code exchange for obtaining refresh tokens.

Can I skip the backchannel exchange in the hybrid flow?

No. The authorization code must still be exchanged server-side for access and refresh tokens.

Mini Project

Build a single-page application demonstrating all three hybrid flow variants with a mock OIDC provider. Show the timing and payload differences between each variant, including fragment parsing, code exchange, and session establishment.

What's Next

  • Learn about OIDC session management for maintaining user sessions
  • Explore logout mechanisms including RP-initiated and OP-initiated logout
  • Continue to session logout and post-logout redirects

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro