Skip to content

Authentication endpoints

54 endpoints at https://api.vaif.studio, generated from the API's OpenAPI document. The REST API page covers authentication, and All endpoints lists every group.

POST /auth/session/token

Get a short-lived access token for this browser's session (cookie)

Response 200 (application/json)
{
  ok: true;
  accessToken: string;
  expiresIn: number;
  csrfToken: string;
  session: {
    id: string;
    expiresAt: string;
    idleTimeoutSeconds: number;
  };
  user: {
    id: string;
    email: string;
    name?: string | null;
    avatarUrl?: string | null;
    phone?: string | null;
    timezone?: string | null;
    createdAt: string (date-time) | string;
  };
  upgraded?: boolean;
}

Errors: 401, 403, 409, 429, with the error body.

GET /auth/session

Describe the current browser session

Response 200 (application/json)
{
  ok: boolean;
  user: any;
  session: null;
  csrfToken: null;
  canChangeSignInMethods: boolean;
} | {
  ok: boolean;
  user: {
    id: string;
    email: string;
    name: null | string;
    avatarUrl: null | string;
    phone: null | string;
    timezone: null | string;
    createdAt: string (date-time) | string;
  };
  signInMethods: {
    password: boolean;
    mfa: boolean;
  };
  csrfToken: string;
  session: {
    id: string;
    expiresAt: string;
    idleTimeoutSeconds: number;
    createdAt: string;
    lastSeenAt: string;
    authTime: string;
    reauthAt: null | string;
    amr: string[];
  };
  canChangeSignInMethods: boolean;
}

GET /auth/sessions

List this account's signed-in browsers

Response 200 (application/json)
{
  sessions: {
    id: string;
    current: boolean;
    createdAt: string;
    lastSeenAt: string;
    expiresAt: string;
    ip: null | string;
    userAgent: null | string;
    amr: string[];
  }[];
}

DELETE /auth/sessions/{id}

Sign one browser session out

ParameterInTypeRequired
idpathstring (uuid)Yes
Response 200 (application/json)
{
  ok: boolean;
  ended: boolean;
}

POST /auth/logout-all

Sign out everywhere

Response 200 (application/json)
{
  ok: boolean;
  endedSessions: number;
}

POST /auth/session/device

Keep this browser's device id on a referral creator's session

Request body (application/json, required)
{
  deviceId: string (uuid);
}
Response 200 (application/json)
{
  ok: true;
}

Errors: 400, 401, with the error body.

POST /auth/reauthenticate

Confirm it's you before changing how you sign in

Request body (application/json, required)
{
  password?: string;
  code?: string;
}
Response 200 (application/json)
{
  ok: boolean;
  validForSeconds: number;
}

POST /auth/me/linked-accounts/{provider}/start

Start linking a sign-in method — answers the provider URL to open

ParameterInTypeRequired
providerpath"google" | "github" | "microsoft" | "apple"Yes
Response 200 (application/json)
{
  ok: boolean;
  url: string;
}

DELETE /auth/me/linked-accounts/{provider}

Unlink an OAuth provider from the current user's account

ParameterInTypeRequired
providerpathstringYes
Response 200 (application/json)
{
  ok: true;
}

Errors: 400, 401, 403, 404, with the error body.

POST /auth/impersonate/token

Re-mint the memory-only impersonation token from the admin's session cookie

Request body (application/json, required)
{
  sessionId: string (uuid);
}
Response 200 (application/json)
{
  token: string;
  expiresIn: number;
  sessionId: string;
  readOnly: boolean;
  user: {
    id: string;
    email: string;
  };
}

Errors: 401, 403, 404, 429, with the error body.

GET /auth/mfa/status

Response 200 (application/json)
{
  enrolled: boolean;
  enrolledAt: any;
  backupCodesRemaining: number;
}

POST /auth/mfa/enroll-start

Response 200 (application/json)
{
  enrollToken: string;
  otpauthUri: string;
  secret: string;
  expiresInSeconds: number;
}

POST /auth/mfa/enroll-confirm

Request body (application/json)
{
  enrollToken: string;
  code: string;
}
Response 200 (application/json)
{
  ok: boolean;
  backupCodes: string[];
}

POST /auth/mfa/verify

Request body (application/json)
{
  challengeToken: string;
  code: string;
}
Response 200 (application/json)
{
  ok: true;
  accessToken: string;
  expiresIn: number;
  user: {
    id: string;
    email: string;
    name: null | string;
    avatarUrl: null | string;
    phone: null | string;
    timezone: null | string;
    createdAt: string (date-time) | string;
  };
  refreshToken: string;
  usedBackupCode: boolean;
} | {
  ok: true;
  accessToken: string;
  expiresIn: number;
  user: {
    id: string;
    email: string;
    name: null | string;
    avatarUrl: null | string;
    phone: null | string;
    timezone: null | string;
    createdAt: string (date-time) | string;
  };
  refreshToken?: any;
  csrfToken: string;
  session: {
    id: string;
    expiresAt: string;
    idleTimeoutSeconds: number;
  };
  usedBackupCode: boolean;
}

