REST API

Auth API

Authenticate users and manage sessions and access tokens.

Generated from the Celerp 2.4.0 OpenAPI schema, 16 September 2026.

POST /auth/api-key

Create Api Key

Responses

StatusDescriptionBody
200Successful Responseobject

Example

curl -X POST http://localhost:8000/auth/api-key \
  -H "Authorization: Bearer $TOKEN"

GET /auth/bootstrap-status

Bootstrap Status

Public endpoint: returns whether the system has been bootstrapped. UI uses this to decide whether to show the first-admin registration wizard (bootstrapped=false) or the normal login screen (bootstrapped=true). Once any user exists, registration is locked out from the public UI.

Responses

StatusDescriptionBody
200Successful Responseobject

Example

curl -X GET http://localhost:8000/auth/bootstrap-status \
  -H "Authorization: Bearer $TOKEN"

POST /auth/change-password

Change Password

Change password for the currently authenticated user.

Request body

FieldTypeRequiredDescription
current_passwordstringyesCurrent Password
new_passwordstringyesNew Password

Responses

StatusDescriptionBody
200Successful Responseobject
422Validation ErrorHTTPValidationError

Example

curl -X POST http://localhost:8000/auth/change-password \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ ... }'

POST /auth/login

Login

Request body

FieldTypeRequiredDescription
emailstringyesEmail
passwordstringyesPassword

Responses

StatusDescriptionBody
200Successful Responseobject
422Validation ErrorHTTPValidationError

Example

curl -X POST http://localhost:8000/auth/login \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ ... }'

POST /auth/login-force

Login Force

Like /login but evicts all other active sessions from the tracker first.

Request body

FieldTypeRequiredDescription
emailstringyesEmail
passwordstringyesPassword

Responses

StatusDescriptionBody
200Successful Responseobject
422Validation ErrorHTTPValidationError

Example

curl -X POST http://localhost:8000/auth/login-force \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ ... }'

POST /auth/logout

Logout

Revoke the caller's session, then rotate their nonce so every existing access AND refresh token for this user is immediately rejected. Accepts EITHER a current access token (Authorization header) or a current v2 refresh token (JSON body), so a browser whose access cookie has expired but whose refresh cookie is still live can still log out server-side (F3). Revocation only happens after the presented credential's snonce is confirmed current under the ``UserAuthState`` row lock: a stale credential cannot rotate a newer session generation, and logout stays idempotent (always 200).

Request body

LogoutRequest, optional

Responses

StatusDescriptionBody
200Successful Responseobject
422Validation ErrorHTTPValidationError

Example

curl -X POST http://localhost:8000/auth/logout \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ ... }'

GET /auth/my-companies

My Companies

List all companies the current user has access to.

Responses

StatusDescriptionBody
200Successful Responseobject

Example

curl -X GET http://localhost:8000/auth/my-companies \
  -H "Authorization: Bearer $TOKEN"

POST /auth/password-reset/confirm

Password Reset Confirm

Confirm password reset with token and new password.

Request body

FieldTypeRequiredDescription
tokenstringyesToken
new_passwordstringyesNew Password

Responses

StatusDescriptionBody
200Successful Responseobject
422Validation ErrorHTTPValidationError

Example

curl -X POST http://localhost:8000/auth/password-reset/confirm \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ ... }'

POST /auth/password-reset/request

Password Reset Request

Request a password reset link. Always returns 200 (prevents user enumeration).

Request body

FieldTypeRequiredDescription
emailstringyesEmail

Responses

StatusDescriptionBody
200Successful Responseobject
422Validation ErrorHTTPValidationError

Example

curl -X POST http://localhost:8000/auth/password-reset/request \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ ... }'

POST /auth/register

Register

Register first admin. Locked out after bootstrap (any user exists). A transaction-scoped advisory lock serializes concurrent first-admin registrations so exactly one wins: the second caller blocks until the first transaction finishes, then re-checks whether an owner exists. Core bootstrap rows and direct seed data commit once through the central token issuer, so those changes are all-or-nothing. Module lifecycle hooks retain their existing best-effort policy; the one-time setup code is consumed only after commit.

Request body

FieldTypeRequiredDescription
company_namestringyesCompany Name
emailstringyesEmail
namestringyesName
passwordstringyesPassword
setup_codestring, optional--Setup Code

Responses

StatusDescriptionBody
200Successful Responseobject
422Validation ErrorHTTPValidationError

Example

curl -X POST http://localhost:8000/auth/register \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ ... }'

POST /auth/switch-company/{company_id}

Switch Company

Switch the active company. Returns a new JWT scoped to the target company. Only succeeds if the user has an active entry in user_companies for that company.

Parameters

NameInRequiredTypeDescription
company_idpathyesstring--

Responses

StatusDescriptionBody
200Successful Responseobject
422Validation ErrorHTTPValidationError

Example

curl -X POST http://localhost:8000/auth/switch-company/:company_id \
  -H "Authorization: Bearer $TOKEN"

POST /auth/token/refresh

Refresh Token

Exchange a valid refresh token for a new access token + rotated refresh token. Fully DB-authoritative: the refresh token is decoded strictly (v2, type, non-empty snonce), then re-bound to current DB state - active user, active membership, company-validity rule, and exact nonce equality. The new pair's role and email come from current DB membership, never from the refresh JWT. Every failure mode returns the same neutral "Invalid refresh token" so the caller learns nothing about which element failed.

Request body

FieldTypeRequiredDescription
refresh_tokenstringyesRefresh Token

Responses

StatusDescriptionBody
200Successful Responseobject
422Validation ErrorHTTPValidationError

Example

curl -X POST http://localhost:8000/auth/token/refresh \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ ... }'