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
| Parameter | In | Type | Required |
|---|---|---|---|
id | path | string (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
| Parameter | In | Type | Required |
|---|---|---|---|
provider | path | "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
| Parameter | In | Type | Required |
|---|---|---|---|
provider | path | string | Yes |
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
| Parameter | In | Type | Required |
|---|---|---|---|
mode | query | "login" | "signup" | "link" | No |
redirect | query | string | No |
provider | path | "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
| Parameter | In | Type | Required |
|---|---|---|---|
code | query | string | No |
state | query | string | No |
error | query | string | No |
error_description | query | string | No |
provider | path | "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}
| Parameter | In | Type | Required |
|---|---|---|---|
id | path | string | Yes |
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.