Authentication
The marketplace API has two auth modes. Use the one that matches your caller.
Mode 1 — Cookie session (browser SPA)
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 group | Cookie session | Bearer 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
| Status | When |
|---|---|
| 401 UNAUTHORIZED | No cookie, no bearer, or expired/invalid token |
| 403 FORBIDDEN | Authenticated but lacking required role |
error.details.signInUrl and error.details.signUpUrl are populated on 401 to make agent-side redirects easy.