Auth API Reference

Base URL: https://auth-api.yourdomain.com  ·  Built with FastAPI + asyncpg + Redis

Overview

The Tronexus Auth API is a standalone authentication service. It provides Google OAuth for human users, JWT-based access tokens, rotating refresh tokens, and API keys for service-to-service authentication.

It is designed to serve multiple apps from a single instance. Each app gets its own user namespace and role system.

Health check: GET /health returns {"status":"ok"} with no authentication required.

OAuth Flow

Tronexus uses the authorization code flow with PKCE. The flow is:

  1. Your app redirects the user to GET /oauth/google?app_id=<your_app_id>
  2. The Auth API generates a PKCE code challenge and redirects to Google
  3. After Google authentication, the user is redirected to /oauth/google/callback
  4. The Auth API exchanges the code, fetches user info, upserts the user, and returns tokens
# Initiate OAuth — redirect user to this URL
GET https://auth-api.yourdomain.com/oauth/google?app_id=43d8b05c-2eaf-4077-9ee1-3602ba8901de

# Response: 302 redirect to Google's OAuth consent screen
# Callback — handled automatically by the Auth API
# On success returns:
{
  "access_token": "eyJhbGciOiJIUzI1NiJ9...",
  "token_type": "bearer",
  "expires_in": 900,
  "refresh_token": "550e8400-e29b-41d4-a716-446655440000.Abc123..."
}

Tokens

Access Token

JWT signed with HS256. Expires in 15 minutes by default. Contains:

{
  "sub": "user-uuid",
  "app_id": "app-uuid",
  "roles": ["admin", "user"],
  "exp": 1234567890,
  "iat": 1234567890
}

Refresh Token

Format: token-row-uuid.secret. Stored as a bcrypt hash in Postgres. Rotates on every use. If a used token is presented again, the entire token family is revoked (theft detection).

POST /auth/refresh
Content-Type: application/json

{
  "refresh_token": "550e8400-e29b-41d4-a716-446655440000.Abc123..."
}

# Response: new access_token + new refresh_token

Endpoints

MethodPathAuthDescription
GET/healthNoneLiveness check
GET/oauth/googleNoneInitiate Google OAuth. Requires app_id query param.
GET/oauth/google/callbackNoneOAuth callback. Handled by Auth API — do not call directly.
POST/auth/refreshRefresh tokenRotate refresh token and issue new access token.
POST/auth/logoutAccess tokenRevoke all refresh tokens for the current user.
GET/auth/meAccess tokenCurrent user profile and roles.
GET/appsAdmin API keyList all registered apps.
POST/appsAdmin API keyRegister a new app.
GET/apps/{id}/rolesAccess tokenList roles for an app.
POST/apps/{id}/rolesAdmin API keyCreate a role for an app.
POST/apps/{id}/users/{user_id}/rolesAdmin API keyAssign a role to a user.
POST/apikeysAdmin API keyCreate a new API key.
DELETE/apikeys/{id}Admin API keyRevoke an API key.
POST/apikeys/verifyNoneVerify an API key and return its claims.

Authentication Header

Pass the access token or API key as a Bearer token:

Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...

Apps & Roles

Apps are namespaces. Each app has its own users and roles. You can run multiple apps from one Auth API instance.

# Create an app
POST /apps
Authorization: Bearer ak_your_admin_key
Content-Type: application/json

{
  "name": "my-app",
  "description": "My application"
}

# Create a role
POST /apps/{app_id}/roles
{
  "name": "admin",
  "description": "Full access"
}

# Assign role to user
POST /apps/{app_id}/users/{user_id}/roles
{
  "role_id": "role-uuid"
}

API Keys

API keys are for service-to-service authentication. They are bcrypt hashed on creation — the plain key is returned once and never stored.

# Create an API key
POST /apikeys
Authorization: Bearer ak_your_admin_key
Content-Type: application/json

{
  "app_id": "app-uuid",
  "name": "my-service",
  "scopes": ["admin"],
  "expires_in_days": 365
}

# Response includes the plain key — store it immediately:
{
  "id": "key-uuid",
  "key": "ak_Abc123...",   // shown ONCE
  "scopes": ["admin"],
  "expires_at": "2027-01-01T00:00:00Z"
}

# Verify an API key (for service-to-service)
POST /apikeys/verify
Content-Type: application/json
{
  "key": "ak_Abc123..."
}

Rate Limiting

Rate limiting uses a Redis sliding window per IP per endpoint. Defaults:

  • 20 requests per 60-second window
  • After 10 violations: 15-minute IP lockout
  • Permanent bans stored in Postgres for repeat offenders
  • /health is exempt from rate limiting

Adjust thresholds via .env variables. See Configuration → Auth API.

Security Notes

  • PKCE is enforced on all OAuth flows — authorization code interception is mitigated
  • Refresh token family detection revokes entire session families on replay
  • API keys are bcrypt hashed — compromise of the database does not expose plain keys
  • API keys have mandatory expiry — maximum 365 days from creation
  • Security headers middleware applies HSTS, CSP, X-Frame-Options, and X-Content-Type-Options to all responses
  • Redis is bound to the internal Docker network — no external exposure