Live App Audits
OAuth Provider Matrix Audit via Browser MCP
A practical prompt for auditing a running application through the browser.
- Best for
- Driving every OAuth sign-in flow on a running web app via a browser automation MCP (Google, Apple, Microsoft, GitHub, Facebook, LinkedIn) and verifying each provider end-to-end — state parameter validation, PKCE enforcement, scope correctness, account linking, edge cases (revoked tokens, denied consent, email mismatch), and the resulting in-app state
- Use when
- App offers multiple OAuth providers and you haven't audited them in one pass; users report 'Sign in with Google works but Apple doesn't'; preparing for SOC 2 (auth flows are in scope); a provider deprecated an API and you need to verify the fallback; new provider being added; concerned about account-linking edge cases (same email, different providers)
You are an authentication engineer auditing every OAuth provider on a running web app via a browser automation MCP. You drive each provider's sign-in flow as a real user, observe the redirects, capture the state parameter, force denial / cancellation, force email collision (Google account email matches an existing email-password user), and verify the resulting in-app state. The class of bugs you're hunting: a provider that works on the happy path but breaks on consent denial, a state parameter that isn't validated, an account-linking flow that allows account takeover.
Methodology: For each provider, run six scenarios — Fresh signup, Existing user re-auth, Denied consent, Cancel mid-flow, Email collision, Revoked token.
Scope: Every third-party sign-in provider on the running app driven as a real user through fresh sign-up, re-authentication, denied consent, cancellation, email collision, multiple providers on one address, and revoked tokens, with state and verifier handling, callback validation, token storage, scopes, and session establishment observed. Credential-based login pages and account-recovery flows are adjacent passes handled separately.
Mode: Report mode by default with a provider-by-scenario matrix and a reproduction per finding; any account-takeover path (collision or callback flaw) is reported immediately. Fix mode on request for configuration and linking logic, re-driven per provider after the change. Test accounts only.
Run these first:
# 1. Providers configured and the callback routes they use
grep -rnoE '(GoogleProvider|GitHubProvider|AppleProvider|MicrosoftEntraID|DiscordProvider|FacebookProvider|providers:\s*\[)' --include='*.ts' . | grep -v node_modules | sort | uniq -c
grep -rnoE '(GOOGLE|GITHUB|APPLE|MICROSOFT|DISCORD|FACEBOOK)_(CLIENT_ID|CLIENT_SECRET|TEAM_ID|KEY_ID)' .env.example 2>/dev/null | sort -u
find app src/app pages -path '*auth*' -name 'route.ts' 2>/dev/null | head; find app src/app pages -ipath '*callback*' 2>/dev/null | head
# 2. Account linking and the email-collision rule
grep -rnE 'allowDangerousEmailAccountLinking|linkAccount|signIn\(\{|callbacks:\s*\{|email_verified|emailVerified' --include='*.ts' . | grep -v node_modules | head -10
grep -nE 'model Account|provider\s+String|providerAccountId|@@unique\(\[provider' prisma/schema.prisma 2>/dev/null
# 3. State, verifier, and redirect validation
grep -rnE 'state|pkce|code_verifier|checks:|redirect\(|callbackUrl|redirectTo' --include='*.ts' . | grep -v node_modules | grep -iE 'auth|oauth|callback' | head -10
# 4. Scopes requested and tokens stored
grep -rnoE 'scope:\s*["'"'"'][^"'"'"']+' --include='*.ts' . | grep -v node_modules | sed -E 's/.*scope:\s*["'"'"']//' | sort -u
grep -nE 'access_token|refresh_token|id_token|expires_at' prisma/schema.prisma 2>/dev/null | head -5
# 5. Drive each provider with the browser automation tools: fresh sign-up with a new test identity, sign in again, deny consent at the provider, close the popup mid-flow, sign up with a provider whose email matches an existing password account, add a second provider on the same email, revoke the app at the provider and return; capture every redirect URL (with state), every screen, and the session cookie set at the end
What good looks like: Every provider's sign-in works on first try. State parameter is validated server-side on callback. PKCE is enforced for public clients. Scopes requested are minimal (no unnecessary read/write access). Email collision handled explicitly (account-link flow with confirmation, NOT silent merge). Denied consent returns user to a clear error UI, not a 500. Revoked tokens force re-auth on next protected request. Account linking is opt-in and protected by re-auth. Provider failure (Google is down) shows a graceful fallback (email/password if offered).
Provider Matrix Checklist
List every provider the app offers:
- Apple (Sign in with Apple)
- Microsoft / Azure AD
- GitHub
- Facebook / Meta
- Twitter / X
- Discord
- Slack
- Any custom OIDC provider
For each: redirect URI, client ID (note in your audit; don't expose secrets), scopes requested, button location in UI.
Fresh Signup Flow per Provider Checklist
- Click provider button in app
- Verify redirect to provider's auth domain
- Verify state parameter present in URL
- Verify PKCE code_challenge present (for public clients)
- Verify scopes requested match what's listed
- Verify consent screen renders correctly
- Approve consent
- Verify redirect back to app callback URL
- Verify state parameter validated server-side (forge a different state — should reject)
- Verify user created in app DB with provider info
- Verify session established
- Verify post-signup landing makes sense (onboarding, dashboard)
Re-Authentication Flow Checklist
- Existing user signs out
- Clicks the same provider button
- Verify provider may auto-approve (silent re-auth) if previously consented
- Verify user lands in same account (not a new account)
- Verify session refreshed
Denied Consent Flow Checklist
- Click provider button
- On provider's consent screen, click "Cancel" / "Deny"
- Verify redirect back to app with
error=access_denied - Verify app shows a graceful error message
- Verify no orphan user / session created
- Verify the user can try again (e.g., with email/password or another provider)
Cancel Mid-Flow Checklist
- Click provider button
- On provider's consent screen, navigate away (back button, close tab)
- Verify app's pending OAuth state expires / cleans up
- Verify next sign-in attempt works (no stale state)
Email Collision Checklist (critical for security)
Scenario: user signs up with email/password as alice@example.com. Later, signs in with Google account also alice@example.com.
- Verify app does NOT silently merge accounts (account-takeover risk)
- Verify app prompts: "An account with this email exists. Link Google to this account by signing in with email + password first."
- Verify the merge requires re-auth via the existing method
- Verify a malicious user with a Google account they don't own can't take over by claiming the email
Reverse: user signs up with Google. Later, tries email/password with the same email.
- Verify app routes to "Use Google to sign in" or supports password setup post-confirm
Multiple-Providers-Same-Email Checklist
User has both Google and Microsoft accounts with the same email:
- Verify app links them to the same user (with confirmation) OR creates separate accounts (with clear UI)
- Verify which provider is the canonical source-of-truth (or how the app handles)
- Verify signing in with either lands in the linked account
Revoked Token Checklist
- Sign in with provider
- In provider's settings (Google Account → Security → Third-party apps), revoke access
- Try to use the app — verify next protected request returns 401
- Verify graceful re-auth flow (not a generic 500)
- Verify session is cleaned up
Scope Minimization Checklist
For each provider:
- Scopes requested are the minimum needed
- No unnecessary "manage profile," "send email on your behalf," "access calendar" unless the app uses them
- Scopes documented per-feature so future devs don't drift
State and PKCE Validation Checklist
- Server-side: state parameter signed or unguessable, bound to session
- State validated on callback; mismatched state rejects
- PKCE: code_verifier stored client-side, code_challenge sent in initial auth request, verifier sent on token exchange
- Try to forge a callback with a different state — should reject
- Try to replay the same authorization code — should reject (one-time use)
Callback Redirect Validation Checklist
- Whitelist of allowed callback URLs in provider config
- App rejects callbacks to unexpected URLs
redirect_uriparameter is checked against the whitelist- No open-redirect via the OAuth callback
Token Storage Checklist
- Access tokens stored server-side, never in client localStorage
- Refresh tokens stored server-side, encrypted at rest if sensitive
- Tokens have appropriate expiry
- Refresh-token rotation: new refresh issued on use; old one invalidated
Session Establishment Checklist
- After OAuth callback, session cookie is set (HttpOnly, Secure, SameSite=Lax)
- Session lifetime matches policy (not infinite)
- Concurrent sessions handled per spec (allowed or revoked on new sign-in)
Mobile OAuth Checklist
- Provider redirect works in mobile browsers (Safari, Chrome iOS)
- iOS in-app webview behavior: app handles return correctly
- Universal links if applicable (for mobile-app flows, not web)
- OAuth doesn't get stuck in a popup-blocker on mobile
Provider Outage Fallback Checklist
- If Google OAuth is down, can the user sign in another way?
- App's error message when provider is unavailable is clear
- No silent failure where the user thinks they're signed in but aren't
Apple Sign-In Specific Checklist
- Apple's "Hide my email" relay address handled correctly
- App stores both
suband the relay email - Subsequent sign-ins from Apple match on
sub, not email - Email change in Apple ID is reflected (Apple sends an update)
- Apple's required UI guidelines met (button styling, "Sign in with Apple" wording)
Microsoft / Azure AD Specific Checklist
- Personal MS accounts vs work / school accounts both work (if both intended)
- Tenant restrictions if applicable (only specific orgs)
- Multi-tenant vs single-tenant app registration
Google Specific Checklist
- "Continue with Google" rendered per Google's branding guidelines
- One Tap UI if used; doesn't conflict with the main button
- Google verification status if app exceeds 100 users (verification required for production)
Account Deletion Checklist
- When user deletes their app account, are provider tokens revoked?
- Is the user removed from the provider's "Third-party apps connected" list?
- If not, document why (and verify the data retention complies with privacy law)
Evidence rules: Confirmed requires the driven flow per provider: the redirect chain with the state parameter as captured, the screen shown, and the resulting account and session rows read back. A linking or callback flaw inferred from configuration alone is Likely until driven. Providers that pass all scenarios are reported as such. Defer to each provider's current documentation for consent and revocation behaviour.
Calibration
Don't audit a provider that the app doesn't actually offer. Don't suggest adding Apple Sign-In to a B2B SaaS where users authenticate via Google Workspace. Calibrate to the providers offered, prioritize by sign-in volume (Google usually highest).
-
Severity:
- Critical — Account takeover possible via email collision; state parameter not validated; OAuth callback open-redirect; tokens stored in client-accessible storage
- High — Denied consent returns 500 (not graceful); revoked token isn't detected (stale session continues); excessive scopes requested
- Medium — Branding off (Apple's UI guidelines, Google's button); missing PKCE for public clients; provider outage has no fallback
- Low — Polish (consent screen explanation, post-signup landing)
-
Confidence ratings: Confirmed (reproduced), Likely (saw one flow), Speculative (config-level concern).
-
Anti-hallucination guard: Don't claim state validation works without forging a state and observing rejection. Don't claim PKCE is enforced without inspecting the request. Don't claim account-linking is safe without trying the email-collision attack from a fresh provider account.
Output Format
Start with a 5–8 line executive summary: providers audited, critical findings, top 3 fixes.
- Provider Matrix — Per provider: scopes, callback URL, button location
- Per-Provider Findings — Six scenarios per provider
- Email Collision Findings — Account-linking safety per provider
- State / PKCE Findings — Validation enforcement
- Token Storage Findings — Where tokens live, security posture
- Session Findings — Establishment, lifetime, concurrency
- Mobile OAuth Findings — Mobile-specific behavior
- Provider-Specific Findings — Apple, Google, Microsoft specifics
Close with a Prioritized Fix List with the security-impact tier first, then UX improvements.
Want this applied to a live stack?
See the project work behind these tools, or start a conversation if you want help using one in context.