Skip to content

Authentication API ​

POST /v1/auth/signup ​

Create an account and workspace.

json
// request
{ "name": "Dana Whitfield", "email": "dana@acme.com", "password": "s3cr3t" }

// response 201
{ "token": "<jwt>", "user": { "id": "uuid", "name": "Dana Whitfield", "email": "dana@acme.com" } }

POST /v1/auth/login ​

json
// request
{ "email": "dana@acme.com", "password": "s3cr3t" }

// response — 2FA not enabled
{ "token": "<jwt>", "user": { ... } }

// response — 2FA enabled
{ "mfaRequired": true, "mfaToken": "<short-lived-jwt>" }

When mfaRequired: true, prompt for TOTP code and call POST /v1/auth/verify-mfa. The mfaToken expires in 5 minutes.

POST /v1/auth/verify-mfa ​

json
// request
{ "mfaToken": "<mfa-jwt>", "code": "123456" }

// response 200
{ "token": "<full-jwt>", "user": { ... } }

Accepts ±1 TOTP window (90 seconds total) and single-use backup codes.

GET /v1/auth/session ​

Validate the stored JWT and return the current user. Called on every page load.

json
{
  "user": {
    "id": "uuid",
    "name": "Dana Whitfield",
    "email": "dana@acme.com",
    "workspaceId": "uuid",
    "workspaceName": "Acme Corp",
    "wsRole": "Owner",
    "emailVerifiedAt": "2025-01-01T00:00:00Z"
  }
}

Returns 401 if the token is invalid, expired, or MFA-pending.

POST /v1/auth/accept-invite ​

Accept a workspace invite. token is from the invite link.

json
// request
{ "token": "a3f9b2..." }

// response 200
{ "token": "<jwt>", "workspaceId": "uuid", "workspaceName": "Acme Corp", "wsRole": "Member" }

POST /v1/auth/switch-workspace ​

Issue a new JWT scoped to a different workspace the caller belongs to.

json
// request
{ "workspaceId": "uuid" }
// response 200
{ "token": "<jwt>", "workspaceId": "uuid", "workspaceName": "Acme Corp" }

Built with SnapEnv