User Service
Authentication, authorization, and organization management — what it owns, how it's built, and where to find the full API reference
Updated 2026-11-03
Verified 2026-11-03
The User Service (cosmos-user-v3) handles authentication, authorization, and user management for the Cosmos platform. Built on Django and Django REST Framework with SimpleJWT, it issues JWTs, manages organizations, and enforces role-based access control (RBAC). It also provides OAuth2/OIDC support via django-oauth-toolkit for external integrations.
Why It Matters
Every other Cosmos service trusts a JWT issued by User Service; there is no independent auth path. It is also the only service that mints short-lived, audience-bound service-to-service tokens (client_credentials), so an outage here doesn't just block logins — it blocks inter-service calls platform-wide.
Architecture At A Glance
- Framework: Django 5.2.4 + DRF 3.14.0 +
djangorestframework-simplejwt. - OAuth2/OIDC:
django-oauth-toolkit, JWKS at/.well-known/jwks.json. - Auth modes: cookie-based refresh tokens (
cosmos_refreshhttpOnly cookie) or header-based (X-Token-Mode: body). - Database: PostgreSQL (
user_dev). - Events: publishes activity events to Kafka on
KAFKA_ACTIVITY_TOPIC(defaultplatform-activity) for the Observer Recent Activity feed. - Telemetry: the uWSGI webserver runs under
opentelemetry-instrument, which reports to Azure Monitor throughAPPLICATIONINSIGHTS_CONNECTION_STRING. - UUID primary keys and soft delete across all models; the permission tree is defined in
permissions_config.yaml.
Key Capabilities
- Dual token delivery — clients choose per-request via
X-Token-Mode. Default (cookie) mode returns the access token in the body and setscosmos_refreshas an httpOnly cookie, auto-sent on refresh viacredentials: 'include'. Body mode returns both tokens in the JSON response, for non-browser clients or local HTTPS-less dev. CookieSameSite/Secureflags vary by environment (Lax/falselocal,None/truecross-origin staging,Lax/truesame-origin production). - Refresh token rotation — every successful refresh issues a new refresh token; in cookie mode the new token is written back to
cosmos_refreshautomatically. The previous refresh token is not blacklisted on rotation; logout blacklists the submitted refresh token. - Multi-factor authentication — login can require a one-time email code, depending on platform, organization, or user policy. See Authentication API.
- Projects — organizations contain projects with their own members, roles, and feature enablements. See Projects API.
- Bulk user administration —
.xlsx-based bulk create (up to 5 MB) with partial-failure error workbooks and row-level messages, plus bulk retrieval by criteria. - Organization metrics — per-organization member, role, and project counts for admin dashboards.
- Organization logo upload — multipart
logo_fileon organizationPATCH, stored per-environment (local filesystem, Azurite, Azure Blob) and served via a temporary signedlogo_url;logo_file=nullremoves it. - Pagination-free RBAC admin queries —
mode=allreturns every permission/role in one response, andexpand=permissionsembeds each role's permissions viaprefetch_related, cutting a typical admin-page load from N+2 calls to one. - Service OAuth clients — every Cosmos service has a provisioned OAuth application and mints
client_credentialstokens carryingactor_type=service/service_id=<client id>claims. See Service Tokens for the full guide and./manage.sh <env> setup-tokens/verify-tokens.
Configuration
| Variable | Description |
|---|---|
DJANGOSECRETKEY | Django secret key |
DB_HOST, DB_PORT, DB_NAME, DB_USER, DBPASSWORD | PostgreSQL connection |
CORS_ALLOWED_ORIGINS | Allowed browser origins |
OAUTH2_ISSUER, JWT_ISSUER | Issuer base URL for issued tokens (OAUTH2_ISSUER takes precedence) |
OAUTH2_ACCESS_TOKEN_EXPIRE_SECONDS | OAuth access token lifetime (30 minutes by default) |
MFA_* | Email-code MFA settings, such as MFA_CODE_TTL_SECONDS |
SENDGRIDAPIKEY | SendGrid key for password reset and MFA emails |
KAFKA_ACTIVITY_TOPIC | Kafka topic for activity events (default platform-activity) |
Deployments apply Django migrations with a Kubernetes migrate job before the webserver rolls out, so migrations must be backward-compatible.
Data Model
| Model | Description |
|---|---|
| User | UUID PK, email-based auth, soft delete, staff/superuser flags |
| Organization | UUID PK, multi-tenant, active/inactive, logo support |
| Permission | Name, code, description for granular access control |
| Role | Name, description, organization association |
| RolePermissionMapping | Many-to-many role ↔ permission relationship |
| UserOrganizationRoleMapping | Links users to organizations with specific roles |
| PasswordResetOTP | OTP-based password reset with expiration |
Integration Points
| Service | Integration |
|---|---|
| All services | JWT validation — every service validates tokens issued by User Service |
| MCP | OAuth2 provider for external AI tool authentication |
| Configurator | Organization validation and PDP checks using service tokens |
| Observer | Receives activity events through Kafka |
| Frontend | Login, session management, RBAC permission checking |
API Overview
| Area | Base path | Description |
|---|---|---|
| Authentication | /api/v1/users/ | Login, MFA, refresh, logout, current user, password reset, user administration |
| OAuth2/OIDC | /oauth/, /.well-known/jwks.json | Authorization code with PKCE, client credentials, JWKS |
| Organizations | /api/v1/organizations/ | Organizations, members, roles, permissions |
| Projects | /api/v1/projects/ | Projects, members, project roles, enablements |
| Health | /health/ | Health check |
- Authentication API — login, MFA, refresh, logout, current user, password reset, user administration, OAuth2/OIDC endpoints, JWT structure
- Organizations API — organization CRUD, metrics, membership, roles, permissions
- Projects API — projects, members, project roles, enablements
→ Full API reference: User API
Troubleshooting
- Login fails with 401 — verify the user exists (
docker exec cosmos-dev-user-db psql -U postgres -d user_dev -c "SELECT email FROM public.user WHERE email='admin@cosmos.dev';") and the service is up (curl http://localhost:8101/health/). - Token refresh fails — cookie mode: confirm
cosmos_refreshis being sent (credentials: 'include', andSameSite/Securematching the environment); header mode: confirmX-Token-Mode: bodyand the refresh token in the request body.