Authentication
Cookie-based JWT sessions, refresh and logout.
Authentication is cookie based. Tokens are issued as HttpOnly cookies so client-side JavaScript never handles them.
How sessions work
| Field | Type | Description |
|---|---|---|
| access | string | HttpOnly cookie. 5 minute lifetime. Sent automatically with every request. |
| refresh | string | HttpOnly cookie. 7 day lifetime. Exchanged for a new pair. |
| Rotation | string | Refresh tokens are rotated on use and the previous value is blacklisted. |
| SameSite | string | Lax, which blocks cross-site POST requests while allowing top-level navigation. |
Sign up
/api/auth/signup/PublicCreates a user and immediately issues the session cookies.
curl -X POST https://api.introzen.com/api/auth/signup/ \
-H "Content-Type: application/json" \
-c cookies.txt \
-d '{"email": "owner@acme.com", "password": "<strong-password>"}'{
"user": {
"id": 12,
"first_name": "",
"last_name": "",
"email": "owner@acme.com",
"is_active": true,
"is_staff": false,
"date_joined": "2026-10-04T09:12:44.512Z"
}
}Sign in
/api/auth/login/PublicValidates credentials and sets a fresh pair of cookies.
Body
| Field | Type | Description |
|---|---|---|
| string | Account email address. | |
| password | string | Account password. |
Refresh
/api/auth/token/refresh/PublicReads the refresh cookie and issues a new access cookie. When rotation is enabled a new refresh cookie is issued as well.
Session status
/api/auth/session_status/Auth requiredTells the frontend where the user is in the onboarding funnel. This is what routes a new account to workspace setup instead of the dashboard.
status values
| Field | Type | Description |
|---|---|---|
| UNAUTHORIZED | string | No valid session. Send the user to sign in. Answered as a 200, because it is one of this endpoint's answers rather than an error. |
| CREATE_TENANT | string | Authenticated but has no workspace yet. |
| SUBSCRIBE_PLAN | string | Workspace exists but has no active plan. |
| ACCESS_GRANTED | string | Fully onboarded. Load the dashboard. |
Password recovery
Recovery is a two-step flow. The request step never reveals whether an address is registered, and the confirm step accepts a link only once.
/api/auth/password-reset/PublicAccepts an email address and always answers 200 with the same body. When the address belongs to an active account, a reset link is emailed to it.
Body
| Field | Type | Description |
|---|---|---|
| string | Address that should receive the reset link. |
/api/auth/password-reset/confirm/PublicCompletes the reset. The new password is validated against the configured password policy, and every existing refresh token for the account is revoked.
Body
| Field | Type | Description |
|---|---|---|
| uid | string | Base64 user identifier taken from the emailed link. |
| token | string | Single-use token taken from the emailed link. |
| password | string | Replacement password. Minimum 8 characters, checked against the password validators. |
# 1. Ask for a reset link (always 200, even for unknown addresses)
curl -X POST https://api.introzen.com/api/auth/password-reset/ \
-H "Content-Type: application/json" \
-d '{"email": "owner@acme.com"}'
# 2. Exchange the uid and token from the email for a new password
curl -X POST https://api.introzen.com/api/auth/password-reset/confirm/ \
-H "Content-Type: application/json" \
-d '{"uid": "<uid>", "token": "<token>", "password": "<new-password>"}'
# 3. Sign in again: previous sessions and refresh tokens no longer work
curl -X POST https://api.introzen.com/api/auth/login/ \
-H "Content-Type: application/json" \
-c cookies.txt \
-d '{"email": "owner@acme.com", "password": "<new-password>"}'Sign out
/api/auth/logout/Auth requiredBlacklists the refresh token and clears both cookies.
Last reviewed October 2026.