Appearance
auth
20 endpoints at a glance
| Method | Path | Summary |
|---|---|---|
POST | /auth/2fa/disable | Disable 2Fa |
POST | /auth/2fa/enable | Enable 2Fa |
POST | /auth/2fa/enroll | Enroll 2Fa |
POST | /auth/2fa/recovery-codes | Regenerate Recovery Codes |
GET | /auth/config | Auth Config |
POST | /auth/login | Login |
POST | /auth/login/2fa | Login 2Fa |
POST | /auth/logout | Logout |
GET | /auth/me | Me |
PATCH | /auth/me | Update Me |
POST | /auth/me/password | Change Password |
DELETE | /auth/me/self-contact | Clear Self Contact |
PUT | /auth/me/self-contact | Set Self Contact |
POST | /auth/register | Register |
GET | /auth/users/ | List Users |
POST | /auth/users/ | Create User |
DELETE | /auth/users/{username} | Delete User |
PATCH | /auth/users/{username} | Update User |
POST | /auth/users/{username}/password | Admin Reset Password |
GET | /auth/users/lookup | Lookup Users |
auth
Auth Config
GET
/auth/config
Public auth-flow flags the SPA reads at boot.
Anonymous-readable so the login + register views can adjust their
chrome (hiding the sign-up link when registration is closed) without
a round-trip to a protected endpoint.
Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
Login
POST
/auth/login
Verify credentials, set the session cookie, return the user.
Generic 401 on any failure — never leak whether the username exists.
When the account has 2FA enabled, the password check is only step one:
instead of a session we return {"mfa_required": true, "mfa_token": …}
and set a short-lived challenge cookie. No session is issued and
last_login is not stamped until the code step succeeds. Accounts
without 2FA get exactly the response shape they always have, so
existing clients (incl. the Swift app) are unaffected unless a user
opts in.
Request Body
application/json
JSON "username": "string", "password": "string"
{
}
Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
Login 2Fa
POST
/auth/login/2fa
Complete login: verify a TOTP code (or a recovery code), open session.
The challenge is read from (in order) the request body, the
kancil_mfa cookie, or an Authorization: Bearer header — so both
the SPA and native clients work. A 6-digit input is checked as TOTP; any
other input is tried as a single-use recovery code. Consecutive bad
codes are rate-limited per :data:TOTP_MAX_ATTEMPTS.
Parameters
Header Parameters
authorization
Request Body
application/json
JSON "code": "string", "mfa_token": "string"
{
}
Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
Register
POST
/auth/register
Self-serve signup. Creates a viewer and auto-logs in.
Admins are still admin-created via POST /auth/users/ —
self-registration intentionally has no role field on the wire.
Gated by KANCIL_REGISTRATION_ENABLED; when False, returns 403
(so the SPA can render a friendly "signups are closed" message
rather than a confusing 404).
Request Body
application/json
JSON "username": "string", "password": "string"
{
}
Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
Logout
Me
Update Me
Lookup Users
GET
/auth/users/lookup
Public user search for any authenticated caller.
Used by the MembersEditor autocomplete. Returns only username +
role so the caller can render a chip; preferences and last_login
stay restricted to the admin /users/ endpoint.
Empty q returns the most recent users — convenient default for
"open the picker and see what's there".
Parameters
Header Parameters
authorization
Query Parameters
q
Type
string
Default
""limit
Type
integer
Default
10Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
Set Self Contact
PUT
/auth/me/self-contact
Designate which contact card represents the logged-in user.
Stored in preferences.self_contact so it round-trips through
/auth/me. Validates the contact is actually one of the user's own
and caches its display name for the "Add myself" affordance.
Parameters
Header Parameters
authorization
Request Body
application/json
JSON "addressbook_id": "string", "uid": "string"
{
}
Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
Clear Self Contact
Change Password
Enroll 2Fa
POST
/auth/2fa/enroll
Begin enrollment: mint a fresh secret, return its QR + otpauth URI.
The secret is stored pending (encrypted) and is not active until
:func:enable_2fa verifies a code from it. Calling this again before
enabling simply rolls a new pending secret; any live 2FA stays intact.
Parameters
Header Parameters
authorization
Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
Enable 2Fa
POST
/auth/2fa/enable
Finish enrollment: verify a code, activate 2FA, return recovery codes.
The recovery codes are shown here exactly once — only their hashes are
stored. If the user loses them, they regenerate (invalidating the old
set), they don't get to re-read these.
Parameters
Header Parameters
authorization
Request Body
application/json
JSON "code": "string"
{
}
Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
Disable 2Fa
Regenerate Recovery Codes
POST
/auth/2fa/recovery-codes
Issue a fresh recovery-code set, invalidating the old one.
Requires the password and an already-enabled 2FA. Returns the new
plaintext codes once.
Parameters
Header Parameters
authorization
Request Body
application/json
JSON "password": "string"
{
}
Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}