Sign in

User Service

Authentication, authorization, and organization management — what it owns, how it's built, and where to find the full API reference

user
userauthenticationauthorizationjwtoauth2rbacorganizations

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_refresh httpOnly cookie) or header-based (X-Token-Mode: body).
  • Database: PostgreSQL (user_dev).
  • Events: publishes activity events to Kafka on KAFKA_ACTIVITY_TOPIC (default platform-activity) for the Observer Recent Activity feed.
  • Telemetry: the uWSGI webserver runs under opentelemetry-instrument, which reports to Azure Monitor through APPLICATIONINSIGHTS_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 sets cosmos_refresh as an httpOnly cookie, auto-sent on refresh via credentials: 'include'. Body mode returns both tokens in the JSON response, for non-browser clients or local HTTPS-less dev. Cookie SameSite/Secure flags vary by environment (Lax/false local, None/true cross-origin staging, Lax/true same-origin production).
  • Refresh token rotation — every successful refresh issues a new refresh token; in cookie mode the new token is written back to cosmos_refresh automatically. 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_file on organization PATCH, stored per-environment (local filesystem, Azurite, Azure Blob) and served via a temporary signed logo_url; logo_file=null removes it.
  • Pagination-free RBAC admin queries — mode=all returns every permission/role in one response, and expand=permissions embeds each role's permissions via prefetch_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_credentials tokens carrying actor_type=service/service_id=<client id> claims. See Service Tokens for the full guide and ./manage.sh <env> setup-tokens / verify-tokens.

Configuration

VariableDescription
DJANGOSECRETKEYDjango secret key
DB_HOST, DB_PORT, DB_NAME, DB_USER, DBPASSWORDPostgreSQL connection
CORS_ALLOWED_ORIGINSAllowed browser origins
OAUTH2_ISSUER, JWT_ISSUERIssuer base URL for issued tokens (OAUTH2_ISSUER takes precedence)
OAUTH2_ACCESS_TOKEN_EXPIRE_SECONDSOAuth access token lifetime (30 minutes by default)
MFA_*Email-code MFA settings, such as MFA_CODE_TTL_SECONDS
SENDGRIDAPIKEYSendGrid key for password reset and MFA emails
KAFKA_ACTIVITY_TOPICKafka 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

ModelDescription
UserUUID PK, email-based auth, soft delete, staff/superuser flags
OrganizationUUID PK, multi-tenant, active/inactive, logo support
PermissionName, code, description for granular access control
RoleName, description, organization association
RolePermissionMappingMany-to-many role ↔ permission relationship
UserOrganizationRoleMappingLinks users to organizations with specific roles
PasswordResetOTPOTP-based password reset with expiration

Integration Points

ServiceIntegration
All servicesJWT validation — every service validates tokens issued by User Service
MCPOAuth2 provider for external AI tool authentication
ConfiguratorOrganization validation and PDP checks using service tokens
ObserverReceives activity events through Kafka
FrontendLogin, session management, RBAC permission checking

API Overview

AreaBase pathDescription
Authentication/api/v1/users/Login, MFA, refresh, logout, current user, password reset, user administration
OAuth2/OIDC/oauth/, /.well-known/jwks.jsonAuthorization 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_refresh is being sent (credentials: 'include', and SameSite/Secure matching the environment); header mode: confirm X-Token-Mode: body and the refresh token in the request body.