POST /auth/mfa/disable

Request body (application/json)
{
  code: string;
}
Response 200 (application/json)
{
  ok: boolean;
}

POST /auth/mfa/regenerate-codes

Request body (application/json)
{
  code: string;
}
Response 200 (application/json)
{
  ok: boolean;
  backupCodes: string[];
}

POST /auth/sso/start

Response 200

No body.

POST /auth/sso/callback

Response 200

No body.

POST /auth/signup

Register a new user account

Request body (application/json, required)
{
  email: string (email);
  password: string;
  name?: string;
  returnTo?: string;
  turnstileToken?: string;
}
Response 200 (application/json)
{
  ok: true;
  accessToken: string;
  expiresIn: number;
  csrfToken?: string;
  session?: {
    id: string;
    expiresAt: string;
    idleTimeoutSeconds: number;
  };
  user: {
    id: string;
    email: string;
    name?: string | null;
    avatarUrl?: string | null;
    phone?: string | null;
    timezone?: string | null;
    createdAt: string (date-time) | string;
  };
} | {
  ok: true;
  pendingVerification: true;
  message: string;
}

Errors: 400, 403, 429, 500, 503, with the error body.

POST /auth/login

Authenticate with email and password

Request body (application/json, required)
{
  email: string (email);
  password: string;
  returnTo?: string;
}
Response 200 (application/json)
{
  ok: true;
  accessToken: string;
  expiresIn: number;
  csrfToken?: string;
  session?: {
    id: string;
    expiresAt: string;
    idleTimeoutSeconds: number;
  };
  user: {
    id: string;
    email: string;
    name?: string | null;
    avatarUrl?: string | null;
    phone?: string | null;
    timezone?: string | null;
    createdAt: string (date-time) | string;
  };
} | {
  ok: true;
  mfaRequired: true;
  challengeToken: string;
  expiresInSeconds: number;
} | {
  ok: true;
  pendingVerification: true;
  message: string;
}

Errors: 400, 401, 403, 429, with the error body.

POST /auth/refresh

Rotate the refresh token and issue a new access token

Response 200 (application/json)
{
  ok: true;
  accessToken: string;
  expiresIn: number;
  csrfToken?: string;
  session?: {
    id: string;
    expiresAt: string;
    idleTimeoutSeconds: number;
  };
  user: {
    id: string;
    email: string;
    name?: string | null;
    avatarUrl?: string | null;
    phone?: string | null;
    timezone?: string | null;
    createdAt: string (date-time) | string;
  };
}

Errors: 401, 403, with the error body.

GET /auth/me

Get the current authenticated user's profile

Response 200 (application/json)
{
  ok: true;
  user: {
    id: string;
    email: string;
    name?: string | null;
    avatarUrl?: string | null;
    phone?: string | null;
    timezone?: string | null;
    emailVerifiedAt?: string (date-time) | string;
    createdAt: string (date-time) | string;
    updatedAt?: string (date-time) | string;
  };
}

Errors: 401, with the error body.

PATCH /auth/me

Update the current authenticated user's profile

Request body (application/json, required)
{
  name?: string;
  phone?: string | null;
  timezone?: string;
  avatarUrl?: string (uri) | null;
}
Response 200 (application/json)
{
  ok: true;
  user: {
    id: string;
    email: string;
    name?: string | null;
    avatarUrl?: string | null;
    phone?: string | null;
    timezone?: string | null;
    emailVerifiedAt?: string (date-time) | string;
    createdAt: string (date-time) | string;
    updatedAt?: string (date-time) | string;
  };
}

Errors: 400, 401, with the error body.

GET /auth/me/admin

Check whether the current user has admin access

Response 200 (application/json)
{
  ok: true;
  isAdmin: boolean;
  role?: string;
  permissions?: string[];
}

Errors: 401, with the error body.

GET /auth/me/context

Get current user profile, org memberships, and admin status in one call

Response 200 (application/json)
{
  ok: true;
  user: {
    id: string;
    email: string;
    name?: string | null;
    avatarUrl?: string | null;
    phone?: string | null;
    timezone?: string | null;
    emailVerifiedAt?: string (date-time) | string;
    createdAt: string (date-time) | string;
    updatedAt?: string (date-time) | string;
  };
  orgs: {
    orgId: string;
    orgName: string;
    orgSlug: string;
    role: string;
    plan: string;
    founded: boolean;
    hasProjects: boolean;
  }[];
  isAdmin: boolean;
  deviceIdRequested?: true;
  mfaEnrollmentRequired: {
    orgId: string;
    orgName: string;
    orgSlug: string;
  }[];
}

