Multi-Factor Authentication
Sphere supports multiple MFA methods: TOTP (authenticator apps), OTP (email codes), magic links, and WebAuthn (passkeys). Users can enable multiple methods simultaneously for maximum flexibility and security.
When MFA is enabled, the login endpoint returns a 202 response with an mfa_token instead of a full token set. The client must then verify the MFA challenge using one of the endpoints below before receiving access tokens.
Get MFA status
Retrieve the current MFA configuration for the authenticated user. Returns which methods are enabled and their details.
Request
curl https://your-sphere.example.com/auth/api/v1/auth/mfa/status \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..."
Response
{
"data": {
"enabled": true,
"methods": ["totp", "webauthn"],
"totp": {
"enabled": true,
"confirmed_at": "2026-01-15T10:30:00Z"
},
"webauthn": {
"enabled": true,
"credentials": [
{
"id": "abc123def456",
"name": "MacBook Pro Touch ID",
"created_at": "2026-02-01T14:20:00Z",
"last_used_at": "2026-02-24T08:15:00Z"
}
]
}
}
}
Verify MFA challenge
Complete the MFA verification step during login. After receiving a 202 response from the login endpoint with an mfa_token, submit the verification code for the chosen MFA method. On success, returns the full token set.
Required attributes
- Name
mfa_token- Type
- string
- Description
The MFA token received from the login endpoint's
202response.
- Name
method- Type
- string
- Description
The MFA method being used. One of
totp,otp, orrecovery_code.
- Name
code- Type
- string
- Description
The verification code from the authenticator app (TOTP), email (OTP), or a recovery code.
Request
curl -X POST https://your-sphere.example.com/auth/api/v1/auth/mfa/verify \
-H "Content-Type: application/json" \
-d '{
"mfa_token": "mfa_abc123def456...",
"method": "totp",
"code": "123456"
}'
Response
{
"data": {
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "def50200a1b2c3d4e5f6...",
"token_type": "Bearer",
"expires_in": 3600
},
"meta": {
"services": {
"auth": "https://your-sphere.example.com/auth",
"core": "https://your-sphere.example.com/core",
"chat": "https://your-sphere.example.com/chat",
"voip": "https://your-sphere.example.com/voip",
"drive": "https://your-sphere.example.com/drive",
"activity": "https://your-sphere.example.com/activity",
"usermanager": "https://your-sphere.example.com/usermanager",
"notes": "https://your-sphere.example.com/notes",
"mail": "https://your-sphere.example.com/mail"
}
}
}
Setup TOTP
Begin the TOTP (Time-based One-Time Password) setup process for the authenticated user. Returns a shared secret, a QR code URL for scanning with an authenticator app, and a provisioning URI. The setup is not complete until the user confirms it with a valid TOTP code via the confirm endpoint.
This endpoint requires authentication and accepts no request body.
Request
curl -X POST https://your-sphere.example.com/auth/api/v1/auth/mfa/totp/setup \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..."
Response
{
"data": {
"secret": "JBSWY3DPEHPK3PXP",
"qr_code_url": "data:image/png;base64,iVBORw0KGgo...",
"provisioning_uri": "otpauth://totp/Sphere:admin%40acme.local?secret=JBSWY3DPEHPK3PXP&issuer=Sphere"
}
}
Confirm TOTP setup
Complete the TOTP setup by verifying a code from the user's authenticator app. This confirms that the user has successfully configured their authenticator and activates TOTP as an MFA method. Returns a set of one-time recovery codes that the user should store securely.
Required attributes
- Name
code- Type
- string
- Description
A valid 6-digit TOTP code from the user's authenticator app.
Request
curl -X POST https://your-sphere.example.com/auth/api/v1/auth/mfa/totp/confirm \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{"code": "123456"}'
Response
{
"data": {
"recovery_codes": [
"a1b2c3d4e5",
"f6g7h8i9j0",
"k1l2m3n4o5",
"p6q7r8s9t0",
"u1v2w3x4y5",
"z6a7b8c9d0",
"e1f2g3h4i5",
"j6k7l8m9n0"
]
},
"message": "TOTP has been enabled successfully."
}
Disable TOTP
Disable TOTP for the authenticated user. Requires the user's current password for security confirmation. If TOTP is the user's only MFA method, MFA will be fully disabled.
Required attributes
- Name
password- Type
- string
- Description
The user's current password to confirm the action.
Request
curl -X DELETE https://your-sphere.example.com/auth/api/v1/auth/mfa/totp \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{"password": "SecurePass123!"}'
Response (204 No Content)
// No response body
Send OTP
Send a one-time password to the user's email address. The OTP is valid for a limited time (typically 10 minutes). This endpoint is public and does not reveal whether the email address exists in the system.
Required attributes
- Name
login- Type
- string
- Description
The email address to send the OTP to.
Request
curl -X POST https://your-sphere.example.com/auth/api/v1/auth/otp/send \
-H "Content-Type: application/json" \
-d '{"login": "user@example.com"}'
Response
{
"message": "If the account exists, a verification code has been sent."
}
Verify OTP
Verify a one-time password sent via email. On success, returns a full token set, completing the authentication flow.
Required attributes
- Name
login- Type
- string
- Description
The email address the OTP was sent to.
- Name
code- Type
- string
- Description
The 6-digit OTP code received via email.
Request
curl -X POST https://your-sphere.example.com/auth/api/v1/auth/otp/verify \
-H "Content-Type: application/json" \
-d '{
"login": "user@example.com",
"code": "123456"
}'
Response
{
"data": {
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "def50200a1b2c3d4e5f6...",
"token_type": "Bearer",
"expires_in": 3600
}
}
Request magic link
Send a magic link to the user's email address for passwordless authentication. The link contains a one-time token that expires after a limited time. This endpoint is public and does not reveal whether the email address exists.
Required attributes
- Name
login- Type
- string
- Description
The email address to send the magic link to.
Request
curl -X POST https://your-sphere.example.com/auth/api/v1/auth/magic-link \
-H "Content-Type: application/json" \
-d '{"login": "user@example.com"}'
Response
{
"message": "If the account exists, a magic link has been sent."
}
Verify magic link
Verify a magic link token received via email. On success, returns a full token set, completing the passwordless authentication flow.
Required attributes
- Name
token- Type
- string
- Description
The one-time token extracted from the magic link URL.
Request
curl -X POST https://your-sphere.example.com/auth/api/v1/auth/magic-link/verify \
-H "Content-Type: application/json" \
-d '{"token": "eyJpdiI6Ik1UQXlNek0wTlRZM09EazAi..."}'
Response
{
"data": {
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "def50200a1b2c3d4e5f6...",
"token_type": "Bearer",
"expires_in": 3600
}
}
Get WebAuthn registration options
Generate WebAuthn registration options for adding a new passkey to the authenticated user's account. Returns a publicKey object compatible with the Web Authentication API's navigator.credentials.create() method. The challenge is cached server-side with a 5-minute TTL and can only be used once.
This endpoint requires authentication and accepts no request body.
Request
curl -X POST https://your-sphere.example.com/auth/api/v1/auth/mfa/webauthn/register/options \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..."
Response
{
"data": {
"publicKey": {
"rp": {
"name": "Sphere",
"id": "your-sphere.example.com"
},
"user": {
"id": "dXNlci0xMjM0NTY...",
"name": "admin@acme.local",
"displayName": "Admin User"
},
"challenge": "Y2hhbGxlbmdlLXJhbmRvbS1ieXRlcw...",
"pubKeyCredParams": [
{ "type": "public-key", "alg": -7 },
{ "type": "public-key", "alg": -257 }
],
"timeout": 300000,
"attestation": "none",
"authenticatorSelection": {
"authenticatorAttachment": "platform",
"residentKey": "preferred",
"userVerification": "required"
}
}
}
}
Complete WebAuthn registration
Complete the WebAuthn registration by submitting the attestation response from the browser's navigator.credentials.create() call. On success, the passkey is stored and WebAuthn is enabled as an MFA method. Returns the credential ID and recovery codes.
Required attributes
- Name
id- Type
- string
- Description
The credential ID returned by the authenticator (base64url-encoded).
- Name
rawId- Type
- string
- Description
The raw credential ID (base64url-encoded).
- Name
response- Type
- object
- Description
The attestation response object containing
attestationObjectandclientDataJSON(both base64url-encoded).
- Name
type- Type
- string
- Description
Always
"public-key".
- Name
name- Type
- string
- Description
Optional human-readable name for the passkey (e.g., "MacBook Pro Touch ID").
Request
curl -X POST https://your-sphere.example.com/auth/api/v1/auth/mfa/webauthn/register/verify \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{
"id": "abc123def456...",
"rawId": "abc123def456...",
"response": {
"attestationObject": "o2NmbXRkbm9uZWdhdHRT...",
"clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4u..."
},
"type": "public-key",
"name": "MacBook Pro Touch ID"
}'
Response
{
"data": {
"credential_id": "abc123def456...",
"name": "MacBook Pro Touch ID",
"recovery_codes": [
"a1b2c3d4e5",
"f6g7h8i9j0",
"k1l2m3n4o5",
"p6q7r8s9t0",
"u1v2w3x4y5",
"z6a7b8c9d0",
"e1f2g3h4i5",
"j6k7l8m9n0"
]
},
"message": "Passkey registered successfully."
}
Get WebAuthn authentication options
Generate WebAuthn authentication options for verifying a passkey during login. Returns a publicKey object compatible with the Web Authentication API's navigator.credentials.get() method. The challenge is cached server-side with a 5-minute TTL.
Required attributes
- Name
login- Type
- string
- Description
The user's email address. Used to look up registered passkeys.
Request
curl -X POST https://your-sphere.example.com/auth/api/v1/auth/mfa/webauthn/authenticate/options \
-H "Content-Type: application/json" \
-d '{"login": "admin@acme.local"}'
Response
{
"data": {
"publicKey": {
"challenge": "cmFuZG9tLWNoYWxsZW5nZS1ieXRlcw...",
"rpId": "your-sphere.example.com",
"allowCredentials": [
{
"id": "abc123def456...",
"type": "public-key",
"transports": ["internal"]
}
],
"timeout": 300000,
"userVerification": "required"
}
}
}
Complete WebAuthn authentication
Complete WebAuthn authentication by submitting the assertion response from the browser's navigator.credentials.get() call. On success, returns a full token set.
Required attributes
- Name
id- Type
- string
- Description
The credential ID returned by the authenticator (base64url-encoded).
- Name
rawId- Type
- string
- Description
The raw credential ID (base64url-encoded).
- Name
response- Type
- object
- Description
The assertion response object containing
authenticatorData,clientDataJSON, andsignature(all base64url-encoded).
- Name
type- Type
- string
- Description
Always
"public-key".
- Name
login- Type
- string
- Description
The user's email address used during the options step.
Request
curl -X POST https://your-sphere.example.com/auth/api/v1/auth/mfa/webauthn/authenticate/verify \
-H "Content-Type: application/json" \
-d '{
"id": "abc123def456...",
"rawId": "abc123def456...",
"response": {
"authenticatorData": "SZYN5YgOjGh0NBcPZHZg...",
"clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4u...",
"signature": "MEUCIQDp7xBJhG..."
},
"type": "public-key",
"login": "admin@acme.local"
}'
Response
{
"data": {
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "def50200a1b2c3d4e5f6...",
"token_type": "Bearer",
"expires_in": 3600
},
"meta": {
"services": {
"auth": "https://your-sphere.example.com/auth",
"core": "https://your-sphere.example.com/core",
"chat": "https://your-sphere.example.com/chat",
"voip": "https://your-sphere.example.com/voip",
"drive": "https://your-sphere.example.com/drive",
"activity": "https://your-sphere.example.com/activity",
"usermanager": "https://your-sphere.example.com/usermanager",
"notes": "https://your-sphere.example.com/notes",
"mail": "https://your-sphere.example.com/mail"
}
}
}
Remove a passkey
Remove a specific WebAuthn credential (passkey) from the authenticated user's account. If this is the user's last passkey and no other MFA methods are enabled, WebAuthn will be fully disabled as an MFA method.
URL parameters
- Name
credentialId- Type
- string
- Description
The ID of the WebAuthn credential to remove.
Request
curl -X DELETE https://your-sphere.example.com/auth/api/v1/auth/mfa/webauthn/abc123def456 \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..."
Response (204 No Content)
// No response body