Accounts and sign-in
People sign in with an email and password; the API answers with a session cookie, us_session (HttpOnly, Secure,
SameSite=Lax, 30 days, extended while in use). Programs use API tokens instead. Every error is
application/problem+json with a title that says what to do. The full reference is
GET /v1/openapi.json (OpenAPI 3.1, generated from the routes the API serves).
The examples below run, in this order, in the API's test suite. They keep the cookie in cookies.txt with curl's
-c (save) and -b (send).
| Route | What it does |
|---|---|
POST /v1/auth/signup | Create an account and its workspace; emails a confirmation link (24 hours) |
POST /v1/auth/verify | Confirm the email address with the token from that link |
POST /v1/auth/verify/resend | Send a new confirmation link |
POST /v1/auth/login | Sign in; sets the cookie, or asks for a second factor |
POST /v1/auth/login/2fa | The second step: the authenticator code |
POST /v1/auth/logout | End this session |
GET /v1/auth/sessions | Your live sessions |
DELETE /v1/auth/sessions/{id} | End one of them |
POST /v1/auth/password/change | Change your password (keeps this session, ends the others) |
POST /v1/auth/password/reset-request | Email a reset link (1 hour) |
POST /v1/auth/password/reset | Set a new password with that link; signs out everywhere |
POST /v1/auth/2fa/enroll | Start two-factor sign-in (TOTP) |
POST /v1/auth/2fa/confirm | Turn it on with a code |
POST /v1/auth/2fa/disable | Turn it off (password and code) |
GET /v1/me | Who you are: your account, workspaces, role and scopes |
GET /v1/openapi.json | The API reference |
Create an account
Passwords need at least 10 characters, and one that appears in a known data breach (checked against Have I Been Pwned without sending the password) is refused. The answer is the same whether or not the email already has an account.
curl https://api.usherstats.com/v1/auth/signup \
-H "Content-Type: application/json" \
-d '{"email": "ana@example.com", "password": "plum-orbit-71-lantern", "workspaceName": "Ana Sites"}'The email holds a link to https://app.usherstats.com/verify?token=.... The app posts that token here with the password
the account was signed up with (so a link opened by someone who did not sign up confirms nothing); it works once, and
starts no session: sign in afterwards.
curl https://api.usherstats.com/v1/auth/verify \
-H "Content-Type: application/json" \
--data @- <<EOF
{"token": "$VERIFY_TOKEN", "password": "plum-orbit-71-lantern"}
EOFLost the email? Ask for another (always 202, so it does not reveal who has an account):
curl https://api.usherstats.com/v1/auth/verify/resend \
-H "Content-Type: application/json" \
-d '{"email": "ana@example.com"}'Sign in
Until the address is confirmed, sign-in answers 403 with type email-unverified. After five wrong passwords for
one account from one address, sign-ins to that account from that address wait 30 seconds, doubling with each further
failure up to 15 minutes; meanwhile they get the same 401 as a wrong password, and other addresses are not
affected. The owner gets one email an hour about it. A password reset clears it at once.
curl https://api.usherstats.com/v1/auth/login -c cookies.txt \
-H "Content-Type: application/json" \
-d '{"email": "ana@example.com", "password": "plum-orbit-71-lantern"}'curl https://api.usherstats.com/v1/me -b cookies.txt/v1/me lists your workspaces. If you belong to more than one, choose the one a request acts on with the
X-Workspace: ws_... header (or ?workspace=ws_...); without it, the oldest membership is used.
Sessions
curl https://api.usherstats.com/v1/auth/sessions -b cookies.txtcurl -X POST https://api.usherstats.com/v1/auth/password/change -b cookies.txt \
-H "Content-Type: application/json" \
-d '{"currentPassword": "plum-orbit-71-lantern", "newPassword": "cedar-quartz-58-harbor"}'Two-factor sign-in
Enrolling returns a secret and an otpauth:// URI for an authenticator app (show the URI as a QR code). It is not on
until a code from the app is confirmed. The secret is stored encrypted; each code works once.
curl -X POST https://api.usherstats.com/v1/auth/2fa/enroll -b cookies.txt \
-H "Content-Type: application/json" \
-d '{"password": "cedar-quartz-58-harbor"}'curl -X POST https://api.usherstats.com/v1/auth/2fa/confirm -b cookies.txt \
-H "Content-Type: application/json" \
--data @- <<EOF
{"code": "$TOTP_CODE"}
EOFSign out, then sign in again: now the password step returns a challenge instead of a cookie, and the code
completes it (five guesses, five minutes).
curl -X POST https://api.usherstats.com/v1/auth/logout -b cookies.txt -c cookies.txtcurl https://api.usherstats.com/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email": "ana@example.com", "password": "cedar-quartz-58-harbor"}'curl https://api.usherstats.com/v1/auth/login/2fa -c cookies.txt \
-H "Content-Type: application/json" \
--data @- <<EOF
{"challenge": "$CHALLENGE", "code": "$TOTP_CODE"}
EOFcurl -X POST https://api.usherstats.com/v1/auth/2fa/disable -b cookies.txt \
-H "Content-Type: application/json" \
--data @- <<EOF
{"password": "cedar-quartz-58-harbor", "code": "$TOTP_CODE"}
EOFForgotten password
Always 202. The link (https://app.usherstats.com/reset?token=...) works once, for one hour. Setting the new
password signs out every session.
curl https://api.usherstats.com/v1/auth/password/reset-request \
-H "Content-Type: application/json" \
-d '{"email": "ana@example.com"}'curl https://api.usherstats.com/v1/auth/password/reset \
-H "Content-Type: application/json" \
--data @- <<EOF
{"token": "$RESET_TOKEN", "password": "violet-anchor-93-meadow"}
EOFcurl https://api.usherstats.com/v1/me -b cookies.txtSign in with the new password, and end that session by its id:
curl https://api.usherstats.com/v1/auth/login -c cookies.txt \
-H "Content-Type: application/json" \
-d '{"email": "ana@example.com", "password": "violet-anchor-93-meadow"}'curl https://api.usherstats.com/v1/auth/sessions -b cookies.txtcurl -X DELETE https://api.usherstats.com/v1/auth/sessions/$SESSION_ID -b cookies.txt -c cookies.txtThe reference
curl https://api.usherstats.com/v1/openapi.jsonLimits
Sign-up, sign-in, the confirmation and reset emails are rate limited per address (and the emails per recipient);
an API token may make 600 requests a minute. Past a limit the answer is 429 with Retry-After in seconds.