Skip to content

Auth and access

Login

/login offers email or username with password, phone OTP and Google. The default tab is the user's last method.

Endpoint Purpose
POST /auth/login Username or email and password
POST /auth/register-individual Learner email signup. No session until email OTP is verified.
POST /auth/email-otp/{send,verify} Email OTP
POST /auth/phone-otp/{send,verify} Phone OTP signup and login
GET /auth/google/{authorize,callback} Google OAuth (web)
POST /auth/google/mobile Google ID token from the native app
POST /auth/refresh Rotate tokens
POST /auth/logout Clear cookies
GET /auth/me Current user, plan, capabilities, available chat modes

Tokens

  • Web uses HttpOnly cookies. Learner auth cookies are scoped to .kwilo.ai so kwilo.ai and app.kwilo.ai share a session.
  • Mobile stores tokens in secure storage and sends a Bearer header.
  • On a 401 the client queues requests, refreshes once and retries.
  • Staging API sits behind Cloudflare Access. Native staging builds send a service token. Production isn't gated.

Identity model

Field Meaning
role What the account can do. See Roles and permissions.
signup_intent What a Learner said they are at signup: learner, parent, trainer or creator. Never used for authorisation.
b2c_plan free or pro. Decides limits, not features.
org_unit_id The active institution. Every Learner account has one too (the shared Individual workspace), so never test it for null to detect B2C. Use role == b2c_user.

Uniqueness: username and google_id are unique. email isn't, because a parent can share an email with a child, except that one Learner account is allowed per email. Any lookup by email has to scope the query.

Capabilities

Between identity and plan sits a capability layer:

  1. Identity: role and signup intent.
  2. Capabilities: a pure function of identity, answering "can this account do X at all?" A miss is 403.
  3. Plan and quota: "is X unlocked right now?" A miss is 402 or 429.

Endpoints declare one capability each with require_capability. The frontend reads capabilities from /auth/me and never recomputes them.

Capability Institutional trainer Institutional learner Learner (B2C)
Chat explain ✓ ✓ ✓
Research ✓ · ·
Exam prep · ✓ ✓
Create presentation ✓ · ✓
Create lesson plan, question bank ✓ · ·
Build personal knowledge base ✓ · ✓
Query knowledge base ✓ ✓ ✓
Create image · · ✓

Where it lives

  • apps/backend/src/api/v1/auth.py; Learner signup in kwiloai-b2c
  • apps/backend/src/core/authorization/ (capabilities, modes, dependencies, ERP permission catalog)
  • apps/backend/src/api/v1/capabilities.py