FabrikFabrik
FabrikAPI Reference

Authentication

Login, token refresh, MFA, password reset, email verification, user and group management — every endpoint under /api/auth/.

All /api/auth/ endpoints. Login is JWT-based via rest_framework_simplejwt; MFA is TOTP with backup codes; admin endpoints are gated by group membership. The full login flow has three optional branches (plain, LDAP, MFA) — pick the one your deployment uses.

Login

POST /api/auth/login/

Plain username + password login. Returns a JWT access/refresh pair.

Request:

{ "username": "alice", "password": "••••••••" }

Response 200:

{
  "access": "eyJ0eXAi...",
  "refresh": "eyJ0eXAi...",
  "user": { "id": 1, "username": "alice", "is_admin": false, "mfa_enabled": false }
}

If the user has MFA enabled, the response is 202 Accepted with { "mfa_required": true, "mfa_token": "..." } — exchange the mfa_token through /api/auth/mfa-login/ to finish.

Rate limited aggressively at the nginx layer (5 rpm per IP).

POST /api/auth/ldap-login/

Same shape as /login/, but authenticates against the configured LDAP directory. Only available when LDAP_ENABLED=true. See LDAP integration for configuration.

POST /api/auth/mfa-login/

Second step when MFA is enabled. Accepts the mfa_token from /login/ plus either a TOTP code or a backup code.

Request:

{ "mfa_token": "…", "code": "123456" }

Response 200: Same JWT envelope as /login/.

POST /api/auth/token/refresh/

Exchange a valid refresh token for a new access token.

Request:

{ "refresh": "eyJ0eXAi..." }

Response 200:

{ "access": "eyJ0eXAi..." }

Rate limited separately — clients that refresh aggressively get throttled before the general user throttle fires.

Access tokens expire after 15 minutes, refresh tokens after 7 days. The frontend refreshes silently in the background when an access token is within 60 seconds of expiry. Your own clients should do the same.

Profile and preferences

GET /api/auth/profile/

Returns the full profile for the authenticated user.

Response 200:

{
  "id": 1,
  "username": "alice",
  "email": "alice@example.com",
  "first_name": "Alice",
  "last_name": "Chen",
  "group_names": ["Operators"],
  "is_admin": false,
  "is_superuser": false,
  "email_verified": true,
  "mfa_enabled": false,
  "query_count": 42,
  "favorite_count": 8,
  "date_joined": "2026-01-15T09:00:00Z",
  "last_login": "2026-04-22T08:15:00Z",
  "preferences": { "timezone": "Europe/Istanbul", "date_format": "DD/MM/YYYY", "time_format": "24h", "theme": "dark" }
}

PATCH /api/auth/profile/

Update first/last name and email. Username is immutable.

GET / PATCH /api/auth/preferences/

Read or update timezone, date_format, time_format, class_browser_sections. Merged into the profile on next fetch.

POST /api/auth/session-timeout/

Persist the idle-logout threshold (in minutes). Valid values: 0, 15, 30, 60, 120, 240, 480 (0 = never).

Password

POST /api/auth/password/change/

Authenticated password change. Requires the current password.

Request:

{ "old_password": "…", "new_password": "…" }

Success invalidates every active session for this user. The calling client keeps its tokens (they were issued before the change) but other devices drop to login on their next request.

POST /api/auth/password-reset/

Start a password reset. Anonymous endpoint.

Request:

{ "email": "alice@example.com" }

Response 200: Always { "status": "ok" }, whether or not the email exists. Prevents account enumeration.

POST /api/auth/password-reset/confirm/

Complete a password reset using either the email link token or an admin-issued one-time 8-character code.

Request (email link):

{ "token": "uidb64:token", "new_password": "…" }

Request (admin code):

{ "code": "AB3D-9F2K", "new_password": "…" }

Admin-issued codes expire after 30 minutes and are single-use — generating a new one invalidates any prior code. See Users.

Email verification

POST /api/auth/email/send-verification/

Send a verification link to the authenticated user's email. Idempotent — sending twice just extends the link's lifetime.

GET /api/auth/email/verify/?token=<token>

Clicked from the email. Marks the email verified and redirects to the frontend login.

Multi-factor authentication

POST /api/auth/mfa/setup/

Begin TOTP enrollment. Generates a secret and returns a QR code (SVG path + base32 string). Does not enable MFA yet.

Response 200:

{ "secret": "JBSWY3DPEHPK3PXP", "qr_code_svg": "<svg>…</svg>", "otpauth_url": "otpauth://totp/…" }

POST /api/auth/mfa/verify/

Confirm the TOTP secret with a live code. On success, MFA is enabled and eight backup codes are returned once.

Request:

{ "code": "123456" }

Response 200:

{ "enabled": true, "backup_codes": ["A1B2-C3D4", "…"] }

GET /api/auth/mfa/status/

Current MFA state: enabled, backup_codes_remaining.

POST /api/auth/mfa/backup-codes/

Regenerate the eight backup codes. Invalidates previous codes immediately. Requires the account password.

POST /api/auth/mfa/disable/

Disable MFA. Requires the account password. Backup codes are purged.

Health and quotas

GET /api/auth/health/

Lightweight ping — confirms auth stack is up. No auth required.

GET /api/auth/quota-usage/

Current user's effective quota and usage counters.

Response 200:

{
  "quota": { "ai_analysis_daily": 50, "queries_max": 500, "can_use_ai_builder": true },
  "usage": { "ai_analysis_today": 7, "queries_total": 42 }
}

GET /api/auth/stats/

Aggregate counters used by the dashboard (queries run, schedules active, notifications unread).

User management (admin)

All routes under /api/auth/management/ require Admin group membership or superuser. Described in full at Users — summarized here.

RoutePurpose
GET /api/auth/management/Paginated user list with filters (?is_active=true, ?group=<id>)
POST /api/auth/management/Create a user
GET /api/auth/management/<id>/User detail
PATCH /api/auth/management/<id>/Update user
DELETE /api/auth/management/<id>/Delete user
POST /api/auth/management/<id>/reset_password/Force-reset a user's password
POST /api/auth/management/<id>/generate_reset_code/Issue a 30-minute 8-char recovery code
POST /api/auth/management/<id>/verify_email/Mark email verified without the link
POST /api/auth/management/<id>/disable_mfa/Remove MFA from a user (logged separately from self-disable)
POST /api/auth/management/<id>/activate/ / deactivate/Toggle is_active
POST /api/auth/management/<id>/add_permissions/ / remove_permissions/Grant/revoke model permissions
GET /api/auth/management/<id>/effective_permissions/Flattened permission list (groups + direct)

Sensitive actions (reset_password, disable_mfa, etc.) have tighter per-user throttles than the general admin rate.

Groups and permissions (admin)

GET /api/auth/groups/

List groups with member counts and the attached GroupQuota.

POST /api/auth/groups/

Create a group. Optional role_template field (one of administrator, operator, editor, viewer) pre-seeds permissions and quota.

POST /api/auth/groups/<id>/clone/

Clone a group, including permissions and quota. Body: { "name": "New Group" }.

POST /api/auth/groups/<id>/add_members/ / remove_members/

Add or remove users from the group. Body: { "user_ids": [1, 2, 3] }.

GET /api/auth/permissions/

Read-only list of Django model permissions, useful when building a permissions picker in an external tool.

WebSocket ticket

POST /api/ws-ticket/

Mint a short-lived (60-second) one-shot token for opening a WebSocket connection. See WebSockets for the handshake.

Response 200:

{ "ticket": "eyJ…", "expires_in": 60 }