Skip to content

Commit 7d84586

Browse files
arne-aignxclaude
andcommitted
feat(auth): add JWT Bearer token authentication support
Extends api.auth to accept Auth0 JWT Bearer tokens alongside existing cookie-based sessions. Bearer auth is opt-in via AUTH_JWT_ENABLED and AUTH_JWT_AUDIENCE; each require_* dependency tries Bearer first, then falls back to cookie. Adds JWKS fetching with per-domain TTL cache. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent b05ae7e commit 7d84586

5 files changed

Lines changed: 448 additions & 72 deletions

File tree

pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,9 @@ dependencies = [
5353
"auth0-fastapi>=1.0.0b5,<2",
5454
"certifi>=2024",
5555
"fastapi>=0.110,<1",
56+
"httpx>=0.28,<1",
5657
"loguru>=0.7,<1",
58+
"PyJWT[cryptography]>=2.10,<3",
5759
"platformdirs>=4,<5",
5860
"psutil>=6",
5961
"pydantic>=2,<3",

src/aignostics_foundry_core/AGENTS.md

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ This file provides an overview of all modules in `aignostics_foundry_core`, thei
1111
| **models** | Shared output format enum | `OutputFormat` StrEnum with `YAML` and `JSON` values for use in CLI and API responses |
1212
| **process** | Current process introspection | `ProcessInfo`, `ParentProcessInfo` Pydantic models and `get_process_info()` for runtime process metadata; `SUBPROCESS_CREATION_FLAGS` for subprocess creation |
1313
| **api.exceptions** | API exception hierarchy and FastAPI handlers | `ApiException` (500), `NotFoundException` (404), `AccessDeniedException` (401); `api_exception_handler`, `unhandled_exception_handler`, `validation_exception_handler` for FastAPI registration |
14-
| **api.auth** | Auth0 authentication FastAPI dependencies | `AuthSettings` (env-prefix and env files derived from `ctx.env_prefix`/`ctx.env_file`), `UnauthenticatedError`, `ForbiddenError` (403); `get_auth_client`, `get_user`, `require_authenticated`, `require_admin`, `require_internal`, `require_internal_admin` FastAPI dependencies; Auth0 cookie security schemes |
14+
| **api.auth** | Auth0 authentication FastAPI dependencies (cookie + Bearer JWT) | `AuthSettings` (env-prefix from `ctx.env_prefix`; fields: `cookie_enabled`, `enabled` (deprecated alias), `jwt_enabled`, `jwt_audience`, domain, credentials, org, role); `UnauthenticatedError`, `ForbiddenError` (403); `get_auth_client`, `get_user` (tries Bearer first, falls back to cookie), `require_authenticated`, `require_admin`, `require_internal`, `require_internal_admin` FastAPI dependencies; Auth0 cookie + Bearer security schemes for OpenAPI |
1515
| **api.core** | Versioned API router and FastAPI factory | `VersionedAPIRouter` (tracks all created instances), `API_TAG_*` constants, `create_public/authenticated/admin/internal/internal_admin_router` factories, `build_api_metadata`, `build_versioned_api_tags`, `build_root_api_tags`, `get_versioned_api_instances(versions, build_metadata=None, *, context=None)`, `init_api()` |
1616
| **api** | Consolidated API sub-package | Re-exports all public symbols from `api.exceptions`, `api.auth`, and `api.core`; import any API symbol directly from `aignostics_foundry_core.api` |
1717
| **log** | Configurable loguru logging initialisation | `logging_initialize(filter_func=None, *, context=None)`, `LogSettings` (env-prefix configurable), `InterceptHandler` for stdlib-to-loguru bridging |
@@ -108,22 +108,21 @@ This file provides an overview of all modules in `aignostics_foundry_core`, thei
108108

109109
### api.auth
110110

111-
**Auth0 authentication and authorization FastAPI dependencies**
111+
**Auth0 authentication and authorization FastAPI dependencies (cookie + Bearer JWT)**
112112

113-
- **Purpose**: Provides Auth0 cookie-based session authentication dependencies for FastAPI routes. All project-specific settings (org ID, role claim) are loaded from `AuthSettings` whose env prefix is configurable at instantiation.
113+
- **Purpose**: Provides Auth0 cookie-based session and JWT Bearer token authentication dependencies for FastAPI routes. Each `require_*` dependency accepts either an Auth0 session cookie **or** a Bearer JWT — Bearer is tried first, cookie is the fallback.
114114
- **Key Features**:
115-
- `AuthSettings(OpaqueSettings)` — uses the active FoundryContext to derive both the env prefix (`{ctx.env_prefix}AUTH_`) and the env file list (`ctx.env_file`). Fields: `internal_org_id` (required `str`; identifies the internal organization), `auth0_role_claim` (required `str`; JWT claim name for role). Both fields are mandatory — no defaults are provided.
115+
- `AuthSettings(OpaqueSettings)` — uses the active FoundryContext (`{ctx.env_prefix}AUTH_`). Key fields: `cookie_enabled` (`AUTH_COOKIE_ENABLED`; new primary name), `enabled` (`AUTH_ENABLED`; deprecated alias for `cookie_enabled`, kept for backwards compat), `jwt_enabled` (`AUTH_JWT_ENABLED`; opt-in Bearer JWT auth), `jwt_audience` (`AUTH_JWT_AUDIENCE`; required when `jwt_enabled=True`), `domain`, `client_id`, `client_secret`, `internal_org_id`, `role_claim`, `session_secret`, `session_expiration`.
116116
- `UnauthenticatedError(Exception)` — raised when a user session is missing or invalid
117117
- `ForbiddenError(ApiException)``status_code = 403`; raised when user lacks required role or org membership
118118
- `get_auth_client(request)` — retrieves `AuthClient` from `request.app.state.auth_client`; raises `RuntimeError` if not configured
119-
- `get_user(request, _cookie)` — async FastAPI dependency; returns user dict from Auth0 session or `None`; validates expiry; sets Sentry user context
120-
- `require_authenticated` — dependency: requires a valid session
121-
- `require_admin` — dependency: requires admin role
122-
- `require_internal` — dependency: requires internal organization membership
123-
- `require_internal_admin` — dependency: requires internal org membership AND admin role
124-
- Auth0 cookie security scheme constants: `AUTH0_SESSION_COOKIE_NAME`, `AUTH0_TRANSACTION_COOKIE_NAME`, `AUTH0_ROLE_ADMIN`
119+
- `get_user(request, _cookie, _bearer)` — async FastAPI dependency; tries Bearer JWT first (when `jwt_enabled=True`), falls back to cookie; returns user dict or `None`; sets Sentry user context
120+
- `require_authenticated`, `require_admin`, `require_internal`, `require_internal_admin` — FastAPI dependencies; each accepts both cookie and Bearer schemes in OpenAPI
121+
- Cookie security schemes: `auth0_session_scheme`, `auth0_admin_scheme`, `auth0_internal_scheme`, `auth0_internal_admin_scheme` (`APIKeyCookie`)
122+
- Bearer security schemes: `auth0_bearer_scheme`, `auth0_admin_bearer_scheme`, `auth0_internal_bearer_scheme`, `auth0_internal_admin_bearer_scheme` (`HTTPBearer`)
123+
- Constants: `AUTH0_SESSION_COOKIE_NAME`, `AUTH0_TRANSACTION_COOKIE_NAME`, `AUTH0_ROLE_ADMIN`, `AUTH0_JWKS_ALGORITHMS`, `AUTH0_JWKS_CACHE_TTL`
125124
- **Location**: `aignostics_foundry_core/api/auth.py`
126-
- **Dependencies**: `auth0-fastapi>=1.0.0b5,<2`, `fastapi>=0.110,<1`, `loguru>=0.7,<1` (all mandatory)
125+
- **Dependencies**: `auth0-fastapi>=1.0.0b5,<2`, `fastapi>=0.110,<1`, `loguru>=0.7,<1`, `PyJWT[cryptography]>=2.10,<3`, `httpx>=0.28,<1` (all mandatory)
127126
- **Import**: `from aignostics_foundry_core.api.auth import AuthSettings, ForbiddenError, UnauthenticatedError, get_auth_client, get_user, require_authenticated, require_admin, require_internal, require_internal_admin`
128127

129128
### api.core

0 commit comments

Comments
 (0)