Session cookies
- Create –
POST /api/auth/loginwith{ email, password, remember }. Whenrememberistrue, a long-lived JWT is written to thetokencookie. Otherwise the cookie lasts for the current browser session. - Check status –
GET /api/authreturnsstatusplus the decoded JWT payload when signed in. Responses includeemail_not_verifiedand2fa_requiredstates so you can prompt users accordingly. - Invalidate –
GET /api/auth/logoutwipes the cookie.
Email verification workflow
Some endpoints callauth({ requireEmailVerification: true }), which means unverified accounts will be rejected with HTTP 400. Use the following flow:
POST /api/auth/verify/requestwhile signed in. Optionally includereturnUrlto control where the CTA in the email sends users.- Users receive a JWT-backed link. Send the
tokentoPOST /api/auth/verify/submit. - On success, the API replies with
{ status: "ok", token }and refreshes thetokencookie.
Password reset workflow
POST /api/auth/reset/requestwith{ email, returnUrl? }. Browsary emails a short-lived JWT.POST /api/auth/reset/submitwith{ token, password, confirmPassword }. The response mirrors the login response and refreshes the cookie.
Two-factor authentication
All 2FA endpoints require an email-verified session.| Endpoint | Purpose |
|---|---|
POST /api/auth/2fa/enable/request | Returns { status: "2fa_setup", url, secret }. url is a TOTP URI you can encode as a QR code. |
POST /api/auth/2fa/enable/submit | Confirms the authenticator by sending { token } (the current TOTP). Response refreshes the cookie. |
POST /api/auth/2fa/verify | Called after login when the API reported 2fa_required. |
POST /api/auth/2fa/reset | Revokes the previous secret after the user proves ownership with the current TOTP code. |
API keys
- Endpoints – CRUD lives under
/api/api-keysand/api/api-keys/{id}. - Delivery – send keys via
x-api-keyorAuthorization: ApiKey <value>.Authorization: Bearer <value>also works if your tooling only supports bearer schemes. - Scopes –
accessTypecontrols what the key can see:full: inherits the owner’s permissions.projects: allow list of project IDs or slugs provided viaprojectIds.custom: supply explicit permission strings (e.g.marketing.pipelines.read).
- Lifecycle – the API only shows the full
secreton creation; subsequent reads expose metadata plus the prefix.
External provider linking
OpenID Connect providers defined inOPENID_PROVIDERS unlock an external account linking flow:
GET /api/auth/external/providerslists supported providers (google,github, etc.).- Signed-in users call
GET /api/auth/external/{provider}/init, which redirects them to the provider and stores PKCE state in cookies. - The provider calls back into
GET /api/auth/external/{provider}/redirect. Browsary either links the provider to the signed-in user, logs in the existing linked account, or redirects to/auth/external-register/<token>to finish onboarding. - Use
GET/DELETE /api/auth/external/{provider}to inspect or unlink accounts.
Shared-secret integrations
Some system-level endpoints use dedicated middleware instead of user identity:- Coordinator – all
/api/coordinator/<token>/*routes requiretoken === process.env.COORDINATOR_TOKEN. - External sessions –
/api/external-sessionand/api/external-session/{id}/capturerequireAuthorization: Bearer <EXTERNAL_TOKEN>or a?token=query string.