Authentication
Today the API authenticates with an opaque session bearer token. You obtain
one by logging in with your operator credentials, then send it as an
Authorization: Bearer <token> header on every request. This is the canonical
auth flow - other pages refer back here.
Obtain a token
Section titled “Obtain a token”Log in with POST /api/auth/login to mint a session and receive a token.
| Method | Path | Purpose | Auth |
|---|---|---|---|
| POST | /api/auth/login |
Log in, mint a session token | public |
| GET | /api/auth/me |
Return the authenticated user | session |
| POST | /api/auth/logout |
Invalidate the current session | session |
The body takes email and password. A successful login returns
{ user, token } - store token and send it on subsequent requests.
curl -X POST "https://thesidedoor.co/api/auth/login" \ -H "Content-Type: application/json" \ -d '{"email":"operator@example.com","password":"your-password"}'const res = await fetch("https://thesidedoor.co/api/auth/login", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ email: "operator@example.com", password: "your-password", }),});const { user, token } = await res.json();$ch = curl_init("https://thesidedoor.co/api/auth/login");curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ["Content-Type: application/json"], CURLOPT_POSTFIELDS => json_encode([ "email" => "operator@example.com", "password" => "your-password", ]),]);$data = json_decode(curl_exec($ch), true);$token = $data["token"];{ "user": { "id": "usr_123", "role": "client", "name": "Jo Operator" }, "token": "s3ss10n.abc123signaturepart"}Two-factor accounts
Section titled “Two-factor accounts”If the account has TOTP two-factor enabled, POST /api/auth/login does not
return a token. Instead it returns { requires_2fa: true, user_id }. Complete
the login by posting the current 6-digit code to POST /api/2fa/validate with
{ user_id, token }; that call returns the usual { user, token }.
{ "requires_2fa": true, "user_id": "usr_123" }Make an authenticated request
Section titled “Make an authenticated request”Send the token as a bearer header. Store it in the SIDEDOOR_TOKEN environment
variable and reuse it across calls. GET /api/auth/me is a good check that a
token is valid.
curl "https://thesidedoor.co/api/auth/me" \ -H "Authorization: Bearer $SIDEDOOR_TOKEN"const res = await fetch("https://thesidedoor.co/api/auth/me", { headers: { Authorization: `Bearer ${process.env.SIDEDOOR_TOKEN}`, },});const { user } = await res.json();$ch = curl_init("https://thesidedoor.co/api/auth/me");curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "Authorization: Bearer {$token}", ],]);$data = json_decode(curl_exec($ch), true);{ "user": { "id": "usr_123", "role": "client", "name": "Jo Operator" } }Token lifetime
Section titled “Token lifetime”Sessions are stored server-side and slide on use - each authenticated request extends the expiry. TTLs depend on the account role:
| Role | Sliding TTL |
|---|---|
Operator/staff (client, organiser) |
3 days |
| Admin | 24 hours |
A missing or expired token on any /api/* route returns 401:
{ "error": "Session expired. Please sign in again." }Re-run the login flow to mint a fresh token.
Log out
Section titled “Log out”POST /api/auth/logout invalidates the current session server-side. Discard the
token afterwards.
curl -X POST "https://thesidedoor.co/api/auth/logout" \ -H "Authorization: Bearer $SIDEDOOR_TOKEN"await fetch("https://thesidedoor.co/api/auth/logout", { method: "POST", headers: { Authorization: `Bearer ${process.env.SIDEDOOR_TOKEN}`, },});$ch = curl_init("https://thesidedoor.co/api/auth/logout");curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "Authorization: Bearer {$token}", ],]);curl_exec($ch);{ "success": true }