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.

ComponentRoleResponsibilities
Ory KratosIdentity ManagementHandles login, user identity, registration, and session lifecycle. Exposes whoami for session validation.
Ory HydraOAuth2/OIDC ProviderIssues and introspects access tokens. Supports client credentials, auth code (+PKCE), refresh tokens.
Ory OathkeeperIdentity & Access ProxyReverse proxy that validates tokens or sessions and applies authentication rules. Integrates with OPA.
OPAPolicy EnginePolicy Decision Point (PDP) using Rego. Evaluates request context (subject, resource, action, env).
API ServiceResource ServerProtected backend service. Receives only authorized and validated traffic.
Envoy + Ext AuthGateway (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.

  1. Login: Client authenticates via Kratos.
  2. Token: Client pulls access token from Hydra.
  3. Request: Client calls API Gateway (Oathkeeper) with Token.
  4. Validation: Oathkeeper introspects token with Hydra.
  5. Decision: Oathkeeper consults OPA.
  6. 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

Recommended for browser apps to avoid exposing tokens.

  1. Request: App sends request with session cookie to Envoy.
  2. Auth: Envoy forwards to External Auth Service.
  3. Identity: External Auth calls Kratos (/sessions/whoami) to validate cookie & get user identity.
  4. Policy: External Auth queries OPA with user + request details.
  5. 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)

  1. IdP: Issues tokens (Cognito, ADFS, or Hydra).
  2. Gateway: Validates token signature/validity.
  3. 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_id based decisions. Simple but lacks granularity.
  • Phase 2 (Production): Full context decisions based on Subject (User/Role), Resource, Action, and Tenant.

Practical Steps

  1. PoC Cleanup: Switch OPA input from client_id to subject + roles + tenant.
  2. Gateway Policy: Standardize a single external auth contract (Input Schema) for OPA.
  3. 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