Dex Federated OpenID Connect Provider

repository·master·Indexed 27 days ago

https://github.com/dexidp/dex

Dex is a federated OpenID Connect (OIDC) provider that allows applications to authenticate users against various upstream identity providers—such as LDAP, SAML, GitHub, Google, and Microsoft—using a single, unified OIDC interface. It issues signed JSON Web Tokens (JWTs) as ID Tokens and can be run natively on Kubernetes clusters using Custom Resource Definitions (CRDs). Dex includes a gRPC API for programmatically managing clients, passwords, connectors, authentication sessions, user identities, and multi-factor authentication (MFA).

Tokens
20.4K
Snippets
27
Records
130
Agent score
95%

What's inside Dex

  1. Overview of Dex Identity Service

    master
    Dex is a federated OpenID Connect (OIDC) provider that acts as an identity service to drive authentication for applications. It serves as a portal to various upstream identity providers (LDAP, SAML, GitHub, Google, etc.) through a system of "connectors." This allows client applications to implement authentication logic once using the OIDC protocol, while Dex handles the specific protocols required by different backend identity providers.
  2. Overview of CEL (Common Expression Language) Integration in Dex

    master

    Dex is integrating [CEL (Common Expression Language)][cel-spec] as a first-class expression engine to handle policy evaluation, claim mapping, and token customization. This integration allows operators to define complex rules declaratively via expressions rather than requiring new Go code or configuration fields for every new requirement.

    Key capabilities being introduced include:

    • Authentication Policies: Control who can log in (e.g., restricting connectors to specific clients, enforcing group membership, or denying logins based on email domains).
    • Token Policies: Customize issued tokens (e.g., adding extra claims to ID tokens, restricting scopes per client, or modifying aud claims).
    • Advanced Claim Mapping: Replace ad-hoc OIDC connector configuration (like ClaimMapping or FilterGroupClaims) with powerful, composable CEL expressions.
    • Global and Per-Client Rules: Apply policies at a global level or specifically to individual OAuth2 clients.
  3. CEL Integration Constraints and Scope

    master

    When using CEL in Dex, be aware of the following design boundaries:

    • Single-expression scope: CEL in Dex is limited to single-expression evaluation. Each expression is a standalone, stateless computation. It does not support intermediate variables, chaining, or multi-step transformations.
    • Not a full policy engine: CEL is scoped specifically to identity and token operations. It is not intended to replace external engines like OPA or Kyverno for general authorization.
    • Additive/Opt-in: The integration is designed to be additive. Existing configuration fields (such as ClaimMapping and ClaimMutations) will continue to function as they did before.
  4. Propose a Dex Enhancement Proposal (DEP)

    master

    Dex Enhancement Proposals (DEPs) are design documents used to propose major new features or significant changes to Dex. Use this process to describe, track, and document changes to the project.

    Before starting

    1. Search GitHub for existing issues, discussions, and DEPs to avoid duplication.
    2. If no discussion exists, open a new discussion.
    3. Discuss your proposed change with the community to ensure a formal DEP is necessary.

    Writing the proposal

    1. Fork the repository.
    2. Copy the template located at docs/enhancements/_title-YYYY-MM-DD-#issue.md and rename it appropriately.
    3. Complete all sections in the template, providing as much detail as possible.
    4. Submit a Pull Request (PR) and engage in discussion with the Dex team.
  5. Configure Token Policies (Claims and Filters) using CEL

    master

    Dex allows operators to mutate ID tokens or restrict token issuance using CEL in the tokenPolicy configuration. This can be applied globally or per-client.

    • claims: Adds or overrides claims in the issued ID token. Each claim has a key (the claim name), a value (the CEL expression for the value), and an optional condition (the claim is only included if this expression is true).
    • filter: Validates the token request. If the expression evaluates to false, the request is denied.

    Note: Certain OIDC/OAuth2 claims (e.g., iss, sub, aud, exp, iat, nbf, jti, auth_time, nonce, at_hash, c_hash) are reserved and cannot be set or overridden via CEL.

    tokenPolicy:
      # Global mutations
      claims:
        - key: "'role'"
          value: "identity.groups.exists(g, g == 'admin') ? 'admin' : 'user'"
        - key: "'idp'"
          value: "request.connector_id"
        - key: "'department'"
          value: "identity.extra['department']"
          condition: "'department' in identity.extra"
    
    staticClients:
      - id: internal-api
        name: Internal API
        secret: ...
        redirectURIs: [...]
        tokenPolicy:
          claims:
            - key: "'custom-claim.company.com/team'"
              value: "identity.extra['team'].orValue('engineering')"
            - key: "'on_call'"
              value: "true"
              condition: "identity.groups.exists(g, g == 'ops')"
          # Restrict scopes
          filter:
            expression: "request.scopes.all(s, s in ['openid', 'email', 'profile'])"
            message: "'Unsupported scope requested'"
  6. Perform Token Exchange via RFC 8693

    master

    Dex supports the OAuth2 Token Exchange grant type (urn:ietf:params:oauth:grant-type:token-exchange). This allows programmatic clients (like CI/CD jobs or machine identities) to exchange a valid token obtained from an upstream Identity Provider (IDP) for a Dex access token, avoiding the need for browser-based login flows or long-lived static secrets.

    To perform an exchange, make a POST request to the Dex /token endpoint using application/x-www-form-urlencoded parameters.

  7. Configure Authentication Policies using CEL

    master

    Operators can define global and per-client authentication policies in the Dex configuration using Common Expression Language (CEL). Each expression must evaluate to a bool. If an expression evaluates to true, the request is denied. Expressions are evaluated in order; the first match wins.

    Global Policy: Applies to all authentication requests. Per-client Policy: Defined within a staticClient and applies only to that specific client.

    # Global authentication policy
    authPolicy:
      - expression: "!identity.email.endsWith('@example.com')"
        message: "'Login restricted to example.com domain'"
      - expression: "!identity.email_verified"
        message: "'Email must be verified'"
    
    staticClients:
      - id: admin-app
        name: Admin Application
        secret: ...
        redirectURIs: [...]
        # Per-client policy
        authPolicy:
          - expression: "!(request.connector_id in ['okta', 'ldap'])"
            message: "'This application requires Okta or LDAP login'"
          - expression: "!('admin' in identity.groups)"
            message: "'Admin group membership required'"
  8. Implement SSO session sharing via SSOSharedWith

    master

    Single Sign-On (SSO) is achieved by allowing clients to share sessions. When a user accesses a client, Dex checks if an existing AuthSession contains an active state for a client that is permitted to share with the target client.

    To allow a client to share its session with others, configure its SSOSharedWith list:

    • Use "*" to allow the client to share its session with all other clients.
    • Use a specific targetClientID to allow sharing only with that specific client.

    SSO Logic Flow:

    1. Dex retrieves the AuthSession via the browser cookie.
    2. It iterates through ClientStates in the session.
    3. For each active/non-expired state, it checks if the sourceClient configuration's SSOSharedWith list contains the targetClientID or "*".
    4. If a match is found, the authentication state is copied to the target client's state in the session.
  9. Map OIDC Connector Claims using CEL

    master

    In OIDC connectors, you can replace legacy claimMapping and claimModifications with claimMappingExpressions. This allows for powerful, logic-based mapping of upstream IdP claims to Dex identity fields.

    Available variable: claims (a map(string, dyn) containing raw upstream claims).

    connectors:
      - type: oidc
        id: corporate-idp
        name: Corporate IdP
        config:
          issuer: https://idp.example.com
          clientID: dex-client
          clientSecret: ...
          # CEL-based claim mapping
          claimMappingExpressions:
            username: "claims.preferred_username.orValue(claims.email)"
            email: "claims.email"
            groups: >
              claims.groups
                .filter(g, g.startsWith('dex:'))
                .map(g, g.trimPrefix('dex:'))
            emailVerified: "claims.email_verified.orValue(true)"
            extra:
              department: "claims.department.orValue('unknown')"
              cost_center: "claims.cost_center.orValue('')"
  10. Enable and Configure Auth Sessions in Dex

    master

    Auth Sessions (DEP 4560) allow for Single Sign-On (SSO) between clients by sharing authentication sessions. To use this feature, you must first enable it via an environment variable.

    Enable the feature

    Set the following environment variable: DEX_SESSIONS_ENABLED=true

    Configure session settings

    Use the sessions block in your config.yaml to manage cookie names and lifetimes. Note that security settings like HttpOnly, Secure, and SameSite are automatically set to secure defaults and are not configurable.

    Configuration Options

    KeyTypeDefaultDescription
    cookieNamestring"dex_session"The name of the session cookie.
    absoluteLifetimeduration"24h"Maximum session lifetime.
    validIfNotUsedForduration"1h"Session expires if not used within this duration.
    ssoSharedWithDefaultstring"none"Default SSO policy for clients without explicit ssoSharedWith config. Options: "all" (realm-wide SSO) or "none".
    rememberMeCheckedByDefaultbooleanfalseWhether the "Remember Me" checkbox is pre-checked in login/approval forms.
    # Enable via environment variable
    # DEX_SESSIONS_ENABLED=true
    
    # Configuration in config.yaml
    sessions:
      cookieName: "dex_session"
      absoluteLifetime: "24h"
      validIfNotUsedFor: "1h"
      ssoSharedWithDefault: "none"
      rememberMeCheckedByDefault: false