Amba

Auth

Client-side auth — anonymous, Apple, Google, email signup / login, account linking, refresh, logout.

The client-side auth surface. Every route accepts an X-Api-Key header (the project's client key). All token verification is project-scoped — a token issued for project A is rejected with 401 INVALID_TOKEN when presented for project B, even if the signature is valid.

Source: apps/api/src/routes/client/auth.ts.

Endpoints

MethodPathDescription
POST/client/auth/anonymousCreate an anonymous user and return session + refresh tokens.
POST/client/auth/socialApple / Google sign-in via identity token exchange.
POST/client/auth/email/signupEmail + password signup (bcrypt-hashed).
POST/client/auth/email/loginEmail + password login.
POST/client/auth/linkLink an anonymous / logged-in account to an Apple / Google identity.
POST/client/auth/refreshRotate session + refresh tokens.
POST/client/auth/logoutRevoke a refresh token (idempotent).

Auth token shape

All success responses return:

{
  "data": {
    "session_token": "eyJ…",
    "refresh_token": "eyJ…",
    "user": {
      "id": "…",
      "email": "…",
      "display_name": "…",
      "anonymous_id": "…",
      "auth_providers": [],
      "properties": {},
      "first_seen_at": "…",
      "last_seen_at": "…"
    }
  }
}

session_token is a short-lived JWT; refresh_token is a long-lived JWT backed by a app_user_sessions row (sha256 hashed). On /refresh we verify the stored hash matches and that the session row hasn't been revoked.

POST /client/auth/anonymous

Create an anonymous user. Returns tokens immediately — no credentials to collect.

Request

No body required.

Response 201

Standard auth response plus anonymous_id:

{
  "data": {
    "session_token": "…",
    "refresh_token": "…",
    "user": { "id": "…", "anonymous_id": "anon_…" },
    "anonymous_id": "anon_…"
  }
}

Errors

  • 500 CREATE_FAILED.

Try it:

POST/client/auth/anonymous
client auth
curl -X POST 'https://api.amba.dev/client/auth/anonymous'
Loading auth… Configure auth in the settings drawer (top-right) to run this request.

Curl:

curl -X POST '${BASE_URL}/client/auth/anonymous' \
  -H 'X-Api-Key: ${CLIENT_API_KEY}' \
  -H 'Authorization: Bearer ${SESSION_TOKEN}' \
  -H 'Content-Type: application/json' \
  -d '{}'

POST /client/auth/social

Apple / Google sign-in. The identity token is verified against the provider's JWKS with strict audience validation (aud must match the project's bundle_id for Apple, google_oauth_client_id for Google). Missing audience config is fail-closed.

Request

FieldTypeRequiredDescription
provider"apple" | "google"yes
tokenstringyesProvider identity token.
session_tokenstringnoExisting session for automatic upgrade.

Response 200

Standard auth response.

Errors

  • 400 AUDIENCE_NOT_CONFIGURED — project has no configured audience for the provider.
  • 401 INVALID_TOKEN — identity token signature or audience verification failed.
  • 404 NOT_FOUND — project not found.
  • 500 CREATE_FAILED / SOCIAL_LOGIN_FAILED.

Try it:

POST/client/auth/social
public auth
curl -X POST 'https://api.amba.dev/client/auth/social'

Curl:

curl -X POST '${BASE_URL}/client/auth/social' \
  -H 'X-Api-Key: ${CLIENT_API_KEY}' \
  -H 'Content-Type: application/json' \
  -d '{}'

POST /client/auth/email/signup

Request

FieldTypeRequired
emailstringyes
passwordstringyes
display_namestringno

Response 201

Standard auth response.

Errors

  • 400 INVALID_INPUT — missing email / password.
  • 409 EMAIL_EXISTS — email already registered.
  • 500 CREATE_FAILED.

Try it:

POST/client/auth/email/signup
public auth
curl -X POST 'https://api.amba.dev/client/auth/email/signup'

