Skip to main content

Authentication

The marketplace API has two auth modes. Use the one that matches your caller.

Used by fleapo-marketplace itself. better-auth issues an HTTP-only session cookie on POST /api/auth/sign-in/email. All subsequent requests include the cookie because fetch is called with credentials: 'include'.

POST /api/auth/sign-in/email
Content-Type: application/json

{ "email": "user@example.com", "password": "..." }

→ 200 + Set-Cookie: better-auth-session=...; HttpOnly; Secure; SameSite=Lax

Subsequent calls:

GET /me/subscriptions
Cookie: better-auth-session=...

For local development, use SameSite=Lax. For production, the cookie is automatically SameSite=None; Secure because the frontend is cross-origin.

Mode 2 — OAuth bearer token (agent backend)

Used by agent services calling marketplace endpoints. The agent backend obtains an access token via OAuth (see OAuth Federation).

GET /me/subscriptions/<agentId>
Authorization: Bearer <access_token>

Access tokens last 10 hours and are refreshable.

Which endpoints accept which

Endpoint groupCookie sessionBearer token
/me/* (user-scoped)
/admin/*✅ (must be platform_admin)✅ (rare)
/agents/* (read)
/agents/* (write)✅ (must be platform_admin)✅ (rare)
/webhooks/stripe❌ — uses Stripe signature instead
/api/auth/*— own auth model

AuthMiddleware checks both. Cookie session is preferred when present; if absent, it falls back to Authorization: Bearer <token> and validates the JWT against the JWKS.

Sign-in helpers from the agent UI

If you're calling the marketplace from your agent backend on behalf of a signed-in user, you need their access token. Get it from better-auth's session:

import { auth } from "./auth";

const session = await auth.api.getSession({ headers: req.headers });
const accessToken = session?.account?.accessToken;
// Now use accessToken in your fetch to the marketplace

Sign-up

POST /api/auth/sign-up/email with { email, password, name }. Creates a user row and immediately writes an interactions row of type user_signup (via the databaseHooks.user.create.after hook).

OAuth provider endpoints

These are at /api/auth/oauth2/* — see OAuth Federation for the full list. They are not part of the user-facing REST API; they implement the OIDC protocol.

Common errors

StatusWhen
401 UNAUTHORIZEDNo cookie, no bearer, or expired/invalid token
403 FORBIDDENAuthenticated but lacking required role

error.details.signInUrl and error.details.signUpUrl are populated on 401 to make agent-side redirects easy.