Errors: 401, with the error body.

POST /auth/logout

Invalidate the current session and clear the refresh token cookie

Response 200 (application/json)
{
  ok: true;
}

POST /auth/forgot-password

Request a password reset email

Request body (application/json, required)
{
  email: string (email);
  turnstileToken?: string;
}
Response 200 (application/json)
{
  ok: true;
  message: string;
}

Errors: 400, 429, 503, with the error body.

POST /auth/reset-password

Submit a new password using a reset token

Request body (application/json, required)
{
  token: string;
  password: string;
  code?: string;
}
Response 200 (application/json)
{
  ok: true;
  message: string;
}

Errors: 400, 401, 403, 429, with the error body.

POST /auth/verify-email/send

Send a verification email to the current user's email address

Request body (application/json)
null | {
  returnTo?: any;
}
Response 200 (application/json)
{
  ok: true;
  message: string;
}

Errors: 401, 404, 429, with the error body.

POST /auth/verify-email/confirm

Confirm email address using a verification token

Request body (application/json, required)
{
  token: string;
}
Response 200 (application/json)
{
  ok: true;
  message: string;
}

Errors: 400, 429, with the error body.

POST /auth/verify-email/resend

Send a new verification link to an address or for an expired link (always answers ok)

Request body (application/json, required)
{
  email: string (email);
  returnTo?: string;
} | {
  token: string;
  returnTo?: string;
}
Response 200 (application/json)
{
  ok: true;
}

Errors: 400, 429, with the error body.

POST /auth/reset-password/check

Check a password reset link before the new password is typed (does not use it)

Request body (application/json, required)
{
  token: string;
}
Response 200 (application/json)
{
  status: "valid";
  email: string;
  requires: "none" | "sso" | "mfa";
  orgName?: string;
} | {
  status: "ended";
}

Errors: 429, with the error body.

GET /auth/oauth/{provider}

Initiate OAuth sign-in or sign-up — redirects to provider, or back to the console with an error code

ParameterInTypeRequired
modequery"login" | "signup" | "link"No
redirectquerystringNo
providerpath"google" | "github" | "microsoft" | "apple"Yes
Response 200

No body.

GET /auth/oauth/{provider}/callback

Handle OAuth redirect from provider — redirects to the app with a session or an error

ParameterInTypeRequired
codequerystringNo
statequerystringNo
errorquerystringNo
error_descriptionquerystringNo
providerpath"google" | "github" | "microsoft" | "apple"Yes
Response 200

No body.

GET /auth/me/linked-accounts

List OAuth accounts linked to the current user

Response 200 (application/json)
{
  accounts: {
    id: string;
    provider: string;
    providerEmail?: string | null;
    providerData?: any;
    linkedAt?: string (date-time) | string;
    lastUsedAt?: string (date-time) | string;
  }[];
}

Errors: 401, with the error body.

GET /auth/oauth/providers

List enabled OAuth providers available for login or account linking

Response 200 (application/json)
{
  providers: {
    provider: string;
    name: string;
    allowSignup?: boolean | null;
    allowLinking?: boolean | null;
  }[];
}

POST /auth/cli/authorize

Request a CLI auth session code — returns a code and browser URL for approval

Response 200 (application/json)
{
  code: string;
  url: string;
  expiresIn: number;
}

Errors: 429, with the error body.

POST /auth/cli/token

Poll for CLI auth token after browser approval

Request body (application/json, required)
{
  code: string;
}
Response 200 (application/json)
{
  ok: false;
  status: "pending";
} | {
  ok: true;
  accessToken: string;
  expiresIn: number;
  user: {
    id: string;
    email: string;
    name?: string | null;
  };
}

Errors: 400, 401, 403, 429, with the error body.

POST /auth/cli/requests/check

Check a CLI sign-in request before approving it (pending, or ended)

Request body (application/json, required)
{
  code: string;
}
Response 200 (application/json)
{
  status: "pending";
  createdAt: string;
  expiresAt: string;
} | {
  status: "ended";
}

Errors: 401, 403, with the error body.

POST /auth/cli/callback

Approve a pending CLI auth session from the web app

Request body (application/json, required)
{
  code: string;
}
Response 200 (application/json)
{
  ok: true;
}

Errors: 400, 401, 403, 409, with the error body.

POST /auth/cli/deny

Deny a pending CLI sign-in request from the web app

Request body (application/json, required)
{
  code: string;
}
Response 200 (application/json)
{
  ok: true;
}

Errors: 401, 403, 409, with the error body.

