thygon

Identity & Access Control

Let users and organizations authenticate, manage identities, and enforce permissions.

Hybrid

With the hybrid approach, the application delegates identity management and authentication to an external broker while retaining ownership of authorization.

The broker manages user identities, credentials, authentication methods, MFA, and external identity provider integrations. The application manages its own authorization model, including roles, permissions, resource ownership, sharing relationships, and access policies.

Unlike a direct broker integration, the application exposes its own vendor-agnostic authentication API. The client communicates exclusively with the App Service, which handles authentication requests, manages sessions, and communicates with the identity broker through a server-side adapter. This isolates client code from the broker's APIs and SDKs, allowing providers to be replaced without changing the client-facing contract.

Authorization can be implemented within the application, through a dedicated service, or using specialized technologies such as OpenFGA, SpiceDB, Cedar-based policy engines, or Open Policy Agent.

Architecture

Rendering diagram…

Diagram source
flowchart LR
    client["App Client"]
    service["App Service"]
    broker["Identity Broker"]
    authz["App-Owned Authorization"]
    providers["External Identity Providers"]

    client <-->|"Authentication API / Sessions / Resources"| service

    service <-->|"Identity and Authentication API"| broker
    service <-->|"Permission Checks / Policy Updates"| authz

    broker <-->|"OIDC / SAML"| providers

The App Client interacts with the application's own API for sign-in, sign-out, session management, account operations, and protected resources. It does not depend on broker-specific SDKs or API contracts.

The App Service exposes a stable authentication interface, translates requests into broker operations through an internal adapter, establishes application sessions, and enforces access decisions using the application-owned authorization component.

The Identity Broker manages identities, credentials, authentication challenges, MFA, and integrations with external identity providers. It may be a managed platform or an independently operated identity system.

The Authorization Component maintains application-specific roles, permissions, policies, and resource relationships. It may run within the App Service or as an independently deployed system.

The application maintains stable internal identifiers mapped to broker identities. Authorization data is owned by the application rather than the broker.

Protocol considerations: The architecture assumes the broker supports the necessary server-mediated authentication APIs. Some authentication methods, particularly federated OIDC and SAML, require browser redirects to the broker or an external identity provider. These flows can still be initiated and completed through application-owned endpoints, but cannot always avoid direct browser interaction with external authentication services.

Authentication Flow

The App Service exposes the authentication interface consumed by the client. Rather than integrating with the broker directly, the client initiates and completes authentication through application-owned endpoints.

The App Service communicates with the broker to initiate authentication, process challenges, and verify the user's identity. Once authentication succeeds, the application establishes its own session.

The following sequence illustrates a first-party authentication flow supported by a broker's server-side APIs.

Rendering diagram…

Diagram source
sequenceDiagram
    autonumber
    actor C as App Client
    participant A as App Service
    participant P as Identity Broker

    C->>A: POST /auth/start
    A->>P: Initiate authentication
    P-->>A: Authentication challenge
    A-->>C: Authentication requirements

    loop Until authentication completes
        C->>A: Submit authentication response
        A->>P: Verify response
        P-->>A: Result or additional challenge
        A-->>C: Next step if required
    end

    P-->>A: Authenticated identity and tokens
    A->>A: Validate authentication result
    A->>A: Resolve internal user identity
    A->>A: Establish application session
    A-->>C: Set secure session cookie

    Note over C,A: Subsequent requests use the application session

The broker remains responsible for verifying authentication factors and determining whether authentication has succeeded. The App Service owns the client-facing workflow and application session lifecycle.

The application session is represented by a secure, HttpOnly cookie with an appropriate SameSite policy. Session validation, expiration, logout, CSRF protection, and invalidation remain the responsibility of the App Service.

Broker-issued access and refresh tokens, where required, are retained securely on the server and are not exposed to browser JavaScript.

Authentication methods determine which challenges and responses must pass through the application API. Passwords, one-time codes, passkey assertions, and other sensitive authentication material require appropriate handling and must never be logged or unnecessarily persisted by the App Service.

