Skip to content

Auth and API Keys

Authentication in Vega works differently depending on the environment: a simple built-in system for local development, and AWS Cognito for production. Both are implemented as adapters behind the IdentityPort interface.

How authentication works

Every protected API endpoint resolves a CurrentUser via the current_user FastAPI dependency in api/dependencies/current_user.py. When a request arrives:

  1. The Authorization: Bearer <token> header is extracted
  2. IdentityAdapter.validate_token(token) is called — either LocalIdentityAdapter or CognitoIdentityAdapter depending on VEGA_AUTH_PROVIDER
  3. The adapter returns a CurrentUser(user_id, groups, role) object, or raises 401 if the token is missing or invalid

Role is derived from group membership: root, operator, or customer. Some endpoints additionally check CurrentUser.role and return 403 if the user lacks the required access level.

Auth configuration endpoint

GET /api/auth/config is an unauthenticated endpoint that returns the active authentication provider and related configuration. The frontend calls this on startup to determine which login flow to use.

{
  "auth_provider": "cognito",
  "cognito_user_pool_id": "us-west-1_xxxxx",
  "cognito_app_client_id": "xxxxx"
}

When auth_provider is "custom", the Cognito fields are null. The frontend uses the returned values to call configureCognitoAuth() at runtime, so Cognito pool IDs don't need to be baked into the frontend build.

Key files: - app/api/routers/auth.pyGET /auth/config route - app/adapters/identity/local/LocalIdentityAdapter - app/adapters/identity/cognito/CognitoIdentityAdapter - app/api/dependencies/current_user.py — Bearer auth → CurrentUser dependency

Local (custom) auth

When VEGA_AUTH_PROVIDER=custom (the default for local development), the backend uses LocalIdentityAdapter:

  • Login: POST /api/auth/login accepts an email and password. The default credentials are debug@example.com / vega-debug-password.
  • Tokens: The adapter issues local:{email} bearer tokens. No cryptographic signing — these are purely for local development.
  • Roles: The email prefix determines the role (root@... → root, operator@... → operator, all others → customer).
curl -s http://localhost:8000/api/auth/login \
  -H 'content-type: application/json' \
  -d '{"email":"debug@example.com","password":"vega-debug-password"}'

Custom auth is not for production

The custom auth system has no real user management, no password hashing, and no MFA. It exists purely to make local development convenient. Always use Cognito in production.

Production (Cognito) auth

When VEGA_AUTH_PROVIDER=cognito, the backend uses CognitoIdentityAdapter:

  1. The user enters credentials in the frontend.
  2. The frontend calls Cognito directly using SRP (Secure Remote Password) protocol.
  3. Cognito returns a JWT access token and a refresh token.
  4. The frontend sends Authorization: Bearer <access_token> on every subsequent API request.
  5. CognitoIdentityAdapter fetches Cognito's JWKS endpoint and validates the JWT signature, expiry, and claims.
  6. User groups are extracted from the JWT (cognito:groups claim) and mapped to Vega roles.

The backend never sees the user's password — that's handled entirely by Cognito.

Key files: - app/adapters/identity/cognito/ — JWT validation via JWKS - infra/terraform/modules/cognito/main.tf — Terraform for the user pool - frontend/src/auth/cognito.ts — frontend Cognito login flow

Required configuration:

VEGA_AUTH_PROVIDER=cognito
VEGA_COGNITO_REGION=us-west-1
VEGA_COGNITO_USER_POOL_ID=us-west-1_xxxxx
VEGA_COGNITO_APP_CLIENT_ID=xxxxx

User management (Cognito)

New user invitations are managed via POST /api/users/invitations (operator/root only). This calls CognitoIdentityAdapter.invite_user(), which creates a Cognito user and sends an invitation email.

In local mode with LocalIdentityAdapter, user management is not supported — only the debug user exists.

API keys

API keys provide programmatic access for automation, CI/CD pipelines, or external tooling.

Users create API keys from the dashboard (/api-keys). An API key works exactly like a Bearer token:

curl -s https://api.vega.example.com/api/projects \
  -H "Authorization: Bearer vk_xxxxxxxxxxxxxxxx"

API keys are stored in the api_keys generic record store (not the identity adapter — they are resolved before the identity layer). The key value (prefixed with vk_) is returned once at creation time and cannot be retrieved again.

Routes:

Method Path Description
GET /api/api-keys List all API keys for current user
POST /api/api-keys Create a new key (returns value once)
POST /api/api-keys/:key_id/revoke Revoke and delete a key

Debugging auth failures

401 invalid_token from /api/auth/me

The token is expired or incorrectly formed. Try logging in again to get a fresh token.

401 on every request in AWS

  1. Confirm VEGA_AUTH_PROVIDER=cognito is set in the API task definition.
  2. Confirm the three Cognito env vars (REGION, USER_POOL_ID, APP_CLIENT_ID) match the deployed Cognito pool.
  3. The Cognito JWKS endpoint must be reachable from the API container — check that outbound HTTPS is allowed from the API security group.

403 forbidden

The user is authenticated but lacks the required role. Check the user's Cognito group membership in the AWS Cognito console. Groups should be root, operator, or user.

Login works locally but not in AWS

Confirm VEGA_AUTH_PROVIDER is not custom in the AWS task definition. Custom auth only works locally.