- Delivery channel is determined by the configured
magic_link_delivery.delivery_template_idcategory (emailorsms) in the portal. - Email template: provide
emailin the request body (or rely on upserteduser.email). - SMS template: provide
phone(+ optionalphone_country_code) or upserteduser.phone. - Send/resend endpoints return
{ ok: true, sent: true }even when the destination is unknown — this prevents email/phone enumeration. - S2S verify (
.../providers/magic_link/verify) requires knowingexternalUserId. - Public verify (
POST /auth/apps/:appId/magic-link/verify) needs only the token; strict IP rate limit (15 req/min). - Invalid, expired, or reused tokens return
400withAUTH_MAGIC_LINK_INVALID(or related code) without revealing whether the destination exists. - App config may include
success_redirect_urlandfailure_redirect_urlreturned on successful verify.
- Configure
magic_link_policy, delivery templates, and content in the Cliodot portal POST .../providers/magic_link/enroll— send first link- End user clicks link; your app calls verify with the token (S2S or public endpoint)
- On success, issue your own session
Default policies (overridable per app in the portal):
| Setting | Default |
|---|---|
| TOTP digits | 6 |
| TOTP period | 30 seconds |
| TOTP algorithm | sha1 |
| TOTP window | 1 |
| Max verification attempts | 5 |
| Lockout duration | 15 minutes |
| Enrollment TTL | 15 minutes |
| Recovery code count | 10 |
OTP Delivery Field Mapping#
Auth Apps separates transport fields (populated on every send), message template variables, and connector meta (user-defined).
Delivery templates and message templates are configured in the Cliodot portal. At runtime you may override content per send with custom_subject and custom_body.
Standard delivery fields#
| Email field | SMS field | Variable |
|---|---|---|
| To | Phone | {{delivery.to}} / {{delivery.phone}} |
| CC | — | {{delivery.cc}} |
| BCC | — | {{delivery.bcc}} |
| Subject | — | {{delivery.subject}} |
| Message | Message | {{delivery.message}} |
| HTML | — | {{delivery.body_html}} |
| Text | Text | {{delivery.body_text}} |
| Magic link URL | Magic link URL | {{delivery.magic_link_url}} |
| Attachments | Attachments | {{delivery.attachments}} |
Flat aliases: {{to}}, {{subject}}, {{message}}, {{phone}}, {{html}}, {{text}}.
Message template variables#
{{code}}, {{magic_link_url}}, {{magic_link_expiration_minutes}}, {{user.display_name}}, {{user.email}}, {{user.external_user_id}}, {{app.name}}, {{expires_minutes}}, {{sender_name}}, {{sender_email}}
Content priority at send: runtime custom_subject / custom_body → app inline custom (portal) → message template slug (portal) → system default.
Connector meta#
Map connector-specific inputs with {{meta.your_key}}:
- Static values: configured on the auth app in the portal (
email_otp_delivery.meta_values, etc.) - Per-send override:
{ "meta": { "campaign_id": "login" } }in runtime request body
Magic Link Notes#
- Delivery channel is determined by the configured
magic_link_delivery.delivery_template_idcategory (emailorsms) in the portal. - Email template: provide
emailin the request body (or rely on upserteduser.email). - SMS template: provide
phone(+ optionalphone_country_code) or upserteduser.phone. - Send/resend endpoints return
{ ok: true, sent: true }even when the destination is unknown — this prevents email/phone enumeration. - S2S verify (
.../providers/magic_link/verify) requires knowingexternalUserId. - Public verify (
POST /auth/apps/:appId/magic-link/verify) needs only the token; strict IP rate limit (15 req/min). - Invalid, expired, or reused tokens return
400withAUTH_MAGIC_LINK_INVALID(or related code) without revealing whether the destination exists. - App config may include
success_redirect_urlandfailure_redirect_urlreturned on successful verify.
API#
Base path: /auth
All endpoints (except public magic-link verify) require app credentials and are rate-limited to 30 requests/minute per IP + path + app + user.
Users#
Upsert User
| Method | PUT |
| Path | /auth/apps/:appId/users/:externalUserId |
| Auth | aak_ API key or App ID + secret |
| Description | Upsert user metadata before or during MFA enrollment. |
Request body (all optional)
| Field | Type |
|---|---|
email |
string |
phone |
string |
phone_country_code |
string |
display_name |
string |
metadata |
object |
Sample success response 200
{
"ok": true,
"user": {
"_id": "auth_user_507f1f77bcf86cd799439012",
"tenant_id": "tenant_456",
"auth_app_id": "auth_app_507f1f77bcf86cd799439011",
"external_user_id": "user_123",
"email": "user@example.com",
"display_name": "Jane Doe",
"metadata": { "department": "engineering" },
"created_at": "2026-07-09T10:30:00.000Z",
"updated_at": "2026-07-09T10:30:00.000Z"
}
}
Common errors: 401 AUTH_UNAUTHORIZED_APP, 403 AUTH_APP_DISABLED, 429 AUTH_RATE_LIMITED
cURL
curl -X PUT "https://api.example.com/auth/apps/auth_app_507f1f77bcf86cd799439011/users/user_123" \
-H "Authorization: Bearer YOUR_APP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"email": "user@example.com", "display_name": "Jane Doe", "metadata": {"department": "engineering"}}'
MFA Status#
Get MFA Status
| Method | GET |
| Path | /auth/apps/:appId/users/:externalUserId/mfa/status |
| Auth | App credentials |
| Description | Get MFA enrollment status for a user across all factors. |
Sample success response 200
{
"ok": true,
"external_user_id": "user_123",
"mfa_enabled": true,
"factors": [
{
"factor_type": "totp",
"status": "active",
"activated_at": "2026-07-09T10:45:00.000Z",
"recovery_codes_remaining": 8
}
]
}
Common errors: 401 AUTH_UNAUTHORIZED_APP, 429 AUTH_RATE_LIMITED
cURL
curl "https://api.example.com/auth/apps/auth_app_507f1f77bcf86cd799439011/users/user_123/mfa/status" \
-H "Authorization: Bearer YOUR_APP_API_KEY"
TOTP#
Enroll TOTP
| Method | POST |
| Path | /auth/apps/:appId/users/:externalUserId/mfa/totp/enroll |
| Auth | App credentials |
| Description | Start TOTP enrollment. Returns secret and QR code once. |
Request body
| Field | Type | Required |
|---|---|---|
label |
string | No |
reset |
boolean | No |
Sample success response 200
{
"ok": true,
"enrollment_id": "auth_enr_507f1f77bcf86cd799439013",
"status": "pending",
"factor_type": "totp",
"secret": "YOUR_TOTP_SECRET",
"otpauth_url": "otpauth://totp/Acme%20Admin:user_123?secret=YOUR_TOTP_SECRET&issuer=Acme%20Admin&digits=6&period=30",
"qr_code_data_url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...",
"pending_expires_at": "2026-07-09T12:00:00.000Z"
}
Common errors: 409 AUTH_ENROLLMENT_ALREADY_ACTIVE, 404 AUTH_APP_NOT_FOUND
cURL
curl -X POST "https://api.example.com/auth/apps/auth_app_507f1f77bcf86cd799439011/users/user_123/mfa/totp/enroll" \
-H "Authorization: Bearer YOUR_APP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"label": "user@example.com"}'
Confirm TOTP Enrollment
| Method | POST |
| Path | /auth/apps/:appId/users/:externalUserId/mfa/totp/confirm |
| Auth | App credentials |
| Description | Confirm enrollment with the first valid 6-digit TOTP code from the authenticator app. |
Request body: code (string, required)
Sample success response 200
{
"ok": true,
"verified": true,
"enrollment_status": "active",
"activated_at": "2026-07-09T10:45:00.000Z"
}
Common errors: 400 AUTH_INVALID_CODE, 410 AUTH_ENROLLMENT_EXPIRED, 409 AUTH_ENROLLMENT_PENDING
cURL
curl -X POST "https://api.example.com/auth/apps/auth_app_507f1f77bcf86cd799439011/users/user_123/mfa/totp/confirm" \
-H "Authorization: Bearer YOUR_APP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"code": "123456"}'
Verify TOTP
| Method | POST |
| Path | /auth/apps/:appId/users/:externalUserId/mfa/totp/verify |
| Auth | App credentials |
| Description | Verify TOTP code during login. Call after your backend validates the user's password. |
Request body: code (string, required)
Sample success response 200
{
"ok": true,
"verified": true,
"method": "totp",
"enrollment_status": "active",
"verified_at": "2026-07-09T11:30:00.000Z",
"recovery_codes_remaining": 8
}
Common errors: 400 AUTH_INVALID_CODE, 409 AUTH_REPLAY_DETECTED, 423 AUTH_USER_LOCKED, 404 AUTH_MFA_NOT_ENABLED
cURL
curl -X POST "https://api.example.com/auth/apps/auth_app_507f1f77bcf86cd799439011/users/user_123/mfa/totp/verify" \
-H "Authorization: Bearer YOUR_APP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"code": "654321"}'
Disable TOTP
| Method | POST |
| Path | /auth/apps/:appId/users/:externalUserId/mfa/totp/disable |
| Auth | App credentials |
| Description | Disable TOTP MFA for a user. |
Sample success response 200
{
"ok": true,
"disabled": true
}
Common errors: 404 AUTH_MFA_NOT_ENABLED
cURL
curl -X POST "https://api.example.com/auth/apps/auth_app_507f1f77bcf86cd799439011/users/user_123/mfa/totp/disable" \
-H "Authorization: Bearer YOUR_APP_API_KEY"
Reset TOTP
| Method | POST |
| Path | /auth/apps/:appId/users/:externalUserId/mfa/totp/reset |
| Auth | App credentials |
| Description | Reset TOTP secret and start new enrollment. Invalidates existing recovery codes. |
Request body: label (optional string)
Sample success response 200
{
"ok": true,
"enrollment_id": "auth_enr_507f1f77bcf86cd799439014",
"status": "pending",
"factor_type": "totp",
"secret": "YOUR_TOTP_SECRET",
"otpauth_url": "otpauth://totp/Acme%20Admin:user_123?secret=YOUR_TOTP_SECRET&issuer=Acme%20Admin&digits=6&period=30",
"qr_code_data_url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...",
"pending_expires_at": "2026-07-09T12:00:00.000Z"
}
Common errors: 404 AUTH_USER_NOT_FOUND
cURL
curl -X POST "https://api.example.com/auth/apps/auth_app_507f1f77bcf86cd799439011/users/user_123/mfa/totp/reset" \
-H "Authorization: Bearer YOUR_APP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"label": "user@example.com"}'
Recovery Codes#
Generate Recovery Codes
| Method | POST |
| Path | /auth/apps/:appId/users/:externalUserId/mfa/recovery-codes |
| Auth | App credentials |
| Description | Generate backup recovery codes. Codes shown once; previous batch invalidated. |
Sample success response 200
{
"ok": true,
"codes": [
"YOUR_RECOVERY_CODE",
"mnop-qrst-uvwx",
"yzab-cdef-ghij",
"klmn-opqr-stuv",
"wxyz-abcd-efgh",
"ijkl-mnop-qrst",
"uvwx-yzab-cdef",
"ghij-klmn-opqr",
"stuv-wxyz-abcd",
"efgh-ijkl-mnop"
],
"batch_id": "auth_rcb_507f1f77bcf86cd799439016",
"count": 10
}
Common errors: 404 AUTH_MFA_NOT_ENABLED
cURL
curl -X POST "https://api.example.com/auth/apps/auth_app_507f1f77bcf86cd799439011/users/user_123/mfa/recovery-codes" \
-H "Authorization: Bearer YOUR_APP_API_KEY"
Verify Recovery Code
| Method | POST |
| Path | /auth/apps/:appId/users/:externalUserId/mfa/recovery-codes/verify |
| Auth | App credentials |
| Description | Verify a one-time recovery code during login. |
Request body: code (string, required)
Sample success response 200
{
"ok": true,
"verified": true,
"method": "recovery_code",
"enrollment_status": "active",
"verified_at": "2026-07-09T11:35:00.000Z",
"recovery_codes_remaining": 7
}
Common errors: 400 AUTH_RECOVERY_CODE_INVALID, 409 AUTH_RECOVERY_CODE_USED, 423 AUTH_USER_LOCKED
cURL
curl -X POST "https://api.example.com/auth/apps/auth_app_507f1f77bcf86cd799439011/users/user_123/mfa/recovery-codes/verify" \
-H "Authorization: Bearer YOUR_APP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"code": "YOUR_RECOVERY_CODE"}'
Email OTP#
Provider path segment: email_otp. Shared request body fields for send endpoints (enroll, challenge, resend):
| Field | Type | Description |
|---|---|---|
email |
string | Recipient email (or rely on upserted user) |
custom_subject |
string | Override message subject |
custom_body |
string | Override message body |
cc |
string | Email CC override |
bcc |
string | Email BCC override |
attachments |
array | Attachment overrides |
meta |
object | Connector meta overrides |
Email OTP — Enroll
| Method | POST |
| Path | /auth/apps/:appId/users/:externalUserId/providers/email_otp/enroll |
| Auth | App credentials |
| Description | Enroll email OTP and send first code via configured delivery template. |
Sample success response 200
{
"ok": true,
"sent": true,
"expires_at": "2026-07-09T12:10:00.000Z"
}
Queued send (resend_mode: queue during cooldown):
{
"ok": true,
"queued": true,
"position": 2,
"scheduled_at": "2026-07-09T12:02:00.000Z"
}
Common errors: 422 AUTH_DESTINATION_REQUIRED, 422 AUTH_METHOD_NOT_ENABLED, 429 AUTH_RESEND_COOLDOWN, 502 AUTH_DELIVERY_FAILED
cURL
curl -X POST "https://api.example.com/auth/apps/auth_app_507f1f77bcf86cd799439011/users/user_123/providers/email_otp/enroll" \
-H "Authorization: Bearer YOUR_APP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"email": "user@example.com", "custom_subject": "Your login code", "custom_body": "Enter {{code}} to sign in"}'
Email OTP — Challenge
| Method | POST |
| Path | /auth/apps/:appId/users/:externalUserId/providers/email_otp/challenge |
| Auth | App credentials |
| Description | Request a new email OTP code (login challenge). |
Request body: Same as enroll.
Sample success response 200
{
"ok": true,
"sent": true,
"expires_at": "2026-07-09T12:10:00.000Z"
}
Common errors: 429 AUTH_RESEND_COOLDOWN, 429 AUTH_RESEND_QUEUE_FULL, 422 AUTH_DESTINATION_REQUIRED
cURL
curl -X POST "https://api.example.com/auth/apps/auth_app_507f1f77bcf86cd799439011/users/user_123/providers/email_otp/challenge" \
-H "Authorization: Bearer YOUR_APP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"email": "user@example.com"}'
Email OTP — Resend
| Method | POST |
| Path | /auth/apps/:appId/users/:externalUserId/providers/email_otp/resend |
| Auth | App credentials |
| Description | Resend the current email OTP code. |
Request body: Same as enroll.
Sample success response 200
{
"ok": true,
"sent": true,
"expires_at": "2026-07-09T12:10:00.000Z"
}
Common errors: 429 AUTH_RESEND_COOLDOWN, 429 AUTH_RESEND_QUEUE_FULL
cURL
curl -X POST "https://api.example.com/auth/apps/auth_app_507f1f77bcf86cd799439011/users/user_123/providers/email_otp/resend" \
-H "Authorization: Bearer YOUR_APP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"email": "user@example.com"}'
Email OTP — Verify
| Method | POST |
| Path | /auth/apps/:appId/users/:externalUserId/providers/email_otp/verify |
| Auth | App credentials |
| Description | Verify email OTP code. Failed verification returns { ok: true, verified: false } without leaking validity details. |
Request body: code (string, required)
Sample success response 200
{
"ok": true,
"verified": true,
"method": "email_otp",
"enrollment_status": "active",
"verified_at": "2026-07-09T11:30:00.000Z"
}
Common errors: 410 AUTH_OTP_EXPIRED, 423 AUTH_USER_LOCKED
cURL
curl -X POST "https://api.example.com/auth/apps/auth_app_507f1f77bcf86cd799439011/users/user_123/providers/email_otp/verify" \
-H "Authorization: Bearer YOUR_APP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"code": "123456"}'
Email OTP — Disable
| Method | POST |
| Path | /auth/apps/:appId/users/:externalUserId/providers/email_otp/disable |
| Auth | App credentials |
| Description | Disable email OTP factor for a user. |
Sample success response 200
{
"ok": true,
"disabled": true
}
Common errors: 404 AUTH_ENROLLMENT_NOT_FOUND, 404 AUTH_MFA_NOT_ENABLED
cURL
curl -X POST "https://api.example.com/auth/apps/auth_app_507f1f77bcf86cd799439011/users/user_123/providers/email_otp/disable" \
-H "Authorization: Bearer YOUR_APP_API_KEY"
Email OTP — Status
| Method | GET |
| Path | /auth/apps/:appId/users/:externalUserId/providers/email_otp/status |
| Auth | App credentials |
| Description | Get email OTP factor enrollment status. |
Sample success response 200
{
"ok": true,
"factor_type": "email_otp",
"enrollment_status": "active",
"mfa_enabled": true,
"destination_masked": "u***@example.com"
}
cURL
curl "https://api.example.com/auth/apps/auth_app_507f1f77bcf86cd799439011/users/user_123/providers/email_otp/status" \
-H "Authorization: Bearer YOUR_APP_API_KEY"
SMS OTP#
Provider path segment: sms_otp. Shared request body fields for send endpoints:
| Field | Type | Description |
|---|---|---|
phone |
string | Recipient phone number |
phone_country_code |
string | Country code (e.g. US) |
custom_body |
string | Override SMS body |
meta |
object | Connector meta overrides |
SMS OTP — Enroll
| Method | POST |
| Path | /auth/apps/:appId/users/:externalUserId/providers/sms_otp/enroll |
| Auth | App credentials |
| Description | Enroll SMS OTP and send first code via configured delivery template. |
Sample success response 200
{
"ok": true,
"sent": true,
"expires_at": "2026-07-09T12:05:00.000Z"
}
Common errors: 422 AUTH_DESTINATION_REQUIRED, 422 AUTH_METHOD_NOT_ENABLED, 429 AUTH_RESEND_COOLDOWN, 502 AUTH_DELIVERY_FAILED
cURL
curl -X POST "https://api.example.com/auth/apps/auth_app_507f1f77bcf86cd799439011/users/user_123/providers/sms_otp/enroll" \
-H "Authorization: Bearer YOUR_APP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"phone": "4155550100", "phone_country_code": "US"}'
SMS OTP — Challenge
| Method | POST |
| Path | /auth/apps/:appId/users/:externalUserId/providers/sms_otp/challenge |
| Auth | App credentials |
| Description | Request a new SMS OTP code (login challenge). |
Request body: Same as enroll.
Sample success response 200
{
"ok": true,
"sent": true,
"expires_at": "2026-07-09T12:05:00.000Z"
}
Common errors: 429 AUTH_RESEND_COOLDOWN, 422 AUTH_DESTINATION_REQUIRED
cURL
curl -X POST "https://api.example.com/auth/apps/auth_app_507f1f77bcf86cd799439011/users/user_123/providers/sms_otp/challenge" \
-H "Authorization: Bearer YOUR_APP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"phone": "4155550100", "phone_country_code": "US"}'
SMS OTP — Resend
| Method | POST |
| Path | /auth/apps/:appId/users/:externalUserId/providers/sms_otp/resend |
| Auth | App credentials |
| Description | Resend the current SMS OTP code. |
Request body: Same as enroll.
Sample success response 200
{
"ok": true,
"sent": true,
"expires_at": "2026-07-09T12:05:00.000Z"
}
Common errors: 429 AUTH_RESEND_COOLDOWN, 429 AUTH_RESEND_QUEUE_FULL
cURL
curl -X POST "https://api.example.com/auth/apps/auth_app_507f1f77bcf86cd799439011/users/user_123/providers/sms_otp/resend" \
-H "Authorization: Bearer YOUR_APP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"phone": "4155550100"}'
SMS OTP — Verify
| Method | POST |
| Path | /auth/apps/:appId/users/:externalUserId/providers/sms_otp/verify |
| Auth | App credentials |
| Description | Verify SMS OTP code. |
Request body: code (string, required)
Sample success response 200
{
"ok": true,
"verified": true,
"method": "sms_otp",
"enrollment_status": "active",
"verified_at": "2026-07-09T11:30:00.000Z"
}
Common errors: 410 AUTH_OTP_EXPIRED, 423 AUTH_USER_LOCKED
cURL
curl -X POST "https://api.example.com/auth/apps/auth_app_507f1f77bcf86cd799439011/users/user_123/providers/sms_otp/verify" \
-H "Authorization: Bearer YOUR_APP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"code": "123456"}'
SMS OTP — Disable
| Method | POST |
| Path | /auth/apps/:appId/users/:externalUserId/providers/sms_otp/disable |
| Auth | App credentials |
| Description | Disable SMS OTP factor for a user. |
Sample success response 200
{
"ok": true,
"disabled": true
}
Common errors: 404 AUTH_ENROLLMENT_NOT_FOUND
cURL
curl -X POST "https://api.example.com/auth/apps/auth_app_507f1f77bcf86cd799439011/users/user_123/providers/sms_otp/disable" \
-H "Authorization: Bearer YOUR_APP_API_KEY"
SMS OTP — Status
| Method | GET |
| Path | /auth/apps/:appId/users/:externalUserId/providers/sms_otp/status |
| Auth | App credentials |
| Description | Get SMS OTP factor enrollment status. |
Sample success response 200
{
"ok": true,
"factor_type": "sms_otp",
"enrollment_status": "active",
"mfa_enabled": true,
"destination_masked": "***0100"
}
cURL
curl "https://api.example.com/auth/apps/auth_app_507f1f77bcf86cd799439011/users/user_123/providers/sms_otp/status" \
-H "Authorization: Bearer YOUR_APP_API_KEY"
Magic Link#
Shared request body fields for send endpoints (enroll, challenge, resend):
| Field | Type | Description |
|---|---|---|
email |
string | For email delivery templates |
phone |
string | For SMS delivery templates |
phone_country_code |
string | Country code for SMS |
custom_subject |
string | Override subject (email) |
custom_body |
string | Override body |
cc, bcc, attachments |
Email overrides | |
meta |
object | Connector meta overrides |
Magic Link — Enroll
| Method | POST |
| Path | /auth/apps/:appId/users/:externalUserId/providers/magic_link/enroll |
| Auth | App credentials |
| Description | Enroll magic link and send first link via configured delivery template. |
Sample success response 200
{
"ok": true,
"sent": true,
"expires_in": 900,
"challenge_id": "auth_ml_ch_507f1f77bcf86cd799439020"
}
Common errors: 422 AUTH_METHOD_NOT_ENABLED, 422 AUTH_DESTINATION_REQUIRED, 429 AUTH_RESEND_COOLDOWN, 502 AUTH_DELIVERY_FAILED
cURL
curl -X POST "https://api.example.com/auth/apps/auth_app_507f1f77bcf86cd799439011/users/user_123/providers/magic_link/enroll" \
-H "Authorization: Bearer YOUR_APP_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"custom_subject": "Sign in to Acme",
"custom_body": "Click {{magic_link_url}} to sign in. Expires in {{magic_link_expiration_minutes}} minutes."
}'
Magic Link — Challenge
| Method | POST |
| Path | /auth/apps/:appId/users/:externalUserId/providers/magic_link/challenge |
| Auth | App credentials |
| Description | Request a new magic link (login challenge). |
Request body: Same as enroll.
Sample success response 200
{
"ok": true,
"sent": true,
"expires_in": 900,
"challenge_id": "auth_ml_ch_507f1f77bcf86cd799439021"
}
Common errors: 429 AUTH_RESEND_COOLDOWN, 422 AUTH_DESTINATION_REQUIRED
cURL
curl -X POST "https://api.example.com/auth/apps/auth_app_507f1f77bcf86cd799439011/users/user_123/providers/magic_link/challenge" \
-H "Authorization: Bearer YOUR_APP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"email": "user@example.com"}'
Magic Link — Resend
| Method | POST |
| Path | /auth/apps/:appId/users/:externalUserId/providers/magic_link/resend |
| Auth | App credentials |
| Description | Resend magic link to the user. |
Request body: Same as enroll.
Sample success response 200
{
"ok": true,
"sent": true,
"expires_in": 900,
"challenge_id": "auth_ml_ch_507f1f77bcf86cd799439022"
}
Common errors: 429 AUTH_RESEND_COOLDOWN
cURL
curl -X POST "https://api.example.com/auth/apps/auth_app_507f1f77bcf86cd799439011/users/user_123/providers/magic_link/resend" \
-H "Authorization: Bearer YOUR_APP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"email": "user@example.com"}'
Magic Link — Verify (S2S)
| Method | POST |
| Path | /auth/apps/:appId/users/:externalUserId/providers/magic_link/verify |
| Auth | App credentials |
| Description | Verify magic link token for a known user. Use when your backend handles the callback. |
Request body: token (string, required) — base64url token from the link
Sample success response 200
{
"ok": true,
"verified": true,
"method": "magic_link",
"challenge_id": "auth_ml_ch_507f1f77bcf86cd799439020",
"user_reference": "user_123",
"success_redirect_url": "https://app.example.com/dashboard",
"failure_redirect_url": "https://app.example.com/login?error=magic_link"
}
Common errors: 400 AUTH_MAGIC_LINK_INVALID, 400 AUTH_MAGIC_LINK_EXPIRED, 400 AUTH_MAGIC_LINK_ALREADY_USED
cURL
curl -X POST "https://api.example.com/auth/apps/auth_app_507f1f77bcf86cd799439011/users/user_123/providers/magic_link/verify" \
-H "Authorization: Bearer YOUR_APP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"token": "base64url-token-from-link"}'
Magic Link — Disable
| Method | POST |
| Path | /auth/apps/:appId/users/:externalUserId/providers/magic_link/disable |
| Auth | App credentials |
| Description | Disable magic link factor for a user. |
Sample success response 200
{
"ok": true,
"disabled": true
}
Common errors: 404 AUTH_ENROLLMENT_NOT_FOUND
cURL
curl -X POST "https://api.example.com/auth/apps/auth_app_507f1f77bcf86cd799439011/users/user_123/providers/magic_link/disable" \
-H "Authorization: Bearer YOUR_APP_API_KEY"
Magic Link — Status
| Method | GET |
| Path | /auth/apps/:appId/users/:externalUserId/providers/magic_link/status |
| Auth | App credentials |
| Description | Get magic link factor enrollment status. |
Sample success response 200
{
"ok": true,
"factor_type": "magic_link",
"enrollment_status": "active",
"mfa_enabled": true,
"destination_masked": "u***@example.com"
}
cURL
curl "https://api.example.com/auth/apps/auth_app_507f1f77bcf86cd799439011/users/user_123/providers/magic_link/status" \
-H "Authorization: Bearer YOUR_APP_API_KEY"
Public Magic Link Verify#
Verify Magic Link (Public)
| Method | POST |
| Path | /auth/apps/:appId/magic-link/verify |
| Auth | None (token only) |
| Description | Public token-only verify endpoint. Strict IP rate limit: 15 requests/minute. Use when the end user's browser hits your callback directly. |
Request body: token (string, required)
Sample success response 200
{
"ok": true,
"verified": true,
"method": "magic_link",
"challenge_id": "auth_ml_ch_507f1f77bcf86cd799439020",
"user_reference": "user_123",
"success_redirect_url": "https://app.example.com/dashboard",
"failure_redirect_url": "https://app.example.com/login?error=magic_link"
}
Common errors: 400 AUTH_MAGIC_LINK_INVALID, 400 AUTH_MAGIC_LINK_EXPIRED, 400 AUTH_MAGIC_LINK_ALREADY_USED, 429 AUTH_RATE_LIMITED
cURL
curl -X POST "https://api.example.com/auth/apps/auth_app_507f1f77bcf86cd799439011/magic-link/verify" \
-H "Content-Type: application/json" \
-d '{"token": "base64url-token-from-link"}'