Skip to content

Authentication API

Base path /api/auth (rate-limited). The web app uses JWT in HttpOnly cookies; external apps use API keys (st_live_*) on the Service API.

Endpoints

MethodPathAuthPurpose
POST/api/auth/registerpublicCreate an account
POST/api/auth/loginpublicLog in → access + refresh tokens (HttpOnly cookies)
POST/api/auth/refreshrefresh cookieRotate the 15-minute access token
POST/api/auth/logoutJWTClear the session
GET/api/auth/meJWTCurrent user
PUT/api/auth/meJWTUpdate profile
GET/api/auth/apikeysJWTList your API keys
POST/api/auth/apikeysJWTCreate an st_live_* key (shown once)
DELETE/api/auth/apikeys/:idJWTRevoke a key

Token model

  • Access token — 15 minutes, HttpOnly cookie.
  • Refresh token — 30 days, HttpOnly cookie; POST /refresh rotates the access token.

API keys

Keys are st_live_*, SHA-256 hashed at rest, and scoped to projects + permissions (read, write, export, webhook). Use them with the Service API.

Account lockout

After 5 consecutive failed password attempts, an account is locked for 15 minutes. A locked account gets 429 on every login try during the lockout window, even with the correct password:

json
{ "error": "Account temporarily locked due to repeated failed logins. Try again later." }
  • The failed-attempt counter and lock both reset on the next successful login.
  • Lockout is checked after confirming the account exists but before verifying the password, so a locked account always responds the same way regardless of whether the submitted password happens to be correct.
  • This is separate from the constant-time password check the login route also performs (a fixed dummy bcrypt hash is compared even for unknown emails) — lockout prevents brute-forcing a known account; the dummy-hash compare prevents timing-based account enumeration.

→ Related: Projects · Service API

Released under the MIT License.