One API.
Any stack.
Build the interface your users deserve. Connect it to the same small set of HTTPS endpoints.
Open the complete OpenAPI contract ↗
Your first connection
-
Create a developer workspace.
Sign up, verify your email, then sign in. Hostinger email is connected for verification and password-reset messages.
-
Create your application project.
Add a name and the verification and password-reset page URLs you own. Production callbacks require HTTPS. Copy the public project ID.
-
Make an HTTP request.
Send JSON with
X-Project-IDto identify your application. No language-specific SDK is required.POST /v1/auth/signup Content-Type: application/json X-Project-ID: YOUR_PROJECT_ID { "email": "person@example.com", "password": "a long unique password phrase", "username": "Taylor" }A
202response is intentionally generic. It does not directly reveal whether an account already exists. The signup password is provisional; login is blocked until verification. -
Complete verification, then sign in.
The email link opens your verification URL with
#token=…. Read the fragment, remove it from the URL, then ask the email owner to choose their final password. POST both values to/v1/auth/email/verify. This replaces the provisional password and cancels sessions and outstanding action links in the same transaction.POST /v1/auth/email/verify Content-Type: application/json X-Project-ID: YOUR_PROJECT_ID { "token": "TOKEN_FROM_THE_EMAIL_FRAGMENT", "password": "FINAL_PASSWORD_CHOSEN_BY_THE_EMAIL_OWNER" }Success returns
{"email_verified":true}. A token without a password is rejected. -
Log in and check the session.
POST email and the final password to
/v1/auth/login. The response has this shape; these are example values:{ "session_token": "ca_s_RANDOM_PRIVATE_TOKEN", "token_type": "Bearer", "expires_at": "2030-01-02T12:00:00Z", "user": { "id": "11111111-1111-4111-8111-111111111111", "email": "person@example.com", "username": "Taylor", "email_verified": true, "created_at": "2030-01-01T12:00:00Z" } }GET
/v1/mewithX-Project-IDandAuthorization: Bearer SESSION_TOKENto validate the session. It returns the user object directly, without auserwrapper. On401, renewable clients may refresh once as described below; otherwise require login. If validation is unavailable, fail closed.
Stay signed in, using the same API
Add "renewable": true to the login JSON. Omit it to keep the existing fixed 24-hour session. Renewable login returns the normal user/access fields plus refresh_token, refresh_expires_at and session_expires_at.
POST /v1/auth/refresh
Content-Type: application/json
X-Project-ID: YOUR_PROJECT_ID
{"refresh_token":"CURRENT_PRIVATE_REFRESH_TOKEN"}
Use the current refresh token once, then replace both saved tokens and expiry values atomically. No access token or server API key is needed for this request. The session ID stays the same, and the old access token immediately stops working. Only one refresh may run per session, including across tabs or backend replicas.
Default limits are 15-minute access, seven days without renewal and 30 days total from login. In Project Settings, choose access of 5–60 minutes, inactivity of 1–90 days and total lifetime of 1–365 days. Inactivity cannot exceed total lifetime. Settings apply to new logins and future refresh checks; they never extend a family’s original absolute maximum.
A consumed refresh token cannot be used again: replay cancels the whole session family. If the refresh response is lost or times out, require login instead of automatically trying the old token again. A refresh 401 also requires login. Logout, password recovery and account disabling cancel access and renewal together.
For browser apps, your backend keeps both secrets. Native apps use Keychain/Keystore or equivalent secure storage. The ComfyAuth portal uses HttpOnly cookies with cross-tab Web Locks; without Web Locks it requires login again after access expiry. This is a custom HTTPS/JSON API, not OAuth/OIDC.
A clear path from UI to identity
For browsers, keep the ComfyAuth bearer token on your server and use a secure, HttpOnly session cookie for your own UI. Native apps can use secure operating-system storage. Never store an administrative API key in browser or mobile code.
Direct browser API calls require an exact allowed origin. Include
?project_id=YOUR_PROJECT_ID as well as the matching
header for CORS preflight routing. Browser token storage remains
your responsibility; a server-backed integration is recommended.
Use the same requests on every platform. Browser backends keep the bearer token private; native apps keep it in secure OS storage. Allow a bounded 60-second client timeout for the Vercel deployment: email requests can include delivery attempts. Do not automatically retry single-use token actions after an uncertain timeout.
The API surface
All routes are relative to this deployment. Requests use
Content-Type: application/json and
X-Project-ID. Authenticated calls also send
Authorization: Bearer SESSION_TOKEN.
| Method | Endpoint | Body / purpose |
|---|---|---|
| POST | /v1/auth/signup | email, password, optional username |
| POST | /v1/auth/login | email, password |
| POST | /v1/auth/refresh | Rotate renewable access and refresh credentials |
| POST | /v1/auth/email/verification-request | |
| POST | /v1/auth/email/verify | token, final password chosen by the email owner |
| POST | /v1/auth/password/reset-request | |
| POST | /v1/auth/password/reset | token, password |
| POST | /v1/auth/password/change | current_password, new_password |
| GET | /v1/me | Current verified user |
| GET | /v1/sessions | Active account sessions |
| DELETE | /v1/sessions/{id} | Revoke one session |
| POST | /v1/auth/logout | Revoke current session |
| POST | /v1/auth/logout-all | Revoke all account sessions |
| POST | /v1/admin/users/{id}/disable | Server API key required |
Handling responses
400 invalid input or link · 401 invalid
credentials or session · 404 missing resource ·
429 rate limited · 503 temporarily
unavailable. Respect Retry-After when provided. Errors
contain error.code and error.message.
Several users may share one application backend. Public traffic
has project capacity budgets and per-account controls, without an
extra login key or arbitrary forwarded-IP headers. Defaults include
1,200 requests/minute per project/source IP and 10 login attempts
per account per 15 minutes. These are ceilings, not guaranteed throughput.
X-Request-ID helps investigate failures.
Security you can inspect
Passwords use Argon2id. Opaque session tokens and single-use action tokens are stored as hashes. Email payloads are encrypted with AES-256-GCM. Production connections use HTTPS and verified PostgreSQL TLS.
Fixed sessions expire after 24 hours; opted-in renewable sessions follow the project’s access, inactivity and absolute limits. Verification links expire after one hour; password reset links after 20 minutes. Password reset, password change, and disabling an account revoke its sessions. Passwords require 15–128 characters and at most 512 bytes.
Portal access is separate from your application users. Ownership is checked on every project operation; mutations also recheck the developer session inside the database transaction. Portal sessions use HttpOnly, Secure, SameSite=Strict cookies and exact-origin checks.
These controls are informed by the OWASP CSRF guidance and browser cookie rules. This early release has not had an independent security audit.
What is available today
Email/password authentication, project management, user access controls, keys, and session revocation are implemented. Hostinger email is connected with a verified sender domain. Developer and customer verification and password-reset flows have passed real email tests in our Hostinger inbox.
Phone, Google, Apple, passkeys, MFA, team roles, billing, and OAuth/OIDC interoperability are not implemented yet. This is a custom HTTPS authentication API. Existing CLI projects are not automatically assigned to a developer.
Workspaces support up to 100 projects and 20 active server keys per project. Key lists include every active key and up to 80 recent revoked keys. User lists are paginated; activity shows the latest 100 events, retained for 90 days. Vercel Hobby runs daily cleanup; reliable idle email retries require an external scheduler.
Before public production use, test delivery to external email providers, configure reliable idle retries, complete a backup restore drill and workload tests, and arrange maintained common/compromised-password screening and an independent security review. The current small password denylist needs a maintenance and coverage policy; see NIST password guidance. The successful Hostinger inbox tests do not complete these release checks.
Future Google/Apple identities will link to the same user ID using project, provider, and provider subject. Matching email text will not automatically join accounts. Phone-only login first requires a schema and verification-rule migration because email is required today.