Skip to main content
Sinas supports three authentication modes for end-user login, plus API keys for programmatic access. The mode is set per-deployment via the AUTH_MODE environment variable and cannot be changed at runtime.

Auth Modes

Clients (custom frontends, the JS/Python SDKs, the official console) discover the active mode via the unauthenticated GET /info endpoint and branch their login UI accordingly.

Login Flows

otp

  1. Client posts email to POST /auth/login
  2. Sinas sends a 6-digit code (valid 10 min by default)
  3. Client posts code to POST /auth/verify-otp and receives access + refresh tokens

password

  1. Client posts email + password to POST /auth/login
  2. Sinas verifies and immediately returns access + refresh tokens

password+otp

  1. Client posts email + password to POST /auth/login
  2. On password match, Sinas sends a 6-digit OTP and returns an OTP session id
  3. Client posts code to POST /auth/verify-otp and receives access + refresh tokens

Tokens

All modes issue the same JWT pair:
  • Access token — short-lived (default 15 min), sent as Authorization: Bearer <token>
  • Refresh token — long-lived (default 30 days), exchanged at POST /auth/refresh

Superadmin Bootstrap

The first admin user is seeded from environment variables on backend startup:
  • SUPERADMIN_EMAIL — email of the user to create / promote to Admins
  • SUPERADMIN_PASSWORD — only used when AUTH_MODE is password or password+otp. Setting this on a running deployment and restarting the backend will reset the password — the escape hatch for “admin lost their password.”

Password Reset

For modes that include passwords:
  • User-initiated — not implemented when AUTH_MODE=password (no email channel guaranteed). Use admin reset.
  • Admin-initiated — an admin generates a one-time reset link from the user management page in the console and delivers it out-of-band (Slack, in person).
  • Lost-superadmin escape hatch — set SUPERADMIN_PASSWORD in the env and restart the backend.

API Keys

For programmatic access (scripts, CI/CD, integrations), create API keys instead of using short-lived JWT tokens. Each key has its own set of permissions (a subset of the creating user’s permissions). API keys work identically across all auth modes.
API keys can be used via Authorization: Bearer <key> or X-API-Key: <key> headers. Keys can have optional expiration dates.

Token Exchange (bring your own auth)

If your application already authenticates users itself, you don’t need to run a second Sinas login flow. Your backend exchanges its knowledge of “who is logged in” for Sinas tokens:
  1. An admin links your application’s user ids to Sinas users as external identities — or you let the exchange auto-provision them.
  2. Your backend calls the exchange endpoint with an API key holding the sinas.auth.exchange:all permission:
  1. The response contains a normal Sinas access + refresh token pair for that user, which your frontend uses against the runtime API. All ownership scoping (:own), permissions, and audit logging apply as if the user had logged in directly.
Behavior details:
  • The user is resolved by (provider, subject). If unknown and email is given, an existing user with that email is matched and the identity is linked to them.
  • With auto_provision: true, unknown users are created and assigned the TOKEN_EXCHANGE_DEFAULT_ROLE (default GuestUsers). email is required to provision.
  • metadata is stored on the identity and refreshed on every exchange. custom_fields is shallow-merged into the user’s custom fields (partner keys win, admin-set keys survive).
  • provisioned: true in the response indicates the exchange created the user.
The exchange endpoint trusts the caller to assert identities — treat keys with sinas.auth.exchange:all like any other admin credential.