POST /auth/cli/login

Authenticate CLI with email and password (fallback flow)

Request body (application/json, required)
{
  email: string (email);
  password: string;
  returnTo?: string;
}
Response 200 (application/json)
{
  ok: true;
  accessToken: string;
  refreshToken: string;
  expiresIn: number;
  user: {
    id: string;
    email: string;
    name?: string | null;
  };
} | {
  ok: true;
  mfaRequired: true;
  challengeToken: string;
  expiresInSeconds: number;
} | {
  ok: true;
  pendingVerification: true;
  message: string;
}

Errors: 400, 401, 403, 429, with the error body.

POST /auth/impersonate/exchange

Exchange a one-time impersonation code for the impersonation token

Request body (application/json, required)
{
  code: string;
}
Response 200 (application/json)
{
  token: string;
  sessionId?: string;
  user: {
    id: string;
    email: string;
    name: string | null;
  };
}

Errors: 400, 429, with the error body.

POST /auth/account-setup

Request body (application/json)
{
  token: string;
  password: string;
}
Response 200 (application/json)
{
  ok?: true;
  accessToken?: string;
  expiresIn?: number;
  user?: {
    id: string;
    email: string;
    name: null | string;
    avatarUrl: null | string;
    phone: null | string;
    timezone: null | string;
    createdAt: string (date-time) | string;
  };
  refreshToken?: any;
  csrfToken?: string;
  session?: {
    id: string;
    expiresAt: string;
    idleTimeoutSeconds: number;
  };
  redirectTo: string;
}

POST /auth/account-setup/check

Request body (application/json)
{
  token: string;
}
Response 200 (application/json)
{
  status: string;
} | {
  status: string;
  email: string;
  orgName: null | string;
  expiresAt: string;
}

POST /auth/saml/acs/{id}

ParameterInTypeRequired
idpathstringYes
Response 200

No body.

POST /auth/sso/restart

Response 200 (application/json)
{
  ok: boolean;
  domain: string;
}

POST /auth/tenant/sso/start

Start single sign-on with this command center's organization

Request body (application/json, required)
{
  bindingHash: string;
  email?: string (email);
}
Response 200 (application/json)
{
  redirectUrl: string;
}

Errors: 400, 404, 429, 502, with the error body.

POST /auth/tenant/handoff

Finish a single sign-on started on this command center (the hand-off code and this tab's binding)

Request body (application/json, required)
{
  handoff: string;
  binding: string;
}
Response 200 (application/json)
{
  ok: true;
  accessToken: string;
  expiresIn: number;
  csrfToken: string;
  session: {
    id: string;
    expiresAt: string;
    idleTimeoutSeconds: number;
  };
} | {
  ok: true;
  mfaRequired: true;
  challengeToken: string;
  expiresInSeconds: number;
}

Errors: 400, 401, 403, 409, 429, with the error body.

POST /auth/tenant/login

Sign in to this command center with email and password (when single sign-on does not cover the address)

Request body (application/json, required)
{
  email: string (email);
  password: string;
}
Response 200 (application/json)
{
  ok: true;
  accessToken: string;
  expiresIn: number;
  csrfToken: string;
  session: {
    id: string;
    expiresAt: string;
    idleTimeoutSeconds: number;
  };
} | {
  ok: true;
  mfaRequired: true;
  challengeToken: string;
  expiresInSeconds: number;
}

Errors: 400, 401, 403, 429, with the error body.

POST /auth/tenant/mfa/verify

Finish a command center sign-in with an authenticator or backup code

Request body (application/json, required)
{
  challengeToken: string;
  code: string;
}
Response 200 (application/json)
{
  ok: true;
  accessToken: string;
  expiresIn: number;
  csrfToken: string;
  session: {
    id: string;
    expiresAt: string;
    idleTimeoutSeconds: number;
  };
}

Errors: 400, 401, 403, 429, with the error body.

POST /auth/tenant/refresh

Get a short-lived access token for this tenant session (cookie and CSRF token)

Response 200 (application/json)
{
  ok: true;
  accessToken: string;
  expiresIn: number;
  csrfToken: string;
  session: {
    id: string;
    expiresAt: string;
    idleTimeoutSeconds: number;
  };
}

Errors: 401, 403, 429, with the error body.

POST /auth/tenant/logout

Sign out of this tenant's command center only

Response 200 (application/json)
{
  ok: true;
}

Errors: 403, with the error body.

GET /auth/tenant/session

Who is signed in to this command center, their role and how they signed in

Response 200 (application/json)
{
  user: {
    id: string;
    name: string | null;
    email: string;
  };
  orgRole: "owner" | "admin" | "billing";
  amr: ("pwd" | "mfa" | "sso")[];
}

Errors: 401, with the error body.