Skip to content
Docs
opendesk.shOpen app

Account and auth

Sign in, sessions, two-factor authentication and your own user account.

These endpoints act on the signed-in user, not a workspace, so they do not take OD-Workspace. They are for user sessions; API keys cannot use them.

Method Path Description
GET /v1/auth/config Providers, password login, sign-up and challenge settings
POST /v1/auth/register {email, password, name, turnstile_token?}
POST /v1/auth/login {email, password, turnstile_token?}
POST /v1/auth/mfa {mfa_token, code}
POST /v1/auth/refresh {user_id?} + the account’s refresh cookie → new access token, rotates that account’s refresh token
POST /v1/auth/accounts The accounts this browser is signed in to, with their workspaces. Rotates nothing
POST /v1/auth/logout Revokes this account’s session in the browser and closes its sockets; {all: true} for every account
POST /v1/auth/password/forgot {email}, always 204
POST /v1/auth/password/reset {token, password}
POST /v1/auth/email/verify {token}
POST /v1/auth/email/resend
GET /v1/auth/oauth/{provider}/start?redirect_to= Redirects to Google, Microsoft, GitHub or OIDC
GET /v1/auth/oauth/{provider}/callback Redirects to APP_URL/auth/callback?code=
POST /v1/auth/oauth/exchange {code, code_verifier?} → access token, or mfa_required. The verifier is required for a code from a native sign-in
POST /v1/auth/app-attest/challenge {} → {challenge}, single use, five minutes. For the iPhone app’s App Attest
POST /v1/auth/app-attest/keys {key_id, attestation, challenge} → 204. Registers an attested key
Terminal window
curl https://api.opendesk.sh/v1/auth/config
{ "providers": [{ "id": "google", "name": "Google" }], "password_login": true, "signup_enabled": true, "turnstile_site_key": "0x4AAA..." }

/v1/auth/config also has native: { app_attest, push, relay_url } for the native apps: whether App Attest is accepted, and the push mode (direct, relay or off).

Login, registration and password reset are rate limited and protected by a Turnstile challenge when one is configured; a native iPhone client may send an App Attest proof instead. Native clients receive the refresh token in the body rather than a cookie: see Native apps. Login gives the same answer, in the same time, for an unknown email and a wrong password.

Method Path Description
POST /v1/auth/totp/setup → {secret, otpauth_url}
POST /v1/auth/totp/enable {code} → {recovery_codes}
POST /v1/auth/totp/disable {code}

A code can be used only once. Recovery codes are single use.

Method Path Description
GET /v1/me { user, memberships }
PATCH /v1/me {name?, avatar_url?}
POST /v1/me/password {current_password, new_password}
GET /v1/me/sessions Your sessions, with current marking this one and client (web, desktop or ios)
DELETE /v1/me/sessions/{id} Revoke a session
GET /v1/me/devices Phones registered for push notifications
POST /v1/me/devices {platform: "ios", token? or relay_token?, environment, app_version, name}: register this phone, bound to the calling session
PATCH /v1/me/devices/{id} {muted_types?}: notification types this phone does not get, on top of your notification preferences
DELETE /v1/me/devices/{id} Remove a phone
DELETE /v1/me {password?, code?}: delete your account
type User = { id: string; email: string; name: string; avatar_url: string; email_verified: boolean; totp_enabled: boolean; created_at: string };
type Membership = { workspace: Workspace; role: Role };

A device belongs to the session that registered it: signing out or revoking that session removes it. See Push notifications.

Method Path Description
GET /v1/me/notification-preferences Your preferences in the workspace named by OD-Workspace
PATCH /v1/me/notification-preferences {email_cadence?, digest_hour?, timezone?, paused_until?, types?: [{type, email?, push?, desktop?}]}
POST /v1/me/notification-preferences/test Send yourself a sample notification email (5 an hour)
POST /v1/notifications/unsubscribe Public. {token} from a notification email: turns off that workspace’s notification emails
type NotificationPreferences = {
email_cadence: "instant" | "hourly" | "daily" | "off"; digest_hour: number; timezone: string; paused_until: string | null;
email: string; email_verified: boolean; delay_minutes: number;
types: { type: string; group: "tickets" | "team" | "ai_billing"; email: boolean; push: boolean; desktop: boolean;
defaults: { email: boolean; push: boolean; desktop: boolean } }[];
};

Channels (email, push for your phones, desktop for the desktop app) are chosen per type and per workspace. The email schedule and the pause apply to your whole account. With instant, an unread notification is emailed after delay_minutes, together with anything else waiting for you in that workspace; a notification you read first is never emailed. Notification emails carry a one-click unsubscribe (RFC 8058).

Passwords are 12 to 128 characters and are refused if they appear in a list of breached passwords. Deleting your account is refused while you are the only owner of a workspace that has other members.

Edit this page on GitHub