Auth API

building

Confirm an address, and send the link again when the first one never arrives.

Verify email

Most apps never need this page. An account is created by reading a six-digit code we email, so the address is already confirmed the moment the account exists — there is no pending state to resolve. See sign up.

What is here is the link-based flow, which still runs for two cases: accounts created before codes existed, and an address that changes later. Both end at the same endpoint.

The mail

It goes out under your project's name rather than ours — in the subject line and in the From column, which is the half people actually read:

From: "Acme" <noreply@xplatform.dev>
Subject: Confirm your email for Acme

The code mail is the same in that respect, and one thing more: the digits are never in the subject line. A subject is repeated on lock screens and notification shades, and a code readable without unlocking the mailbox is a code that did not need the mailbox.

The sending address stays ours, because it is the domain verified with our mail provider. Only the name is yours. Someone signing up for your app has never heard of us, and their inbox should not be where they find out.

GET/v1/auth/verify-email

The link in the message. The person's browser follows it; you never call this yourself.

$BASE/v1/auth/verify-email?token=<token>&callbackURL=<where-to-land>

It marks the address verified and redirects to callbackURL, which must be an origin you registered. A link that could land anywhere is an open redirect with a session attached.

The token is signed, not stored — there is no row to expire and no table to clean up. It is good for 24 hours.

POST/v1/auth/send-verification-email

Send another one. Takes a publishable key.

Request
1curl -X POST "$BASE/v1/auth/send-verification-email" \2  -H "authorization: Bearer $PK" \3  -H "content-type: application/json" \4  -d '{"email":"ada@example.com","callbackURL":"https://yourapp.com/welcome"}'
Response
1{ "status": true }

The answer is the same whether the address is unknown, already verified, or rate limited. Anything else makes this a way to test who has an account with you. It means a true here is not a promise that a mail was sent.

Build a resend into your sign-in screen. The people who need it are the ones whose first mail never arrived — and if your app offers social login, they are the ones who will otherwise be stuck, because a social sign-in sends nothing.

Why an unverified address can block social login

Signing in with Google links that provider to an existing account with the same address. That link is refused while your record of the address is unverified, and the refusal is account_not_linked.

The reasoning is worth knowing before you meet it: without that rule, anyone could register someone else's address with a password, never confirm it, and be handed the account the first time the real owner used Google. Verifying the address is what proves which of them owns it.

Errors

StatusCodeMeans
400INVALID_TOKENThe link is malformed, expired, or already used
403INVALID_REDIRECT_URLcallbackURL is not a registered origin
429—Rate limited; see limits