Broker independence: The client-facing authentication contract remains stable when switching identity brokers. However, broker replacement may still require adapter changes, identity migration, session invalidation, or user re-enrollment. Authentication capabilities that differ between providers may also require changes to the server-side workflow.

Authorization Flow

The application independently manages and evaluates its authorization model. The identity broker establishes who the user is, but does not determine what the user may access within the application.

For each protected operation, the App Service validates the application session, resolves the authenticated principal, and evaluates the requested action against its own authorization policies.

Rendering diagram…

Diagram source
sequenceDiagram
    autonumber
    actor C as App Client
    participant A as App Service
    participant E as Authorization Component

    C->>A: PATCH /projects/42 (session cookie)
    A->>A: Validate session and resolve identity

    A->>E: check(user:7, edit, project:42)
    E->>E: Evaluate policies and relationships
    E-->>A: Allow or deny

    alt Authorized
        A->>A: Apply requested change
        A-->>C: 200 OK
    else Forbidden
        A-->>C: 403 Forbidden
    end

The authorization component may evaluate roles, organizational membership, resource ownership, inherited permissions, contextual attributes, and relationships between resources.

Authorization must be enforced for every protected operation. Decisions are based on trusted application data, not client-supplied permissions. Requests without a matching authorization policy are denied by default.

The authorization component can be implemented in several ways:

  • Application-level authorization: Policies are evaluated directly within the App Service, typically against its own database. Suitable for relatively contained authorization models with limited cross-service requirements.
  • Dedicated authorization service: A centralized service exposes a consistent authorization interface to multiple applications or backend services.
  • Specialized authorization engine: A relationship-based or policy-based system evaluates complex permissions, resource hierarchies, sharing relationships, or contextual rules.

When authorization data resides in a separate store, the application must propagate changes to roles, memberships, ownership, and resource relationships reliably.

A transactional outbox can atomically record application changes and corresponding synchronization events within the same database transaction. An asynchronous relay then propagates those events to the authorization system, with retries and idempotent processing.

Because delivery and policy updates may be asynchronous, implementations must account for delayed propagation, duplicate events, ordering, and stale authorization decisions. Where supported, consistency tokens or equivalent mechanisms can provide stronger guarantees about which changes an authorization check observes.

Limitations

  • Increased implementation complexity. The application must maintain its own authentication-facing API, broker adapter, session lifecycle, and authorization model. These responsibilities require additional design, testing, and maintenance compared with direct managed integration.

  • Authentication feature constraints. Not all brokers expose APIs for fully server-mediated authentication. Some capabilities require hosted interfaces, browser redirects, or provider-specific client interactions, limiting how completely the broker can be hidden from the client.

  • Expanded security responsibility. The App Service becomes part of the authentication boundary. Handling authentication challenges, credentials, tokens, and sessions introduces security obligations even though the broker performs credential verification.

  • Distributed identity and authorization ownership. The broker owns identities and authentication state, while the application owns authorization. Account deletion, suspension, organization membership changes, and identity linking may require coordination across both systems.

  • Authorization data consistency. When authorization relationships are maintained in a separate store, synchronization delays and failures can create stale access decisions. Reliable propagation, reconciliation, and explicit consistency requirements become necessary.

  • Authorization availability and latency. A separately deployed authorization component introduces additional network calls and availability dependencies. Caching can reduce latency but introduces invalidation and permission-revocation challenges.

  • Complex resource queries. Evaluating permissions individually across large collections can become expensive. Efficient list filtering may require batch evaluation, authorization-aware queries, or precomputed access relationships.

  • Policy maintenance. Application-owned authorization rules must evolve with the product's data model and business requirements. Changes require testing, versioning, and controlled deployment to prevent unintended access.

  • Remaining broker dependency. A vendor-agnostic API isolates the client from the identity provider but does not eliminate backend dependencies. Broker-specific authentication capabilities, credential portability, API behavior, and data migration remain important considerations.

Implementation

Implement this subsystem

Implementation starts with technical scoping. We review your existing architecture, agree on boundaries, interfaces, and acceptance criteria, and adapt this design to fit before committing to delivery milestones.

There is no off-the-shelf package or fixed price: scope, timeline, and cost follow from that alignment.

Implement this subsystem (opens in a new tab)