OIDC Authentication Request — Building Authorization URLs for User Login
In this tutorial, you will learn about OIDC Authentication Request. We cover key concepts, practical examples, and best practices to help you master this topic.
The OIDC authentication request is the initial URL that redirects the user to the provider's login page, containing parameters that specify the client, requested permissions, and security values like state and nonce.
What You'll Learn
- All authentication request parameters and their purposes
- How state and nonce protect against CSRF and replay attacks
- Building and validating auth request URLs
Why It Matters
A malformed authentication request can fail silently, redirect to the wrong URL, or introduce security vulnerabilities. Understanding each parameter ensures a smooth, secure login flow for your users.
Real-World Use
When a user clicks "Sign In" on Doda Browser, the app builds an authentication request with a random state value (CSRF protection) and nonce (replay protection), encodes them in the redirect URL, and sends the user to the provider's login page.
sequenceDiagram
Browser->>App: Click Sign In
App->>App: Generate state + nonce
App->>Provider: Redirect with auth request
Provider->>User: Login + consent
Provider->>App: Redirect callback with code
App->>App: Verify state matches
App->>Provider: Exchange code for tokens
App->>App: Verify nonce in ID token
Building the Auth Request
import secrets
import urllib.parse
def build_auth_request(client_id, redirect_uri, authorization_endpoint,
scope="openid profile email", response_type="code"):
state = secrets.token_urlsafe(32)
nonce = secrets.token_urlsafe(16)
params = {
"client_id": client_id,
"response_type": response_type,
"redirect_uri": redirect_uri,
"scope": scope,
"state": state,
"nonce": nonce,
}
auth_url = f"{authorization_endpoint}?{urllib.parse.urlencode(params)}"
return auth_url, state, nonce
# Usage
auth_url, state, nonce = build_auth_request(
client_id="your-client-id",
redirect_uri="https://yourapp.com/callback",
authorization_endpoint="https://provider.com/auth"
)
print(f"Redirect user to: {auth_url}")
print(f"Store state={state} and nonce={nonce} for verification")
Handling the Callback
from flask import Flask, request, session
import requests
app = Flask(__name__)
PROVIDER_CONFIG = {
"token_endpoint": "https://provider.com/token",
"client_id": "your-client-id",
"client_secret": "your-client-secret",
}
@app.route("/callback")
def callback():
# Verify state parameter (CSRF protection)
returned_state = request.args.get("state")
if returned_state != session.get("oauth_state"):
return "Invalid state parameter", 400
session.pop("oauth_state", None)
# Exchange authorization code for tokens
code = request.args.get("code")
token_resp = requests.post(PROVIDER_CONFIG["token_endpoint"], data={
"code": code,
"client_id": PROVIDER_CONFIG["client_id"],
"client_secret": PROVIDER_CONFIG["client_secret"],
"redirect_uri": "https://yourapp.com/callback",
"grant_type": "authorization_code",
})
tokens = token_resp.json()
# Verify nonce in ID token
id_token = tokens["id_token"]
import jwt
claims = jwt.decode(id_token, options={"verify_signature": False})
if claims.get("nonce") != session.get("oauth_nonce"):
return "Invalid nonce", 400
session.pop("oauth_nonce", None)
return f"Authenticated as {claims['name']}"
Complete Auth Request with All Parameters
def build_complete_auth_request(
client_id, redirect_uri, authorization_endpoint,
scope="openid profile email",
response_type="code",
response_mode="query",
display="page",
prompt=None,
max_age=None,
ui_locales=None,
claims=None,
):
state = secrets.token_urlsafe(32)
nonce = secrets.token_urlsafe(16)
params = {
"client_id": client_id,
"response_type": response_type,
"redirect_uri": redirect_uri,
"scope": scope,
"state": state,
"nonce": nonce,
}
if response_mode:
params["response_mode"] = response_mode
if display:
params["display"] = display
if prompt:
params["prompt"] = prompt
if max_age:
params["max_age"] = str(max_age)
if ui_locales:
params["ui_locales"] = ui_locales
if claims:
import json
params["claims"] = json.dumps(claims)
auth_url = f"{authorization_endpoint}?{urllib.parse.urlencode(params)}"
return auth_url, state, nonce
Common Mistakes
1. Not Using a Random State Value
Without state, your app is vulnerable to CSRF Attacks. An attacker can intercept the callback and inject their own authorization code.
2. Not Validating State in the Callback
Generating state but not checking it on return provides no protection. Always compare the returned state with the stored value.
3. Reusing Nonce Values
A reused nonce allows replay attacks. Generate a unique nonce for every authentication request.
4. Not Encoding Redirect URI Correctly
The redirect URI must exactly match what is registered with the provider. Mismatched URIs cause "redirect_uri_mismatch" errors.
5. Missing Scope Parameter
Without the openid scope, the request is treated as OAuth2 and no ID token is returned.
Practice Questions
- What is the purpose of the
stateparameter in an OIDC auth request? - How does the
nonceparameter differ fromstate? - What happens if the
redirect_uridoes not match the registered URI? - What does the
promptparameter control? - Why should
stateandnoncebe cryptographically random?
Answers:
stateprevents CSRF attacks by verifying that the response corresponds to the request initiated by the same user session.stateprotects against CSRF (session-level).nonceprotects against replay attacks (token-level) and is embedded in the ID token.- The provider returns a
redirect_uri_mismatcherror. The URI must match exactly, including protocol, domain, port, and path. promptcontrols whether the provider shows login, consent, or select_account screens. Values:none,login,consent,select_account.- Predictable state/nonce values allow attackers to forge auth requests or replay captured tokens.
Challenge: Build a complete Flask OIDC login flow with proper state and nonce handling, token exchange, and session creation. Include error handling for all failure modes.
FAQ
Mini Project
Create a Flask app that implements a complete OIDC authentication flow. Include: auth URL generation with state and nonce, callback handler with state verification, token exchange, nonce verification, and user session creation. Test with a real OIDC provider.
What's Next
Continue with OIDC Response Types to understand how tokens are delivered, or explore OIDC Flows for different authentication grant types.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro