Ory + OPA AuthZ/AuthN Architecture
Context & Purpose
This architecture was designed to provide robust authentication (AuthN) and authorization (AuthZ) for API access across multiple deployment scenarios, including SaaS, On-premise, and Multi-tenant environments.
Key Principles
- Privacy: Avoid PII in services that don’t need it; minimize identity surface.
- Control: Implement RBAC/UI access control, evolving toward attribute-based policies (ABAC).
- Decoupling: Decouple policy logic from application code using OPA (Open Policy Agent).
- Flexibility: Support multiple Identity Providers (IdPs) and federation scenarios.
Core Components
The solution leverages the Ory ecosystem for identity management and OPA for policy enforcement.
| Component | Role | Responsibilities |
|---|---|---|
| Ory Kratos | Identity Management | Handles login, user identity, registration, and session lifecycle. Exposes whoami for session validation. |
| Ory Hydra | OAuth2/OIDC Provider | Issues and introspects access tokens. Supports client credentials, auth code (+PKCE), refresh tokens. |
| Ory Oathkeeper | Identity & Access Proxy | Reverse proxy that validates tokens or sessions and applies authentication rules. Integrates with OPA. |
| OPA | Policy Engine | Policy Decision Point (PDP) using Rego. Evaluates request context (subject, resource, action, env). |
| API Service | Resource Server | Protected backend service. Receives only authorized and validated traffic. |
| Envoy + Ext Auth | Gateway (Alt) | Used in On-prem scenarios to delegate auth to a custom external auth service if Oathkeeper isn’t used. |
Deployment Scenarios & Flows
1. On-premise (Token-based)
Used for service-to-service communication or headless clients.
- Login: Client authenticates via Kratos.
- Token: Client pulls access token from Hydra.
- Request: Client calls API Gateway (Oathkeeper) with Token.
- Validation: Oathkeeper introspects token with Hydra.
- Decision: Oathkeeper consults OPA.
- Forward: If OPA allows, traffic reaches the API.
sequenceDiagram participant Client participant Oathkeeper as Oathkeeper (Gateway) participant Hydra participant OPA participant API as Backend Service Client->>Oathkeeper: Request + Access Token activate Oathkeeper Oathkeeper->>Hydra: Introspect Token Hydra-->>Oathkeeper: Token Valid + Claims Oathkeeper->>OPA: Check Policy (Subject, Resource, Action) OPA-->>Oathkeeper: Allow/Deny alt Allowed Oathkeeper->>API: Forward Request API-->>Client: Response else Denied Oathkeeper-->>Client: 403 Forbidden end deactivate Oathkeeper
2. On-premise UI/App (Session Cookie)
Recommended for browser apps to avoid exposing tokens.
- Request: App sends request with session cookie to Envoy.
- Auth: Envoy forwards to External Auth Service.
- Identity: External Auth calls Kratos (
/sessions/whoami) to validate cookie & get user identity. - Policy: External Auth queries OPA with user + request details.
- Result: Envoy blocks or forwards based on decision.
sequenceDiagram participant Browser participant Envoy participant ExtAuth as External Auth Svc participant Kratos participant OPA participant API Browser->>Envoy: Request + Session Cookie activate Envoy Envoy->>ExtAuth: Delegate Auth activate ExtAuth ExtAuth->>Kratos: /sessions/whoami (Cookie) Kratos-->>ExtAuth: Valid Session + User ID ExtAuth->>OPA: Query Policy (User, Path, Method) OPA-->>ExtAuth: Allow/Deny ExtAuth-->>Envoy: OK / 401 / 403 deactivate ExtAuth alt Allowed Envoy->>API: Forward Request end deactivate Envoy
3. Cloud / SaaS (Gateway + IdP)
- IdP: Issues tokens (Cognito, ADFS, or Hydra).
- Gateway: Validates token signature/validity.
- Policy: Gateway queries OPA for fine-grained authorization default.
sequenceDiagram participant Client participant Gateway participant OPA participant API Client->>Gateway: Request + JWT activate Gateway Gateway->>Gateway: Validate JWT Signature Gateway->>OPA: Authorization Query (Claims, Request) OPA-->>Gateway: Allow/Deny alt Allowed Gateway->>API: Forward Request end deactivate Gateway
Security & Implementation Notes
Authorization Evolution
- Phase 1 (PoC):
client_idbased decisions. Simple but lacks granularity. - Phase 2 (Production): Full context decisions based on Subject (User/Role), Resource, Action, and Tenant.
Practical Steps
- PoC Cleanup: Switch OPA input from
client_idtosubject+roles+tenant. - Gateway Policy: Standardize a single external auth contract (Input Schema) for OPA.
- Token Strategy:
- Headless: OAuth2 Tokens (JWT or Opaque).
- Browser: Session Cookies (Kratos).
Example OPA Input
{
"subject": {
"id": "user-123",
"roles": ["operator", "planner"],
"tenant": "magna-org"
},
"request": {
"method": "POST",
"path": "/v1/orders/confirm",
"resource": "orders",
"action": "confirm"
}
}Component View
flowchart TB subgraph "Clients" Web[Web App] Svc[Service] end subgraph "Identity Layer" Kratos["Ory Kratos<br/>(Identity)"] Hydra["Ory Hydra<br/>(OAuth2)"] end subgraph "Access Layer" Gateway[Oathkeeper / Envoy] OPA["Open Policy Agent<br/>(Policy Engine)"] end subgraph "Backend" API[Target Service] end Web -.->|Session Cookie| Gateway Svc -.->|Bearer Token| Gateway Gateway -->|Validate| Kratos Gateway -->|Introspect| Hydra Gateway -->|AuthZ Check| OPA Gateway -->|Forward| API