End-user Auth

Mark a table as auth_table: true to get built-in email/password auth.

# Sign up
POST /p/{id}/auth/signup
{ "email": "user@example.com", "password": "secret123" }
# -> { token, refresh_token, user }

# Log in
POST /p/{id}/auth/login
{ "email": "user@example.com", "password": "secret123" }

# Refresh token
POST /p/{id}/auth/refresh
{ "refresh_token": "..." }

# Get current user
GET /p/{id}/auth/me
Authorization: Bearer {token}

# Logout
POST /p/{id}/auth/logout
Authorization: Bearer {token}

Using the token

Pass the JWT in subsequent requests:

Authorization: Bearer eyJhbGci...

Password management

# Change password (requires Bearer token)
POST /p/{id}/auth/change-password
{ "current_password": "old", "new_password": "new123456" }

# Forgot password (sends reset email)
POST /p/{id}/auth/forgot-password
{ "email": "user@example.com", "redirect_url": "https://myapp.com/reset" }

# Reset password (with token from email)
POST /p/{id}/auth/reset-password
{ "token": "...", "new_password": "new123456" }

forgot-password always returns 200 (never reveals whether the email exists). The redirect_url is your app's reset page — the token is appended as ?token=....

Important: redirect_url must use an origin from the project's allowed_redirect_origins allow-list. Configure it once with the admin key — otherwise forgot-password returns 400 VALIDATION_REDIRECT_URL:

PUT /p/{id}/v1/redirect-origins
X-Admin-Key: sk_...
{ "allowed_redirect_origins": ["https://myapp.com", "https://staging.myapp.com"] }

Changing or resetting a password invalidates all of that user's outstanding access tokens (they're bound to a per-user password version that bumps on every change). Refresh tokens are unaffected.

Key & secret rotation

POST /p/{id}/v1/rotate-keys        # rotate sk_ or pk_ (admin key required)
POST /p/{id}/v1/rotate-jwt-secret  # invalidates ALL outstanding end-user JWTs

Email verification

Add "verify_email": true to the auth table. Users receive a verification email on signup.

GET  /p/{id}/auth/verify?token=...
POST /p/{id}/auth/resend-verification
     Authorization: Bearer {token}

Signup with extra fields

If your auth table has custom columns, pass them in the signup body:

POST /p/{id}/auth/signup
{
  "email": "user@example.com",
  "password": "secret123",
  "display_name": "Alice",
  "role": "user"
}