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": "sdt_9f2a7c…redacted"}The token is an opaque credential - treat it as a secret string; its internal
structure is not part of the contract and may change.
Two-factor accounts
Section titled “Two-factor accounts”If the account has two-factor authentication enabled, the login is completed with
a second step: an authenticator code challenge. Once the challenge is satisfied
you receive the same { user, token } result. Handle it interactively (a person
enters their code); it isn’t suited to unattended server-to-server use.
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. An operator/staff session lasts 3 days on a sliding window (any authenticated request extends it).
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 }