This page lists the credentials and HTTP headers that the Cluster ERP API reads and writes, at the level a client developer needs to call it. It covers tenant users, the operator console, and the token-based supplier portal and signup routes. The design of sessions and tokens is explained in Authentication and sessions; this page does not repeat it and does not describe internal checks beyond their results.
Credentials¶
| Credential | Carried in | Used by | Source |
|---|---|---|---|
| Access token | Authorization: Bearer header |
desktop client and scripts; every route that depends on get_current_user or require_permission |
src/cluster_erp/modules/auth/session_cookies.py:63-75 |
| Access cookie | HttpOnly cookie cluster_access, with the __Host- prefix over TLS |
web client after a cookie-transport sign-in | src/cluster_erp/modules/auth/session_cookies.py:35, src/cluster_erp/modules/auth/session_cookies.py:51-55 |
| Refresh token | JSON body of POST /api/v1/auth/refresh |
desktop client and scripts | src/cluster_erp/modules/auth/login/schemas.py:41-44 |
| Refresh cookie | HttpOnly cookie cluster_refresh, path /api/v1/auth |
web client | src/cluster_erp/modules/auth/session_cookies.py:36-39, src/cluster_erp/modules/auth/session_cookies.py:145-153 |
| Operator token | Authorization: Bearer header on /api/v1/vendor/* |
operator console; separate from tenant tokens | src/cluster_erp/server/routes/vendor.py:84-95 |
| Portal token | path segment {token} |
supplier portal routes under /api/v1/procurement/portal/rfqs/ |
src/cluster_erp/modules/procurement/purchase_rfqs/portal_routes.py:34-64 |
| Signup token | JSON body field signup_token or verify_token |
signup status, resend, cancel, and verify | src/cluster_erp/server/routes/signup.py:102-112 |
A well-formed Bearer header wins over the access cookie; a Bearer value of null or undefined is ignored (src/cluster_erp/modules/auth/session_cookies.py:63-75).
Sign-in and token refresh¶
The sequence shows the tenant user flow at mechanism level. The web client asks for the cookie transport; the desktop client and scripts use the body transport.
sequenceDiagram participant Client participant Login as POST /auth/login participant Refresh as POST /auth/refresh participant Route as Protected route Client->>Login: LoginRequest, optional X-Token-Transport cookie Login-->>Client: LoginResponse with tokens, or empty tokens and Set-Cookie Client->>Route: Bearer header or access cookie Route-->>Client: 200, or 401 AUTH_TOKEN_EXPIRED Client->>Refresh: refresh token in body or refresh cookie Refresh-->>Client: new access and refresh token pair Client->>Route: retry with the new access token
| Step | Behaviour | Source |
|---|---|---|
| Sign-in request | LoginRequest carries username, password, and remember_me. |
src/cluster_erp/modules/auth/login/schemas.py:8-13 |
| Failed sign-in | Answers 401 with AUTH_INVALID_CREDENTIALS. Repeated failures lock the account for a period, and a per-client attempt budget answers 429 with AUTH_TOO_MANY_ATTEMPTS. |
src/cluster_erp/modules/auth/login/routes.py:71-97, src/cluster_erp/modules/auth/login/routes.py:136-180 |
| Sign-in response | LoginResponse carries access_token, refresh_token, token_type, user, and permissions. With the cookie transport the two token fields are empty strings and the tokens are set as cookies. |
src/cluster_erp/modules/auth/login/schemas.py:16-21, src/cluster_erp/modules/auth/login/routes.py:214-257 |
| Session length | Without remember_me, a cookie-transport session gets session cookies and a session end of jwt_session_hours. |
src/cluster_erp/modules/auth/login/routes.py:219-226, src/cluster_erp/modules/auth/session_cookies.py:124-153 |
| Refresh | The presented refresh token is spent and a new pair is issued; the response mirrors the transport of the request. | src/cluster_erp/modules/auth/login/routes.py:260-370 |
| Sign-out | POST /api/v1/auth/logout revokes the presented tokens, stamps last_logout_at, clears the cookies, and answers 204. |
src/cluster_erp/modules/auth/login/routes.py:373-432 |
| Current user | GET /api/v1/auth/me returns MeResponse with user and permissions. |
src/cluster_erp/modules/auth/login/routes.py:434-459 |
Token lifetimes come from the settings jwt_access_expire_minutes, jwt_refresh_expire_days, and jwt_session_hours (src/cluster_erp/config/settings.py:307-312). The values are described in Settings reference.
Request headers¶
| Header | Purpose | When required | Source |
|---|---|---|---|
Authorization |
Bearer access token, or operator token on /api/v1/vendor/* |
every protected route when no access cookie is sent | src/cluster_erp/modules/auth/session_cookies.py:63-75 |
Cookie |
access and refresh cookies of the web client | cookie transport | src/cluster_erp/modules/auth/session_cookies.py:63-84 |
X-Token-Transport |
value cookie asks sign-in to set cookies instead of returning tokens |
sign-in from a browser | src/cluster_erp/modules/auth/session_cookies.py:31-43 |
X-Requested-With |
must equal CSRF_VALUE on every cookie-authenticated request whose method is not GET, HEAD, or OPTIONS; otherwise 403 AUTH_CSRF_HEADER_MISSING |
cookie transport writes and refresh | src/cluster_erp/modules/auth/session_cookies.py:33-34, src/cluster_erp/modules/auth/session_cookies.py:112-121 |
X-Tenant-Domain |
the sign-in mail domain, used to route a request to its tenant when no signed token carries a tenant claim | multi-tenant mode, before sign-in | src/cluster_erp/server/dependencies.py:138-148 |
Accept-Language |
the first two letters select the language of label texts; default en |
optional; read by 49 dependency uses of get_language |
src/cluster_erp/server/dependencies.py:247-249 |
X-Deact-Reason, X-Deact-Note |
URL-encoded reason and note stamped onto a record that a DELETE deactivates |
optional on deactivation requests | src/cluster_erp/server/dependencies.py:63-72 |
X-Session-Id, X-Correlation-Id |
written into the database session settings for audit; a correlation id is generated when absent | optional | src/cluster_erp/server/dependencies.py:34-63 |
If-None-Match |
revalidation of GET /api/v1/_meta; a match answers 304 |
optional | src/cluster_erp/server/app.py:1553-1555 |
Accept-Encoding |
gzip selects the pre-compressed metadata body |
optional | src/cluster_erp/server/app.py:1544-1552 |
Content-Length |
compared with max_request_body_bytes; a larger value answers 413 |
every request with a body | src/cluster_erp/server/app.py:1396-1411 |
Origin |
cross-origin access is granted only to configured console origins and only on /api/v1/vendor/fleet |
operator console in a browser | src/cluster_erp/server/app.py:1362-1388 |
Response headers¶
| Header | When | Source |
|---|---|---|
Set-Cookie |
sign-in and refresh with the cookie transport; deletion on sign-out | src/cluster_erp/modules/auth/session_cookies.py:124-158 |
ETag, Cache-Control: private, no-cache, Vary |
GET /api/v1/_meta |
src/cluster_erp/server/app.py:1546-1556 |
Content-Security-Policy, X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy |
every response | src/cluster_erp/server/app.py:1412-1421 |
Strict-Transport-Security |
responses to HTTPS requests | src/cluster_erp/server/app.py:1426-1429 |
Retry-After: 2 |
an unhandled-error response with status 503 |
src/cluster_erp/server/error_handler.py:309 |
Access-Control-Allow-Origin and related |
/api/v1/vendor/fleet for a configured console origin |
src/cluster_erp/server/app.py:1365-1388 |
Tenant selection¶
When multi_tenant is off, every request uses the process database (src/cluster_erp/server/dependencies.py:117-118). When it is on, get_db_session resolves the tenant from the signed tenant claim of the presented token, then from the X-Tenant-Domain header. A request that resolves to no active tenant gets one generic 401 with AUTH_TENANT_UNRESOLVED (src/cluster_erp/server/dependencies.py:104-157). The model is explained in Multi-tenancy.
Permission checks¶
require_permission(*codes) is a dependency that resolves the user and requires every listed code; a missing code answers 403 with AUTH_PERMISSION_DENIED and details.required_permission (src/cluster_erp/modules/auth/guards.py:205-240, src/cluster_erp/core/errors.py:388-394). For each code it also evaluates the attribute policies configured for that code. Codes listed in the setting abac_strict_permission_codes are denied when no policy exists (src/cluster_erp/modules/auth/guards.py:216-235, src/cluster_erp/config/settings.py:341). Some routes check the signed-in user inside the handler instead, with get_current_user; the module pages name the guard of every route. Roles and policies are explained in Roles and permissions and ABAC policies.
Terms introduced¶
| Term | Code identifier | Definition | Turkish term | Source |
|---|---|---|---|---|
| cookie transport | TRANSPORT_COOKIE |
The web sign-in mode in which the tokens travel only as HttpOnly cookies instead of in the response body. | çerez taşıması | src/cluster_erp/modules/auth/session_cookies.py:31-32 |
| operator token | require_operator |
The Bearer token of an operator console account, read only by the /api/v1/vendor routes. |
operatör belirteci | src/cluster_erp/server/routes/vendor.py:84-95 |
| portal token | token |
The path segment that identifies a supplier's RFQ invitation on the supplier portal routes. | portal belirteci | src/cluster_erp/modules/procurement/purchase_rfqs/portal_routes.py:34 |
Related pages¶
Verified against commit 92f8051 on 2026-11-13.