Skip to main content

Authorization Endpoint

The authorization endpoint starts the OAuth 2.0 Authorization Code flow. When a user clicks "Sign in with LumoAuth" in your application, you redirect them here. LumoAuth handles authentication and consent, then redirects back to your application with an authorization code that your backend exchanges for tokens at the Token Endpoint.

GET /orgs/{orgId}/api/v1/oauth/authorize

The Authorization Code flow is defined by RFC 6749 — the OAuth 2.0 Authorization Framework, the core specification that defines the authorize and token endpoints and the standard grant types.

How It Works

  1. User is shown a login form (or social login options).
  2. If MFA is enabled, they complete the second factor.
  3. User reviews and approves the permissions your app is requesting.
  4. LumoAuth redirects back to your app with an authorization code.
Why Use This Flow?

In the Authorization Code flow, the user's credentials are entered at LumoAuth and never reach your application. Your application only ever sees the authorization code, which it exchanges for tokens over a back-channel.

Request Parameters

ParameterRequiredDescription
client_idYesYour application's public identifier
redirect_uriYesURL where LumoAuth will send the authorization code. Must exactly match a registered URI.
response_typeYesMust be code for the Authorization Code flow
scopeNoSpace-separated list of permissions (e.g., openid profile email)
stateRecommendedRandom string to prevent CSRF attacks. Always verify this in your callback.
code_challengeRecommendedPKCE code challenge (SHA-256 hash of code_verifier, base64url encoded)
code_challenge_methodIf PKCES256 (recommended) or plain
nonceIf OIDCRandom string to prevent replay attacks. Returned in the ID token.
promptNologin forces re-authentication; create shows registration

PKCE is defined by RFC 7636 — Proof Key for Code Exchange: the client generates a random secret (the code verifier) and sends a hash of it when starting the authorization flow, then the real secret when exchanging the code. An attacker who intercepts the authorization code cannot redeem it without the verifier. PKCE is required for public clients (SPAs, mobile apps) and recommended for everyone.

Example Request

GET /orgs/acme-corp/api/v1/oauth/authorize?
response_type=code&
client_id=abc123def456&
redirect_uri=https://myapp.com/callback&
scope=openid%20profile%20email&
state=xyzSecureRandom123&
code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&
code_challenge_method=S256
HTTP/1.1
Host: app.lumoauth.dev

Successful Response

After the user authenticates and approves, LumoAuth redirects to your redirect_uri with the authorization code and state:

HTTP/1.1 302 Found
Location: https://myapp.com/callback?
code=SplxlOBeZQQYbYS6WxSbIA&
state=xyzSecureRandom123
Verify the State

Always compare the state parameter in the callback with the one you sent. If they don't match, the request may be a CSRF attack — reject it.

Error Response

If the user denies access or an error occurs, LumoAuth redirects with an error:

HTTP/1.1 302 Found
Location: https://myapp.com/callback?
error=access_denied&
error_description=The+user+denied+the+request&
state=xyzSecureRandom123
Error CodeDescription
invalid_requestMissing or invalid parameters
invalid_clientUnknown client_id or mismatched redirect_uri
access_deniedUser denied the authorization request
server_errorUnexpected server error

PKCE Implementation

A complete PKCE example in Python:

import secrets
import hashlib
import base64

# Step 1: Generate code_verifier (43-128 characters)
code_verifier = secrets.token_urlsafe(32)

# Step 2: Create code_challenge (SHA-256 hash, base64url encoded)
code_challenge = base64.urlsafe_b64encode(
hashlib.sha256(code_verifier.encode()).digest()
).decode().rstrip('=')

# Step 3: Build authorization URL
auth_url = (
f"https://app.lumoauth.dev/orgs/acme-corp/api/v1/oauth/authorize?"
f"response_type=code&"
f"client_id=YOUR_CLIENT_ID&"
f"redirect_uri=https://myapp.com/callback&"
f"scope=openid%20profile&"
f"state={secrets.token_urlsafe(16)}&"
f"code_challenge={code_challenge}&"
f"code_challenge_method=S256"
)

# Step 4: Store code_verifier in session (you'll need it later)
session['code_verifier'] = code_verifier

# Step 5: Redirect user to auth_url

Next Steps

After receiving the authorization code, exchange it for tokens at the Token Endpoint. See PKCE for a deeper dive and Security considerations for redirect URI and state validation.