Auth API

building

Create an account with a six-digit code emailed to the address. No password needed.

Sign up

An account is created when somebody reads a code we email them. Two calls: ask for a code, then send the code back. That is the whole flow, and it is the only way an account comes into being.

There is no password sign-up. POST /v1/auth/sign-up/email answers 404 — see why below. A password is something a person adds later, once they already own the account.

1. Ask for a code

Request
1curl -X POST "$BASE/v1/auth/email-otp/send-verification-otp" \2  -H "authorization: Bearer $PK" \3  -H "content-type: application/json" \4  -d '{"email":"ada@example.com","type":"sign-in"}'
FieldRequiredNotes
emailyesLowercased and used as the account's identity
typeyessign-in for this flow — the same code creates or signs in
Response
1{ "success": true }

The same answer whether or not the address has an account, which is what keeps this from being a way to find out who your users are. One code, two outcomes, decided when it is redeemed.

2. Send the code back

Request
1curl -X POST "$BASE/v1/auth/sign-in/email-otp" \2  -H "authorization: Bearer $PK" \3  -H "content-type: application/json" \4  -d '{"email":"ada@example.com","otp":"481920"}'
Response
1{2  "token": "onSnRF8wZMuCs03Li7lcKJT2tLTvHjQO",3  "user": {4    "id": "NrzmwycxFVpxrD8RSZqieT4iqpW24W9M",5    "email": "ada@example.com",6    "emailVerified": true,7    "name": ""8  }9}

A Set-Cookie comes back with it. That cookie is the session — httpOnly, Secure, SameSite=Lax, and namespaced to your project so a browser can hold sessions for several apps at once without them colliding.

From a browser, send credentials: "include" or the cookie will not stick.

emailVerified is true on the first response, because proving the address is how the account was made. There is no separate confirmation step to wait on.

What the code looks like

Six digits, valid for ten minutes, three attempts. It arrives under your project's name rather than ours, and the digits are not in the subject line — a subject is repeated on lock screens and notification shades, and a code visible without unlocking the mailbox is a code that did not need the mailbox.

Adding a password afterwards

Optional, and most products do not need it. Somebody who wants one uses the password reset flow: it sets a password whether or not there was one before, and it proves the address on the way through.

Once set, they can use sign in with a password as well as codes. Both work; neither replaces the other.

Why there is no password sign-up

With one open, anybody can create an account against an address they do not own and choose its password. When the real owner later proves the address — clicks a confirmation link, or arrives through Google — the account becomes usable and the password the stranger chose still works. Requiring email verification does not close that; it only delays it.

Creating the account at the moment the address is proved does close it. Nothing exists before the proof, so there is nothing for a stranger to have set.

This is not a setting. See settings for what is fixed and what you can still decide.

Errors

StatusCodeMeans
400INVALID_OTPWrong code
400OTP_EXPIREDOlder than ten minutes — ask for another
403—Sign-up is closed; see disableSignUp in settings
401—Missing or invalid key
403—Publishable key used from an origin you have not registered
429—Rate limited; see limits
503—The project's auth database is still being created

Nothing here says whether the address has an account. Step one answers the same way regardless, and a wrong code is a wrong code whoever sent it.