Email credential
Add an email, confirm it, resend the code, and promote it to primary.
Email is the most basic sign-in and delivery address. An account can bind several addresses, but only the primary one decides where verification codes and reset links go.
Endpoints
| Method | Path | Purpose | Step-up |
|---|---|---|---|
POST | /v1/auth/credentials/email/options | Send a code to the new address | max_age=300 |
POST | /v1/auth/credentials/email | Submit the code to finish binding | None |
POST | /v1/auth/credentials/email/resend | Resend the code | None |
POST | /v1/auth/credentials/email/:credentialId/primary | Make it the primary email | max_age=300 |
Step one: send the code
| Parameter | Type | Required | Notes |
|---|---|---|---|
email | string | ✅ | Address to bind, 3–254 chars |
{ "success": true, "expires_in": 600, "resend_after": 60 }The address is pinned in server-side state and valid for 10 minutes. resend_after is "seconds until a resend is allowed", computed by the server. Do not count it down on the client: the cooldown is set only after the mail was actually sent, so a locally counted timer drifts away from the server's remaining time.
Step two: confirm
| Parameter | Type | Required | Notes |
|---|---|---|---|
code | string | ✅ | The received code, 4–32 chars |
{ "success": true, "credential": { "id": "cred_...", "type": "email" } }This step does not take an address
The address was already pinned in step one. Accepting it again would allow the combination "code sent to A, binding B". The account's first email automatically becomes the primary one.
Resending
No request body; the response has the same shape as step one. It only requires a normal session: the code lives 600 seconds while the step-one elevation window is 300, so requiring step-up here would bounce any user who waited out the timer to a fresh sign-in.
Repeated calls inside the cooldown are rejected with Retry-After.
Making it primary
{ "success": true, "credentials": [ { "id": "cred_...", "primary": true } ] }It returns the whole email set rather than one row: primacy is a relation between rows, and returning a single row would leave the client to infer which one was demoted.
A primary email cannot be deleted, so this endpoint is the only way to move that anchor. Every call writes an audit entry.
Related
- Other credential types: Credential management
- How email is used during sign-in: Verification challenges