From auth-identity
Pick and implement the right OAuth 2.0 / OIDC flow by client type: Authorization Code + PKCE for SPA and native apps, confidential-client code flow for server-side apps, client-credentials for M2M. ID-token vs access-token vs refresh-token handling. Deprecated Implicit flow is never recommended.
How this skill is triggered — by the user, by Claude, or both
Slash command
/auth-identity:oauth-oidc-flow-designThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> **Invoked by:** any agent designing or reviewing an OAuth/OIDC authentication flow; `ravenclaude-core/security-reviewer` when reviewing auth-flow changes.
Invoked by: any agent designing or reviewing an OAuth/OIDC authentication flow;
ravenclaude-core/security-reviewerwhen reviewing auth-flow changes.When to invoke: new authentication integration; switching flows; adding an API or M2M service account; auditing an existing flow for security.
Output: documented flow selection rationale + client-type → flow mapping + token-handling guidance + anti-pattern flags.
This skill designs the OAuth/OIDC flow. Implementation details (setting up the Google Cloud OAuth client, Supabase provider configuration) are in the google-sso-setup skill. Session and token storage after the flow completes is in session-and-token-management. Data-row authorization is owned by data-platform/rls-policy-authoring.
| Client type | Correct flow | Never use |
|---|---|---|
| SPA (React, Next.js client-side) | Authorization Code + PKCE | Implicit |
| Native / mobile app | Authorization Code + PKCE | Implicit |
| Server-rendered web app (Next.js SSR, Express) | Authorization Code (confidential client, no PKCE required but PKCE still recommended) | Implicit |
| Backend API / BFF (machine-to-user, acting on behalf of a user) | Authorization Code (confidential client) | Implicit, Resource Owner Password |
| Machine-to-machine (service account, daemon, CI) | Client Credentials | Any user-facing flow |
| TV / CLI / device with no browser | Device Authorization Grant | Implicit |
The OAuth 2.0 Implicit flow (response_type=token) returns an access token directly in the URL fragment. It was designed for SPAs before PKCE existed. It is deprecated by OAuth 2.0 Security BCP (RFC 9700) and the OAuth 2.1 draft [unverified — verify current RFC numbers] because:
The best-practice use-authorization-code-pkce-never-implicit.md is an absolute rule in this plugin.
PKCE (Proof Key for Code Exchange) adds a code verifier/challenge that binds the browser that started the flow to the browser that completes it, defeating authorization code interception.
[Browser] [Auth Server (Google/Supabase)]
| |
|-- generate code_verifier (random 43-128 chars, high entropy)
|-- code_challenge = BASE64URL(SHA256(code_verifier))
| |
|-- GET /authorize? |
| response_type=code |
| client_id=... |
| redirect_uri=... |
| code_challenge=<hash> |
| code_challenge_method=S256 |
| scope=openid email profile |
| state=<random CSRF nonce> |
| |
| user authenticates + consents |
| |
|<-- redirect to redirect_uri?code=<code>&state=<nonce>
| |
|-- verify state matches CSRF nonce |
| |
|-- POST /token |
| grant_type=authorization_code |
| code=<code> |
| code_verifier=<original verifier> |
| client_id=... |
| redirect_uri=... |
| |
|<-- { access_token, id_token, refresh_token, expires_in }
The code_verifier is never sent to the authorization server during the first leg — only its hash. The token exchange proves the same party completed both legs.
Supabase Auth handles PKCE automatically when using @supabase/ssr. Do not disable it. [unverified — confirm PKCE is on by default in current Supabase Auth version]
For server-side apps that can keep a client_secret confidential (Express, Next.js API routes, Django, etc.). The client_secret is included in the token exchange, providing authentication of the client itself — in addition to PKCE if used.
client_secret never leaves the server.For service accounts, background jobs, CI pipelines, API-to-API calls with no human user in the loop.
[Service A] [Auth Server]
|-- POST /token |
| grant_type=client_credentials |
| client_id=<service-client-id> |
| client_secret=<secret> | ← in env var, never in code
| scope=<required scope> |
| |
|<-- { access_token, expires_in }
| Token | What it contains | Who validates it | Where to store |
|---|---|---|---|
ID token (OIDC id_token) | User identity claims (sub, email, name, picture). A signed JWT. | Server-side: verify signature + iss + aud + exp. Never trust unverified. | Decode claims server-side only; do not store in localStorage. |
| Access token | Authorization to call APIs. May be opaque or a JWT. Short-lived (seconds to minutes). | API server via introspection or JWT verification. | HttpOnly cookie or server-side session. Never localStorage. |
| Refresh token | Long-lived credential to get new access tokens without re-authenticating. | Auth server only. | Server-side session or HttpOnly cookie with SameSite=Strict. High-value target — rotate on use. |
Storage rule: never store any token in localStorage. The never-store-tokens-in-localstorage.md best-practice is an absolute rule. Use HttpOnly + Secure + SameSite cookies (managed automatically by Supabase SSR and most auth libraries).
Before trusting any claim in an OIDC id_token:
https://accounts.google.com/.well-known/openid-configuration → jwks_uri). [unverified — confirm Google's OIDC discovery URL]iss matches the expected issuer (e.g., https://accounts.google.com).aud matches your application's client_id.exp is in the future.iat is not too far in the past (clock-skew tolerance, typically ±5 minutes).nonce matches the value you sent in the authorization request.The validate-id-tokens-server-side.md best-practice is an absolute rule. Use a well-maintained library (google-auth-library, jose, jsonwebtoken with explicit algorithm pinning) — do not roll your own verification. Route to ravenclaude-core/security-reviewer before shipping.
refresh_token_already_used or invalid_refresh_token errors gracefully (redirect to login).Always include a random, unguessable state parameter in the authorization request. Verify it matches on return. Without it, an attacker can forge the callback and inject their authorization code into your user's session.
Supabase Auth handles state automatically. If rolling your own, generate a cryptographically random value, store it in a short-lived session cookie (HttpOnly), and validate on callback.
response_type=token) for any new implementation — deprecated, unsafeid_token or access_token in localStorage — see never-store-tokens-in-localstorage.mdid_token claims without server-side signature verification — see validate-id-tokens-server-side.mdclient_secret present in front-end code or a NEXT_PUBLIC_ env var — server-side onlystate parameter — opens CSRF attack vector../google-sso-setup/SKILL.md — provider setup (Supabase + Google Cloud config)../session-and-token-management/SKILL.md — what to do with tokens after the flow completes../../best-practices/use-authorization-code-pkce-never-implicit.md../../best-practices/never-store-tokens-in-localstorage.md../../best-practices/validate-id-tokens-server-side.md../../../ravenclaude-core/agents/security-reviewer.mdnpx claudepluginhub mcorbett51090/ravenclaude --plugin auth-identityGuides completion of development work by verifying tests, detecting environment, and presenting structured options for merge, PR, or cleanup.
Guides creation and editing of skills using test-driven development with pressure scenarios and subagents to verify agent compliance.
Dispatches multiple subagents concurrently for independent tasks without shared state. Use when facing 2+ unrelated failures or subsystems that can be investigated in parallel.