Security Model: Platform Permissions vs Downstream Auth
Overview
Agent Atlas uses a two-layer authorization model:
- Platform-level authorization (enforced by Atlas)
- Downstream API authorization (enforced by the downstream API)
Platform-Level Authorization
Atlas enforces whether a caller can use Atlas at all.
Required permissions
| Permission | Required for |
|---|---|
platform-code-mode:search | Searching/browsing the tool catalog |
platform-code-mode:execute | Executing tool plans |
platform-code-mode:execute:write | Executing write/destructive tools (optional gate) |
Token validation
Atlas validates incoming JWTs:
- Signature verified against OIDC provider’s JWKS
issin configured allowlistaudmatches configured audienceexpnot expired (with 30s clock skew)
Permission claim mapping
Configure which JWT claim contains permissions:
# appsettings.json or environment variables
Atlas:
PlatformPermissions:
Claim: "scp" # or "roles", or custom claim name
The claim can be space-delimited ("search execute") or array-style.
Downstream Authorization
Atlas does not enforce downstream API permissions.
x-mcp.requiredPermissionsis informational metadata only- Atlas displays required permissions in the UI for visibility
- Atlas computes an access hint (
granted/missing/unknown) from the caller’s token claims - The downstream API is responsible for enforcing authorization
- Atlas forwards the caller’s JWT as-is:
Authorization: Bearer <token>
Downstream 401/403 handling
When a downstream API returns 401 or 403:
- Atlas surfaces the error as a downstream error (not an Atlas auth error)
- The error message distinguishes between Atlas authorization failures and downstream failures
Security Boundaries
Caller → [Atlas JWT validation] → [Platform permission check] → [Execute plan]
↓
[Downstream API]
[Enforces its own auth]
Atlas only calls base URLs declared in the catalog repo. Arbitrary hostnames in plans are rejected.
Keycloak OAuth2 clients
The local development Keycloak realm (src/Atlas.AppHost/keycloak/atlas-realm.json) ships with three pre-configured clients:
| Client ID | Type | Flows | Purpose |
|---|---|---|---|
atlas-mcp-client | Confidential | client_credentials and authorization code + PKCE | M2M service-account access and guided/interactive auth via MCP Inspector. PKCE (S256) is enforced even on this confidential client for defence-in-depth. |
mcp-inspector | Public (PKCE) | Authorization code + PKCE | Dedicated public client for interactive MCP Inspector sessions. |
atlas-ui-client | Public (PKCE) | Authorization code + PKCE | Atlas React UI (future use). |
atlas-mcp-client carries three default scopes: platform-code-mode:search, platform-code-mode:execute, and someapi:customers:read.
Guided OAuth2 discovery via ProtectedResourceMetadata
When an unauthenticated request reaches /mcp, Atlas returns:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="<issuer>/.well-known/openid-configuration"
The ProtectedResourceMetadata advertises:
AuthorizationServers— the Keycloak realm URL, so MCP Inspector can auto-discover the token and authorization endpoints.ScopesSupported—platform-code-mode:searchandplatform-code-mode:execute, so MCP Inspector pre-fills the required scopes in its guided/quick OAuth flow without manual input.
This means MCP Inspector can complete the entire OAuth2 PKCE exchange automatically — no manual token copying required.