Skip to main content

OAuth threat model

The marketplace acts as OIDC provider for every agent. Agents are public clients (no secret) using Authorization Code + PKCE-S256.

Threats and mitigations

1. Authorization code interception

Threat: An attacker intercepts the ?code= query param (URL leak, browser history, server logs) and trades it for tokens.

Mitigation: PKCE-S256. The legitimate client sent a SHA-256 hash of a random code_verifier. Trading the code at /token requires presenting the original code_verifier. An attacker has the hash but not the preimage.

PKCE is mandatory — the marketplace's /authorize rejects requests without code_challenge. There's no fallback.

2. Refresh token theft

Threat: An attacker obtains a refresh token (exfiltrated from the agent's DB, leaked log, etc.) and uses it to mint access tokens indefinitely.

Mitigation: Refresh token rotation. Every use issues a new refresh token and invalidates the old. If the legitimate client presents an old (rotated-out) token, the marketplace recognizes the reuse and invalidates the entire chain. The attacker and the legitimate user both lose access — and the attack is detectable.

Treat refresh tokens with the same care as passwords. They should never leave the agent backend.

3. Open redirect via redirect_uri

Threat: An attacker crafts an /authorize URL with their own redirect_uri and tricks a user into following it. The user signs in; the code goes to the attacker.

Mitigation: The marketplace validates redirect_uri against the agent's allow-list (oauthClient.redirect_uris, mirrored from agents.redirectUris). Mismatched URIs receive 400 invalid_redirect_uri before authorization runs.

Keep the allow-list tight. Never include wildcards. Never include localhost in production.

4. CSRF on the callback

Threat: An attacker makes the user's browser hit the agent's /oauth2/callback/marketplace with a code minted via a victim flow they control, fooling the agent into binding the victim's session to the attacker's marketplace identity.

Mitigation: The state parameter. The agent's /authorize request includes a random state; the agent backend stashes it in a short-lived cookie. The callback verifies the returned state matches. Better Auth handles this automatically.

5. Token replay across agents

Threat: A user installs Agent A and Agent B. Agent B (malicious or compromised) takes the user's access token and uses it to call Agent A's marketplace endpoints.

Mitigation: Access tokens carry aud (audience) — the client_id of the agent they were issued to. Each agent's userinfo / subscriptions / usage calls verify the token's aud matches the requested agent's OAuth client. A token issued to Agent B can't impersonate the user against Agent A.

Implementation: AuthMiddleware's jwtVerify includes audience: clientId in the verify options.

6. ID token forgery

Threat: An attacker fabricates an ID token claiming role: platform_admin.

Mitigation: The ID token is signed with the marketplace's EdDSA (Ed25519) private key. The agent verifies against the public JWKS. Forgery is computationally infeasible.

Use createRemoteJWKSet so key rotation propagates automatically.

7. Stolen session via XSS on the agent UI

Threat: An agent's frontend has an XSS; attacker injects JS to exfiltrate session cookies.

Mitigation: This is the agent's responsibility, not the marketplace's. Set cookies HttpOnly so JS can't read them. CSP. Sanitize all user-supplied HTML.

The marketplace's own session cookie is HttpOnly + Secure. The marketplace UI has no documented XSS surface (no dangerouslySetInnerHTML from user content).

8. Phishing via fake marketplace login

Threat: Attacker puts up marketp1ace.fleapo.ai and tricks users into entering credentials.

Mitigation: This is general phishing — out of scope for OAuth itself. Mitigate via:

  • Public encouragement of password managers.
  • 2FA (better-auth supports twoFactor plugin).
  • Domain monitoring.

Threat: A malicious third-party agent registers, gets oauthClientId, and tricks users into granting scopes.

Mitigation: Today, agent creation requires platform_admin. Third-party agents will need a separate onboarding flow with:

  • Email verification.
  • Manual review.
  • skipConsent: false so users see the consent screen.
  • Scopes audit before approval.

Until that exists, treat every agent as first-party.

Reference

Marketplace OIDC config:

  • Algorithm: EdDSA (Ed25519), 10h TTL.
  • Issuer: ${AUTH_URL}/api/auth.
  • JWKS: ${AUTH_URL}/api/auth/jwks (auto-rotates).

Client config:

  • Type: public.
  • PKCE: required, S256 only.
  • Grant types: authorization_code, refresh_token.
  • Response types: code only.

See Concept: OAuth federation for the full flow.