Curl:

curl -X POST '${BASE_URL}/client/auth/email/signup' \
  -H 'X-Api-Key: ${CLIENT_API_KEY}' \
  -H 'Content-Type: application/json' \
  -d '{}'

POST /client/auth/email/login

Request

FieldTypeRequired
emailstringyes
passwordstringyes

Response 200

Standard auth response.

Errors

  • 400 INVALID_INPUT.
  • 401 INVALID_CREDENTIALS — wrong email / password.
  • 500 LOGIN_FAILED.

Try it:

POST/client/auth/email/login
public auth
curl -X POST 'https://api.amba.dev/client/auth/email/login'

Curl:

curl -X POST '${BASE_URL}/client/auth/email/login' \
  -H 'X-Api-Key: ${CLIENT_API_KEY}' \
  -H 'Content-Type: application/json' \
  -d '{}'

POST /client/auth/link

Link an Apple or Google identity to an existing user (typically an anonymous one, to preserve history). The session token must match the API key's project.

Email linking via this endpoint is explicitly refused — email identities must go through a verified signup / login flow.

Request

FieldTypeRequired
provider"apple" | "google"yes
tokenstringyes
session_tokenstringyes

Response 200

Standard auth response.

Errors

  • 400 UNSUPPORTED_PROVIDERprovider = "email".
  • 400 AUDIENCE_NOT_CONFIGURED.
  • 401 INVALID_SESSION — session token invalid.
  • 401 INVALID_TOKEN — identity token invalid.
  • 403 FORBIDDEN — session belongs to a different project.
  • 404 NOT_FOUND — project or user not found.
  • 409 IDENTITY_ALREADY_LINKED — the social identity is already bound to another account.
  • 500 LINK_FAILED.

Try it:

POST/client/auth/link
client auth
curl -X POST 'https://api.amba.dev/client/auth/link'
Loading auth… Configure auth in the settings drawer (top-right) to run this request.

Curl:

curl -X POST '${BASE_URL}/client/auth/link' \
  -H 'X-Api-Key: ${CLIENT_API_KEY}' \
  -H 'Authorization: Bearer ${SESSION_TOKEN}' \
  -H 'Content-Type: application/json' \
  -d '{}'

POST /client/auth/refresh

Rotate tokens. The old session row is revoked. Replaying a revoked token returns 401 INVALID_TOKEN — this is how token theft is detected.

Request

FieldTypeRequired
refresh_tokenstringyes

Response 200

{ "data": { "session_token": "…", "refresh_token": "…" } }

Errors

  • 400 INVALID_INPUT.
  • 401 INVALID_TOKEN — signature invalid, session not found, project mismatch, expired, or revoked.
  • 500 REFRESH_FAILED.

Try it:

POST/client/auth/refresh
public auth
curl -X POST 'https://api.amba.dev/client/auth/refresh'

Curl:

curl -X POST '${BASE_URL}/client/auth/refresh' \
  -H 'X-Api-Key: ${CLIENT_API_KEY}' \
  -H 'Content-Type: application/json' \
  -d '{}'

POST /client/auth/logout

Revoke the session. Idempotent — invalid tokens return success.

Request

FieldTypeRequired
refresh_tokenstringyes

Response 200

{ "data": { "success": true } }

Errors

  • 400 INVALID_INPUT.
  • 500 LOGOUT_FAILED.

Try it:

POST/client/auth/logout
client auth
curl -X POST 'https://api.amba.dev/client/auth/logout'
Loading auth… Configure auth in the settings drawer (top-right) to run this request.

Curl:

curl -X POST '${BASE_URL}/client/auth/logout' \
  -H 'X-Api-Key: ${CLIENT_API_KEY}' \
  -H 'Authorization: Bearer ${SESSION_TOKEN}' \
  -H 'Content-Type: application/json' \
  -d '{}'