Skip to main content

Authentication

The Ascend API supports multiple authentication methods to accommodate different use cases, from browser-based admin access to automated SDK integrations.

Authentication Methods

MethodBest ForSecurity Level
Session CookieAdmin UI, browser appsHighest (HttpOnly, CSRF)
JWT BearerCognito integration, mobile appsHigh (RS256 signed)
API KeySDK, automation, CI/CDHigh (SHA-256 hashed)

Used by the Admin UI for browser-based access with maximum security.

How It Works

  1. User authenticates via Cognito
  2. Backend creates enterprise JWT
  3. JWT stored in HttpOnly cookie (access_token)
  4. CSRF token provided for mutation protection
SettingValuePurpose
HttpOnlytruePrevent XSS access
SecuretrueHTTPS only
SameSiteLaxCSRF protection
Path/All paths

CSRF Protection

Mutating requests (POST, PUT, DELETE) require CSRF token:

curl -X POST "https://pilot.owkai.app/api/actions" \
-H "Cookie: access_token=..." \
-H "X-CSRF-Token: your_csrf_token" \
-H "Content-Type: application/json" \
-d '{"action_type": "create"}'

The CSRF token is provided in the owai_csrf cookie and must match the X-CSRF-Token header.

Compliance: OWASP CSRF Prevention, SOC 2 CC6.1

JWT Bearer Authentication

For Cognito-authenticated clients and programmatic access.

Cognito JWT

After authenticating with AWS Cognito, use the access token:

curl "https://pilot.owkai.app/api/v1/actions" \
-H "Authorization: Bearer eyJraWQiOiJsNktH..."

Token Verification

CheckDescription
SignatureRS256 verified against Cognito JWKS
ExpirationToken must not be expired (1 hour default)
IssuerMust match Cognito User Pool
AudienceMust match App Client ID

Token Claims

ClaimDescription
subCognito user ID
emailUser email address
cognito:groupsCognito groups (for roles)
token_useMust be "access"

Enterprise Token (SEC-081)

Internal endpoints use enterprise tokens with additional claims:

ClaimDescription
db_user_idDatabase user ID (integer)
db_org_idDatabase organization ID
roleUser role
permissionsPermission set

Source: services/token_service.py

API Key Authentication

For SDK integration, automation, and external systems.

Key Format

owkai_admin_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
└────┬────┘└─┬─┘└──────────────┬──────────────┘
prefix role random token (43 chars)

Using API Keys

Option 1: X-API-Key Header (Recommended)

curl "https://pilot.owkai.app/api/v1/actions" \
-H "X-API-Key: owkai_admin_your_api_key"

Option 2: Bearer Token

curl "https://pilot.owkai.app/api/v1/actions" \
-H "Authorization: Bearer owkai_admin_your_api_key"

Key Security

FeatureImplementation
StorageSHA-256 hash with random salt
ComparisonConstant-time (timing attack resistant)
DisplayOnly prefix visible after creation
ExpirationConfigurable (default: 365 days)

Key Prefixes by Role

RolePrefix
Adminowkai_admin_
Userowkai_user_
Managerowkai_manager_

Source: routes/api_key_routes.py, dependencies_api_keys.py

Dual Authentication

Some endpoints support both JWT and API key:

# Backend dependency
@router.get("/data")
async def get_data(
current_user = Depends(get_current_user_or_api_key)
):
# Works with either authentication method
return {"org_id": current_user["organization_id"]}

Priority Order

  1. Session cookie (if present)
  2. JWT Bearer token (if present and valid)
  3. API key (Bearer or X-API-Key header)

Multi-Tenant Isolation

All authentication methods enforce organization isolation:

# Every authenticated request includes organization_id
{
"user_id": 123,
"email": "user@company.com",
"organization_id": 4, # Always present
"role": "admin"
}

Security Enforcement

LayerProtection
Applicationget_organization_filter() dependency
DatabaseRow-Level Security (RLS) policies
QueryAll queries filter by organization_id

Compliance: SOC 2 CC6.1, PCI-DSS 7.1, HIPAA 164.312(a)

Token Expiration

Token TypeDefaultMaximum
Access Token60 minutes24 hours
Refresh Token30 days365 days
API Key365 daysNever
Session Cookie60 minutes24 hours

Refresh Flow

# Refresh expired access token
curl -X POST "https://pilot.owkai.app/api/auth/refresh" \
-H "Content-Type: application/json" \
-d '{"refresh_token": "your_refresh_token"}'

Response:

{
"access_token": "new_access_token",
"expires_in": 3600,
"token_type": "Bearer"
}

Error Responses

401 Unauthorized

{
"detail": "Authentication required"
}

Causes:

  • Missing authentication header/cookie
  • Expired token
  • Invalid token signature

403 Forbidden

{
"detail": "Admin access required"
}

Causes:

  • Insufficient permissions
  • CSRF validation failed
  • Organization access denied

429 Too Many Requests

{
"detail": "Rate limit exceeded"
}

Headers:

Retry-After: 3600

Security Best Practices

  1. Rotate API keys regularly - Every 90 days recommended
  2. Use minimal permissions - Only grant required access
  3. Set expiration dates - Avoid never-expiring keys
  4. Monitor usage - Review API key activity weekly
  5. Revoke promptly - Disable compromised keys immediately
  6. Use HTTPS only - All endpoints require TLS

API Reference

EndpointMethodDescription
/api/auth/cognito-sessionPOSTExchange Cognito tokens
/api/auth/refreshPOSTRefresh access token
/api/auth/logoutPOSTInvalidate session
/api/keys/generatePOSTGenerate API key
/api/keys/listGETList API keys
/api/keys/{id}/revokeDELETERevoke API key

Compliance: SOC 2 CC6.1, NIST IA-2/IA-5, PCI-DSS 8.3


Source: dependencies.py, dependencies_api_keys.py, dependencies_cognito.py