Skip to Content
API ReferenceAuthentication

Authentication

The AEGIS API uses a two-step authentication flow: exchange email/password credentials for a JWT token, then use the token on subsequent requests. The Go API gateway enforces authentication on every request except health checks and the token endpoint itself.

Authentication Flow

1. Client sends email + password to POST /api/v1/auth/token 2. Auth service verifies credentials (bcrypt), returns JWT 3. Client includes JWT in Authorization header (or aegis_token cookie) on all subsequent requests 4. Gateway validates JWT on each request before proxying to backend

Obtaining a JWT Token

Exchange email and password credentials for a JWT token by calling the token endpoint. This endpoint does not require prior authentication.

curl -X POST http://localhost:8000/api/v1/auth/token \ -H "Content-Type: application/json" \ -d '{"email": "admin@aegis.local", "password": "aegis-dev-admin"}'

Request Body

FieldTypeRequiredDescription
emailstringYesThe user’s email address (matched case-insensitively)
passwordstringYesThe user’s password

Response

{ "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type": "bearer", "expires_in": 86400, "user_id": "dev-user", "roles": ["admin", "operator", "reviewer"] }
FieldTypeDescription
access_tokenstringThe JWT to use in the Authorization header
token_typestringAlways "bearer"
expires_inintegerToken lifetime in seconds (86400 = 24 hours)
user_idstringThe authenticated user’s ID
rolesstring[]Roles granted to this user

If the email or password is incorrect (or the user is inactive), the endpoint returns 401 Unauthorized with {"detail": "Invalid email or password"}.

Using the JWT Token

Include the JWT in the Authorization header with the Bearer scheme on all subsequent requests:

curl http://localhost:8000/api/v1/conversations \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

For browser clients (SSE/EventSource), the gateway also accepts the JWT from the aegis_token cookie set at login, so no Authorization header is required.

# Step 1: Get a token TOKEN=$(curl -s -X POST http://localhost:8000/api/v1/auth/token \ -H "Content-Type: application/json" \ -d '{"email": "admin@aegis.local", "password": "aegis-dev-admin"}' | jq -r '.access_token') # Step 2: Use the token curl http://localhost:8000/api/v1/conversations \ -H "Authorization: Bearer $TOKEN"

Token Details

JWT Claims

The JWT payload contains the following claims:

ClaimDescription
user_idThe authenticated user’s identifier
emailThe authenticated user’s email address
rolesArray of role strings (e.g., ["admin", "operator", "reviewer"])
issIssuer — "aegis-auth" for tokens from the auth service
iatIssued-at timestamp (Unix epoch)
expExpiration timestamp (Unix epoch)

Token Expiry

Tokens expire 24 hours after issuance. When a token expires, the gateway returns 401 Unauthorized. Request a new token by calling POST /api/v1/auth/token again.

Signing Algorithm

Tokens are signed with HS256 (HMAC-SHA256) using a shared secret configured via the JWT_SECRET environment variable.

Token Validation

The gateway validates tokens locally using the shared JWT secret. It does not call the auth service on every request. The auth service also exposes an internal validation endpoint used during initial gateway setup:

curl -X POST http://localhost:8000/api/v1/auth/validate \ -H "Content-Type: application/json" \ -d '"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."'

Response:

{ "valid": true, "user_id": "dev-user", "roles": ["admin", "operator", "reviewer"] }

Role-Based Access

Some endpoints require specific roles. The gateway checks roles from the JWT claims before proxying the request:

Endpoint PatternRequired Role
/api/v1/admin/*admin
/api/v1/detection-rules/*power_user or admin
All other endpointsAny authenticated user

If the user’s roles do not include the required role, the gateway returns 403 Forbidden:

{ "error": "admin role required" }

Public Endpoints

The following endpoints do not require authentication:

EndpointDescription
GET /healthGateway health check
POST /api/v1/auth/tokenToken exchange
GET /api/v1/entity-types*Public entity type listings
GET /api/v1/relationship-rules*Public relationship rule listings
GET /api/v1/relationship-types*Public relationship type listings

User Provisioning

Accounts are admin-provisioned — there is no self-serve signup. Users live in the users table (see the auth-service page) and are created via a CLI:

cd services/auth-service poetry run python -m auth_service.create_user \ --email alice@example.com \ --roles admin,operator,reviewer

The command prompts for a password (or reads it from AEGIS_NEW_USER_PASSWORD). Re-running it for an existing email rotates that user’s password.

Bootstrap Admin

On startup the auth service seeds an initial admin from the BOOTSTRAP_ADMIN_EMAIL and BOOTSTRAP_ADMIN_PASSWORD environment variables, if a user with that email does not already exist. For local development these default to admin@aegis.local / aegis-dev-admin.

EmailPasswordRoles
admin@aegis.localaegis-dev-adminadmin, operator, reviewer

The default bootstrap admin credentials must never be used in production. Set strong BOOTSTRAP_ADMIN_EMAIL / BOOTSTRAP_ADMIN_PASSWORD values and a real JWT_SECRET via environment variables before deploying.

Security Notes

  • Passwords are hashed with bcrypt before storage; plaintext passwords are never persisted.
  • Email matching is case-insensitive (enforced by a LOWER(email) unique index).
  • The JWT_SECRET must be set via an environment variable in production.
  • CORS is configured to allow all origins (*). Restrict this in production deployments.
Last updated on