### Run Example Application Source: https://github.com/dexidp/dex/blob/master/CONTRIBUTING.md Builds and runs the example OIDC client application. ```shell ./bin/example-app ``` -------------------------------- ### Start Dex Development Server Source: https://github.com/dexidp/dex/blob/master/CONTRIBUTING.md Builds Dex and starts the server using the development configuration. ```shell ./bin/dex serve config.dev.yaml ``` -------------------------------- ### Install Development Dependencies with Make Source: https://github.com/dexidp/dex/blob/master/CONTRIBUTING.md Run this command to install necessary development tools like golangci-lint, protoc, and kind. ```shell make deps ``` -------------------------------- ### Start Dex Server with gRPC Enabled Source: https://github.com/dexidp/dex/blob/master/examples/grpc-client/README.md Launch the Dex server instance using the configured YAML file that enables the gRPC API. This command starts the server with an in-memory data store. ```bash ./bin/dex serve examples/grpc-client/config.yaml ``` -------------------------------- ### Conventional Commits Examples Source: https://github.com/dexidp/dex/blob/master/CONTRIBUTING.md Examples of commit messages following the Conventional Commits specification. ```shell feat: use protobuf for session cookie (#4675) ``` ```shell fix: non-constant format string in call to newRedirectedErr (#4671) ``` ```shell build(deps): bump github/codeql-action from 4.33.0 to 4.34.1 (#4679) ``` -------------------------------- ### No SSO, Different User Example Source: https://github.com/dexidp/dex/blob/master/docs/enhancements/auth-sessions-2026-02-18.md Demonstrates a scenario where SSO is not available, allowing different users to log into different clients within the same browser session. ```text 1. User logged into client-A as alice AuthSession.ClientStates["client-A"] = {UserID: "alice", Active: true} 2. User accesses client-B (client-A does NOT share with client-B) - No SSO available - Redirect to connector for authentication 3. User logs in as bob (different account) AuthSession.ClientStates["client-B"] = {UserID: "bob", Active: true} Same browser, two different users, no conflict! ``` -------------------------------- ### SSO Flow Example Source: https://github.com/dexidp/dex/blob/master/docs/enhancements/auth-sessions-2026-02-18.md Illustrates a successful Single Sign-On flow where a user logged into one client is automatically authenticated to another client if SSO is configured. ```text 1. User logs into client-A as alice AuthSession.ClientStates["client-A"] = {UserID: "alice", Active: true} 2. User accesses client-B - client-A.ssoSharedWith includes "client-B" ✓ - SSO! Copy: ClientStates["client-B"] = {UserID: "alice", Active: true} - Issue tokens for alice to client-B ``` -------------------------------- ### Clean Up Dex gRPC Credentials Source: https://github.com/dexidp/dex/blob/master/examples/grpc-client/README.md Run this command to remove all generated credential files created by the `cert-gen` script. This is a cleanup step to revert the changes made during the example setup. ```bash ./examples/grpc-client/cert-destroy ``` -------------------------------- ### Dex CEL Package Structure Source: https://github.com/dexidp/dex/blob/master/docs/enhancements/cel-expressions-2026-02-28.md The core CEL library for Dex is organized into several Go files within the `pkg/cel/` directory, handling environment setup, compilation, evaluation, and cost estimation. ```go pkg/ cel/ cel.go # Core Environment, compilation, evaluation types.go # CEL type declarations (Identity, Request, etc.) cost.go # Cost estimation and budgeting doc.go # Package documentation library/ email.go # Email-related CEL functions groups.go # Group-related CEL functions ``` -------------------------------- ### Configure OIDC Connector in Dex Source: https://github.com/dexidp/dex/blob/master/docs/enhancements/token-exchange-2023-02-03- Example configuration for an OIDC connector in Dex. Ensure the issuer URL is correctly set for your OIDC provider. ```yaml connectors: - type: oidc id: my-platform name: My Platform config: issuer: https://oidc.my-platform.example/ ``` -------------------------------- ### Verify Certificate Signatures with OpenSSL Source: https://github.com/dexidp/dex/blob/master/examples/grpc-client/README.md Use OpenSSL commands to confirm that the generated server and client certificates have been correctly signed by the CA certificate. This ensures the integrity of the TLS setup. ```bash openssl verify -CAfile ca.crt server.crt ``` ```bash openssl verify -CAfile ca.crt client.crt ``` -------------------------------- ### Example ID Token JWT Source: https://github.com/dexidp/dex/blob/master/README.md This is an example of a JSON Web Token (JWT) representing an ID Token issued by Dex. It contains claims about the issuer, subject, audience, expiration, and user identity. ```text eyJhbGciOiJSUzI1NiIsImtpZCI6IjlkNDQ3NDFmNzczYjkzOGNmNjVkZDMyNjY4NWI4NjE4MGMzMjRkOTkifQ.eyJpc3MiOiJodHRwOi8vMTI3LjAuMC4xOjU1NTYvZGV4Iiwic3ViIjoiQ2djeU16UXlOelE1RWdabmFYUm9kV0kiLCJhdWQiOiJleGFtcGxlLWFwcCIsImV4cCI6MTQ5Mjg4MjA0MiwiaWF0IjoxNDkyNzk1NjQyLCJhdF9oYXNoIjoiYmk5NmdPWFpTaHZsV1l0YWw5RXFpdyIsImVtYWlsIjoiZXJpYy5jaGlhbmdAY29yZW9zLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJncm91cHMiOlsiYWRtaW5zIiwiZGV2ZWxvcGVycyJdLCJuYW1lIjoiRXJpYyBDaGlhbmcifQ.OhROPq_0eP-zsQRjg87KZ4wGkjiQGnTi5QuG877AdJDb3R2ZCOk2Vkf5SdP8cPyb3VMqL32G4hLDayniiv8f1_ZXAde0sKrayfQ10XAXFgZl_P1yilkLdknxn6nbhDRVllpWcB12ki9vmAxklAr0B1C4kr5nI3-BZLrFcUR5sQbxwJj4oW1OuG6jJCNGHXGNTBTNEaM28eD-9nhfBeuBTzzO7BKwPsojjj4C9ogU4JQhGvm_l4yfVi0boSx8c0FX3JsiB0yLa1ZdJVWVl9m90XmbWRSD85pNDQHcWZP9hR6CMgbvGkZsgjG32qeRwUL_eNkNowSBNWLrGNPoON1gMg ``` -------------------------------- ### Initialize WebAuthn Authentication Flow Source: https://github.com/dexidp/dex/blob/master/web/templates/webauthn_verify.html Sets up the necessary parameters and initiates the WebAuthn registration or login process based on the mode. Handles API calls and error display. ```javascript (function() { const mode = {{ .Mode }}; const basePath = window.location.pathname.replace(/\/mfa\/webauthn$/, ""); const params = new URLSearchParams(window.location.search); const reqID = params.get("req"); const hmacVal = params.get("hmac"); const authenticator = params.get("authenticator"); function apiParams() { return "req=" + encodeURIComponent(reqID) + "&hmac=" + encodeURIComponent(hmacVal) + "&authenticator=" + encodeURIComponent(authenticator); } function showError(msg) { document.getElementById("webauthn-error").textContent = msg; document.getElementById("webauthn-error").style.display = "block"; document.getElementById("webauthn-working").style.display = "none"; document.getElementById("webauthn-btn").style.display = ""; } function bufferToBase64url(buffer) { const bytes = new Uint8Array(buffer); let str = ""; for (let i = 0; i < bytes.length; i++) { str += String.fromCharCode(bytes\[i\]); } return btoa(str).replace(/\+/g, "-").replace(/\//g, "").replace(/=/g, ""); } function base64urlToBuffer(value) { let base64 = value.replace(/-/g, "+").replace(/\_/g, "/"); while (base64.length % 4) { base64 += "="; } const binary = atob(base64); const bytes = new Uint8Array(binary.length); for (let i = 0; i < binary.length; i++) { bytes\[i\] = binary.charCodeAt(i); } return bytes.buffer; } function handleFetchError(resp, fallbackMsg) { if (resp.ok) { return resp.json(); } return resp.json() .then(function(j) { throw new Error(j.error || fallbackMsg); }) .catch(function() { throw new Error(fallbackMsg + " (status " + resp.status + ")"); }); } function decodeCredentialIDs(list) { if (!list) { return; } for (let i = 0; i < list.length; i++) { list\[i\] = base64urlToBuffer(list\[i\]); } } function formatError(err) { if (err.name === "NotAllowedError") { return "Request was cancelled or timed out. Please try again."; } if (err.name === "SecurityError") { return "Security key operation not allowed on this domain."; } return err.message || "An unexpected error occurred."; } window.startWebAuthn = function() { document.getElementById("webauthn-error").style.display = "none"; document.getElementById("webauthn-working").style.display = "block"; document.getElementById("webauthn-btn").style.display = "none"; if (mode === "register") { doRegister(); } else { doLogin(); } }; function doRegister() { fetch(basePath + "/mfa/webauthn/register/begin?" + apiParams(), {method: "POST"}) .then(function(resp) { return handleFetchError(resp, "Registration failed"); }) .then(function(options) { options.publicKey.challenge = base64urlToBuffer(options.publicKey.challenge); options.publicKey.user.id = base64urlToBuffer(options.publicKey.user.id); decodeCredentialIDs(options.publicKey.excludeCredentials); return navigator.credentials.create(options); }) .then(function(credential) { const body = JSON.stringify({ id: credential.id, rawId: bufferToBase64url(credential.rawId), type: credential.type, response: { attestationObject: bufferToBase64url(credential.response.attestationObject), clientDataJSON: bufferToBase64url(credential.response.clientDataJSON) } }); return fetch(basePath + "/mfa/webauthn/register/finish?" + apiParams(), { method: "POST", headers: {"Content-Type": "application/json"}, body: body }); }) .then(function(resp) { return handleFetchError(resp, "Registration failed"); }) .then(function(result) { if (result.redirect) { window.location.href = result.redirect; } }) .catch(function(err) { showError(formatError(err)); }); } function doLogin() { fetch(basePath + "/mfa/webauthn/login/begin?" + apiParams(), {method: "POST"}) .then(function(resp) { return handleFetchError(resp, "Authentication failed"); }) .then(function(options) { options.publicKey.challenge = base64urlToBuffer(options.publicKey.challenge); decodeCredentialIDs(options.publicKey.allowCredentials); return navigator.credentials.get(options); }) .then(function(assertion) { const body = JSON.stringify({ id: assertion.id, rawId: bufferToBase64url(assertion.rawId), type: assertion.type, response: { authenticatorData: bufferToBase64url(assertion.response.authenticatorData), clientDataJSON: bufferToBase64url(assertion.response.clientDataJSON), signature: bufferToBase64url(assertion.response.signature), userHandle: assertion.response.userHandle ? bufferToBase64url(assertion.response.userHandle) : "" } }); return fetch(basePath + "/mfa/webauthn/login/finish?" + apiParams(), { method: "POST", headers: {"Content-Type": "application/json"}, body: body }); }) .then(function(resp) { return handleFetchError(resp, "Authentication failed"); }) .then(function(result) { if (re ``` -------------------------------- ### Build Dex Binaries with Make Source: https://github.com/dexidp/dex/blob/master/CONTRIBUTING.md Compiles the Dex project to generate executable binaries. ```shell make build ``` -------------------------------- ### v3.ext Configuration for Certificates Source: https://github.com/dexidp/dex/blob/master/pkg/httpclient/readme.md Extension file for OpenSSL certificates, defining key usage and subject alternative names. Essential for specifying DNS names and IP addresses for the certificate. ```ini authorityKeyIdentifier=keyid,issuer basicConstraints=CA:FALSE keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment subjectAltName = @alt_names [alt_names] DNS.1 = localhost IP.1 = 127.0.0.1 ``` -------------------------------- ### Run Linter with Make Source: https://github.com/dexidp/dex/blob/master/CONTRIBUTING.md Applies the linter to check code quality and style. ```shell make lint ``` -------------------------------- ### Regenerate Code with Make Source: https://github.com/dexidp/dex/blob/master/CONTRIBUTING.md Regenerates protobuf, ent, and tidies go modules. ```shell make generate ``` -------------------------------- ### Compile and Evaluate CEL Expression Source: https://github.com/dexidp/dex/blob/master/docs/enhancements/cel-expressions-2026-02-28.md Demonstrates the process of creating a CEL compiler with identity and request variables, compiling a boolean expression, and evaluating it against provided data. Ensure all necessary context and data are available for evaluation. ```go // 1. Create a compiler with identity and request variables compiler, _ := cel.NewCompiler( append(cel.IdentityVariables(), cel.RequestVariables()...), ) // 2. Compile a policy expression (type-checked, cost-estimated) prog, _ := compiler.CompileBool( `identity.email.endsWith('@example.com') && 'admin' in identity.groups`, ) // 3. Evaluate against real data result, _ := cel.EvalBool(ctx, prog, map[string]any{ "identity": cel.IdentityFromConnector(connectorIdentity), "request": cel.RequestFromContext(cel.RequestContext{...}), }) // result == true ``` -------------------------------- ### Example ID Token Claims Source: https://github.com/dexidp/dex/blob/master/README.md This JSON object represents the decoded claims from an ID Token issued by Dex. It includes standard OpenID Connect claims and custom claims like groups. ```json { "iss": "http://127.0.0.1:5556/dex", "sub": "CgcyMzQyNzQ5EgZnaXRodWI", "aud": "example-app", "exp": 1492882042, "iat": 1492795642, "at_hash": "bi96gOXZShvlWYtal9Eqiw", "email": "jane.doe@coreos.com", "email_verified": true, "groups": [ "admins", "developers" ], "name": "Jane Doe" } ``` -------------------------------- ### Policy Application Steps Table Source: https://github.com/dexidp/dex/blob/master/docs/enhancements/cel-expressions-2026-02-28.md Details each step in the policy application flow, including the policy name, scope, and the action taken upon a match. This table clarifies the behavior of different policies like authPolicy and tokenPolicy. ```text | Step | Policy | Scope | Action on match | |------|--------|-------|-----------------| | 2 | `authPolicy` (global) | Global | Expression → `true` = DENY login | | 3 | `authPolicy` (per-client) | Per-client | Expression → `true` = DENY login | | 4 | `tokenPolicy.filter` (global) | Global | Expression → `false` = DENY token | | 5 | `tokenPolicy.filter` (per-client) | Per-client | Expression → `false` = DENY token | | 6 | `tokenPolicy.claims` (global) | Global | Adds/overrides claims (with optional condition) | | 7 | `tokenPolicy.claims` (per-client) | Per-client | Adds/overrides claims (overrides global) | ``` -------------------------------- ### Run Dex gRPC Client Source: https://github.com/dexidp/dex/blob/master/examples/grpc-client/README.md Execute the Dex gRPC client, providing the necessary CA certificate, client certificate, and client key as arguments. This initiates communication with the Dex server's gRPC API. ```bash ./bin/grpc-client -ca-crt=ca.crt -client-crt=client.crt -client-key=client.key ``` -------------------------------- ### Configure Static Clients with SSO Sharing Source: https://github.com/dexidp/dex/blob/master/docs/enhancements/auth-sessions-2026-02-18.md Defines static clients and their SSO sharing configurations. `ssoSharedWith` specifies which clients can reuse a client's session. An empty list `[]` means no other clients can reuse its session. ```yaml staticClients: # Public app - allows any client to reuse its sessions - id: public-app name: Public App ssoSharedWith: ["*"] # trustedPeers can be configured separately for token delegation # ... # Admin app - only specific apps can reuse its sessions - id: admin-app name: Admin App ssoSharedWith: ["monitoring-app"] # Only monitoring can SSO from admin sessions # ... # Secret internal service - NO other clients can reuse its sessions - id: secret-service name: Secret Service ssoSharedWith: [] # Empty = no SSO allowed from this client's sessions # But this client CAN use sessions from other clients that share with it! # ... # Monitoring app - can SSO from admin-app (because admin-app shares with it) - id: monitoring-app name: Monitoring App ssoSharedWith: ["admin-app"] # Bidirectional sharing with admin-app # ... ``` -------------------------------- ### Policy Application Flow Diagram Source: https://github.com/dexidp/dex/blob/master/docs/enhancements/cel-expressions-2026-02-28.md Illustrates the sequence of policy applications during the authentication and token issuance process. Each step is optional and executed only if configured. ```text Connector Authentication │ │ upstream claims → connector.Identity │ v Authentication Policies │ │ Global authPolicy │ Per-client authPolicy │ v Token Issuance │ │ Global tokenPolicy.filter │ Per-client tokenPolicy.filter │ │ Global tokenPolicy.claims │ Per-client tokenPolicy.claims │ │ Sign JWT │ v Token Response ``` -------------------------------- ### SSO Flow (Returning User) Source: https://github.com/dexidp/dex/blob/master/docs/enhancements/auth-sessions-2026-02-18.md Illustrates the sequence of requests and responses between a browser, Dex, and storage for a returning user during an SSO flow. It covers session retrieval, policy checks, and consent handling. ```text ┌─────────┐ ┌─────────┐ ┌───────────┐ │ Browser │ │ Dex │ │ Storage │ └────┬────┘ └────┬────┘ └─────┬─────┘ │ │ │ │ GET /auth │ │ │ (with cookie) │ │ │ client_id=B │ │ ├────────────────>│ │ │ │ │ │ │ Get session │ │ ├─────────────────>│ │ │ (valid session) │ │ │<─────────────────│ │ │ │ │ │ Check SSO │ │ │ policy for │ │ │ client B │ │ │ │ │ │ Check consent │ │ │ for client B │ │ ├─────────────────>│ │ │ │ │ If consented: │ │ │ redirect with │ │ │ code │ │ │<────────────────│ │ │ │ │ │ If not: │ │ │ show approval │ │ │<────────────────│ │ │ │ │ ``` -------------------------------- ### Run All Tests with Make Source: https://github.com/dexidp/dex/blob/master/CONTRIBUTING.md Executes all tests in the project, including those with race detection enabled. ```shell make testall ``` -------------------------------- ### Client Configuration Struct in Go Source: https://github.com/dexidp/dex/blob/master/docs/enhancements/auth-sessions-2026-02-18.md Defines the structure for client configuration, including existing fields and new fields for 'TrustedPeers' and 'SSOSharedWith'. 'SSOSharedWith' controls which other clients can reuse this client's authentication session. ```go // storage/storage.go type Client struct { // ...existing fields... // TrustedPeers are a list of peers which can issue tokens on this client's behalf. // This is used for cross-client token issuance (existing behavior). TrustedPeers []string `json:"trustedPeers" yaml:"trustedPeers"` // SSOSharedWith defines which other clients can reuse this client's authentication session. // When a user is authenticated for this client, clients listed here can skip authentication. // This is separate from TrustedPeers - organizations may want different policies for // session sharing vs token delegation. // Special value "*" means share with all clients (Keycloak-like realm-wide SSO). // nil means use ssoSharedWithDefault from sessions config. // Empty slice [] means explicitly share with no one. SSOSharedWith []string `json:"ssoSharedWith,omitempty" yaml:"ssoSharedWith,omitempty"` } ``` -------------------------------- ### Define Session Configuration Structure Source: https://github.com/dexidp/dex/blob/master/docs/enhancements/auth-sessions-2026-02-18.md Defines the structure for session configuration, including cookie name, session lifetimes, and SSO sharing defaults. Use this to configure session behavior. ```go type Sessions struct { // CookieName is the session cookie name (default: "dex_session") CookieName string `json:"cookieName"` // AbsoluteLifetime is the maximum session lifetime (default: "24h") AbsoluteLifetime string `json:"absoluteLifetime"` // ValidIfNotUsedFor is the inactivity timeout (default: "1h") ValidIfNotUsedFor string `json:"validIfNotUsedFor"` // SSOSharedWithDefault is the default SSO sharing policy // "all" = share with all clients, "none" = share with no one (default: "none") SSOSharedWithDefault string `json:"ssoSharedWithDefault"` // RememberMeCheckedByDefault controls the initial checkbox state in templates // true = pre-checked, false = unchecked (default: false) RememberMeCheckedByDefault bool `json:"rememberMeCheckedByDefault"` } ``` -------------------------------- ### Generate TLS Credentials for Dex gRPC Source: https://github.com/dexidp/dex/blob/master/examples/grpc-client/README.md Run this script to create necessary TLS certificates and keys for secure gRPC communication between the Dex server and client. Ensure the SAN environment variable is set correctly for localhost access. ```bash # Used to set certificate subject alt names. export SAN=IP.1:127.0.0.1 # Run the script ./examples/grpc-client/cert-gen ``` -------------------------------- ### Enable Auth Sessions Feature Flag Source: https://github.com/dexidp/dex/blob/master/docs/enhancements/auth-sessions-2026-02-18.md Set the DEX_SESSIONS_ENABLED environment variable to true to enable the auth sessions feature. ```bash # Feature flag (environment variable) # DEX_SESSIONS_ENABLED=true ``` -------------------------------- ### SSO Session Lookup Algorithm Source: https://github.com/dexidp/dex/blob/master/docs/enhancements/auth-sessions-2026-02-18.md Searches for a valid SSO source session for a target client by iterating through active client states and checking sharing configurations. Requires user not to be blocked. ```go // findSSOSession searches for a valid SSO source session for the target client func (s *Server) findSSOSession(authSession *AuthSession, targetClientID string) (*ClientAuthState, *UserIdentity) { targetClient, err := s.storage.GetClient(ctx, targetClientID) if err != nil { return nil, nil } // Iterate through all active client states in this browser session for sourceClientID, state := range authSession.ClientStates { // Skip inactive or expired states if !state.Active || time.Now().After(state.ExpiresAt) { continue } // Get the source client configuration sourceClient, err := s.storage.GetClient(ctx, sourceClientID) if err != nil { continue } // Check if source client shares its session with the target client // SSO is allowed if: // 1. Source client has ssoSharedWith: ["*"] (shares with everyone) // 2. Source client has targetClientID in its ssoSharedWith list if !s.clientSharesSessionWith(sourceClient, targetClientID) { continue } // Found a valid SSO source! Get the user identity identity, err := s.storage.GetUserIdentity(ctx, state.UserID, state.ConnectorID) if err != nil { continue } // Check if user is not blocked if identity.BlockedUntil.After(time.Now()) { continue } return state, identity } return nil, nil } ``` ```go // clientSharesSessionWith checks if sourceClient shares its session with targetClientID func (s *Server) clientSharesSessionWith(sourceClient Client, targetClientID string) bool { for _, peer := range sourceClient.SSOSharedWith { if peer == "*" || peer == targetClientID { return true } } return false } ``` -------------------------------- ### Initiate WebAuthn Login Flow Source: https://github.com/dexidp/dex/blob/master/web/templates/webauthn_verify.html Initiates the WebAuthn login flow. This function should be called when the user intends to log in, distinguishing it from registration flows. Ensure the 'mode' variable is correctly set to 'login' before calling. ```javascript if (mode === "login") { startWebAuthn(); } ``` -------------------------------- ### Configure Default SSO Sharing Policy Source: https://github.com/dexidp/dex/blob/master/docs/enhancements/auth-sessions-2026-02-18.md Sets the default Single Sign-On (SSO) sharing policy for clients that do not have an explicit `ssoSharedWith` configuration. Options are 'all' for realm-wide sharing or 'none' for no sharing. ```yaml sessions: # Default SSO sharing policy for clients without explicit ssoSharedWith config # Options: # "all" - clients without ssoSharedWith share sessions with all other clients (Keycloak-like) # "none" - clients without ssoSharedWith don't share sessions (default) ssoSharedWithDefault: "none" ``` -------------------------------- ### Define CEL Environment Version in Go Source: https://github.com/dexidp/dex/blob/master/docs/enhancements/cel-expressions-2026-02-28.md Defines the EnvironmentVersion type and constants for CEL environments. Use WithVersion to set the target environment version for the compiler. This follows the k8s.io/apiserver/pkg/cel/environment pattern. ```go // EnvironmentVersion represents the version of the CEL environment. // New variables, functions, or libraries are introduced in new versions. type EnvironmentVersion uint32 const ( // EnvironmentV1 is the initial CEL environment. EnvironmentV1 EnvironmentVersion = 1 ) // WithVersion sets the target environment version for the compiler. func WithVersion(v EnvironmentVersion) CompilerOption ``` -------------------------------- ### Configure Dex Server for gRPC API Source: https://github.com/dexidp/dex/blob/master/examples/grpc-client/README.md Enable the gRPC API in the Dex configuration file by specifying the address and TLS certificate details. This allows the Dex server to listen for and handle gRPC requests. ```yaml # Enables the gRPC API. grpc: addr: 127.0.0.1:5557 tlsCert: server.crt tlsKey: server.key ``` -------------------------------- ### Implement SSO Session Sharing Logic Source: https://github.com/dexidp/dex/blob/master/docs/enhancements/auth-sessions-2026-02-18.md Implements the logic for determining if a client session should be shared with another client. It considers explicit sharing lists and the default sharing policy. ```go func (s *Server) clientSharesSessionWith(sourceClient Client, targetClientID string) bool { ssoSharedWith := sourceClient.SSOSharedWith // If client has no explicit ssoSharedWith, use default if ssoSharedWith == nil { switch s.sessionsConfig.SSOSharedWithDefault { case "all": return true // Share with everyone by default default: // "none" return false // Share with no one by default } } // Explicit configuration: empty slice means explicitly share with no one // This is different from nil (not configured) if len(ssoSharedWith) == 0 { return false } // Check explicit sharing list for _, peer := range ssoSharedWith { if peer == "*" || peer == targetClientID { return true } } return false } ``` -------------------------------- ### Construct Discovery Endpoint with End Session Source: https://github.com/dexidp/dex/blob/master/docs/enhancements/auth-sessions-2026-02-18.md Constructs the discovery document, conditionally adding the `end_session_endpoint` if sessions are enabled. This endpoint is used by clients to discover Dex's capabilities. ```go func (s *Server) constructDiscovery(ctx context.Context) discovery { d := discovery{ // ...existing fields... } if s.sessionsEnabled { d.EndSessionEndpoint = s.absURL("/logout") } return d } ``` -------------------------------- ### cel-go Dependency Source: https://github.com/dexidp/dex/blob/master/docs/enhancements/cel-expressions-2026-02-28.md Dex utilizes the `github.com/google/cel-go` library, version v0.27.0, which is the official Go implementation of the Common Expression Language. ```go github.com/google/cel-go v0.27.0 ``` -------------------------------- ### Prompt=none Flow Source: https://github.com/dexidp/dex/blob/master/docs/enhancements/auth-sessions-2026-02-18.md Details the flow when a client requests authentication with prompt=none, indicating no user interaction should occur. It shows redirects based on session and consent status. ```text ┌─────────┐ ┌─────────┐ ┌───────────┐ │ Browser │ │ Dex │ │ Storage │ └────┬────┘ └────┬────┘ └─────┬─────┘ │ │ │ │ GET /auth │ │ │ prompt=none │ │ ├────────────────>│ │ │ │ │ │ │ Get session │ │ ├─────────────────>│ │ │ │ │ If valid session + consent: │ │ redirect with code │ │<────────────────│ │ │ │ │ │ If no session or no consent: │ │ redirect with error=login_required│ │ or error=consent_required │ │<────────────────│ │ │ │ │ ``` -------------------------------- ### Sign Server Certificate with Root CA Source: https://github.com/dexidp/dex/blob/master/pkg/httpclient/readme.md Signs the server's CSR using the Root CA's certificate and key, creating a server certificate valid for 10 years. Includes extensions from v3.ext. ```bash openssl x509 -req -in server.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out server.crt -days 3650 -sha256 -extfile v3.ext ``` -------------------------------- ### Handle OIDC Authorization Request Source: https://github.com/dexidp/dex/blob/master/docs/enhancements/auth-sessions-2026-02-18.md This function parses and handles OIDC authorization parameters like 'prompt', 'max_age', and 'id_token_hint'. It manages user sessions, checks for existing consent, and enforces re-authentication based on 'max_age' or 'prompt' values. ```go func (s *Server) handleAuthorization(w http.ResponseWriter, r *http.Request) { // ...existing parsing... prompt := r.Form.Get("prompt") maxAge := r.Form.Get("max_age") idTokenHint := r.Form.Get("id_token_hint") clientID := r.Form.Get("client_id") // Get auth session from cookie authSession, err := s.getAuthSessionFromCookie(r) // Get client auth state for this specific client var clientState *ClientAuthState var userIdentity *UserIdentity if authSession != nil { clientState = authSession.ClientStates[clientID] if clientState != nil && clientState.Active { userIdentity, _ = s.storage.GetUserIdentity(ctx, clientState.UserID, clientState.ConnectorID) } } // Handle max_age parameter (OIDC Core 3.1.2.1) if maxAge != "" && userIdentity != nil { maxAgeSeconds, err := strconv.Atoi(maxAge) if err == nil && maxAgeSeconds >= 0 { authAge := time.Since(userIdentity.LastLogin) if authAge > time.Duration(maxAgeSeconds)*time.Second { // Session is too old, force re-authentication clientState = nil userIdentity = nil } } } switch prompt { case "none": // Silent authentication - must have valid session and consent if clientState == nil || userIdentity == nil { s.authErr(w, r, redirectURI, "login_required", state) return } // Check consent in identity consentedScopes, hasConsent := userIdentity.Consents[clientID] if !hasConsent || !s.scopesCovered(consentedScopes, requestedScopes) { s.authErr(w, r, redirectURI, "consent_required", state) return } // Issue tokens without UI case "login": // Force re-authentication - ignore existing session for this client clientState = nil userIdentity = nil // Continue to connector login case "consent": // Force consent screen even if previously consented // Continue but don't check consent default: // "" - normal flow // Check for SSO from trusted clients if no direct session if clientState == nil && authSession != nil { clientState, userIdentity = s.findSSOSession(authSession, clientID) } } // Validate id_token_hint if provided if idTokenHint != "" { claims, err := s.validateIDTokenHint(idTokenHint) if err != nil { s.authErr(w, r, redirectURI, "invalid_request", state) return } if userIdentity != nil && userIdentity.UserID != claims.Subject { // Identity user doesn't match hint if prompt == "none" { s.authErr(w, r, redirectURI, "login_required", state) return } // Force re-login for different user clientState = nil userIdentity = nil } } // ...continue with flow... } ``` -------------------------------- ### Define AuthSession Structure in Go Source: https://github.com/dexidp/dex/blob/master/docs/enhancements/auth-sessions-2026-02-18.md Represents a browser's authentication state, unique per session cookie. It maps client IDs to their authentication states, allowing different users or identities per client within the same browser session. ```go type AuthSession struct { ID string ClientStates map[string]*ClientAuthState CreatedAt time.Time LastActivity time.Time IPAddress string UserAgent string } ``` -------------------------------- ### Set Session Cookie in Go Source: https://github.com/dexidp/dex/blob/master/docs/enhancements/auth-sessions-2026-02-18.md Sets an HTTP session cookie. Configures the cookie to be persistent if 'rememberMe' is true, otherwise it acts as a session cookie that expires when the browser closes. Ensure the issuer URL is correctly configured for the Path attribute. ```go func (s *Server) setSessionCookie(w http.ResponseWriter, sessionID string, rememberMe bool) { cookie := &http.Cookie{ Name: s.sessionsConfig.CookieName, Value: sessionID, Path: s.issuerURL.Path, HttpOnly: true, Secure: s.issuerURL.Scheme == "https", SameSite: http.SameSiteLaxMode, } if rememberMe { // Persistent cookie - survives browser restart cookie.MaxAge = int(s.sessionsConfig.absoluteLifetime.Seconds()) } // else: Session cookie - no MaxAge, browser deletes on close http.SetCookie(w, cookie) } ``` -------------------------------- ### Create Root CA Certificate Source: https://github.com/dexidp/dex/blob/master/pkg/httpclient/readme.md Creates a self-signed Root CA certificate valid for 10 years using the generated private key and the server.csr.cnf configuration. ```bash openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 3650 -out rootCA.pem -config server.csr.cnf ``` -------------------------------- ### Handle RP-Initiated Logout Source: https://github.com/dexidp/dex/blob/master/docs/enhancements/auth-sessions-2026-02-18.md Handles logout requests according to the OpenID RP-Initiated Logout specification. It validates parameters like id_token_hint and post_logout_redirect_uri, manages session state, revokes refresh tokens, and redirects or shows a confirmation page. ```go func (s *Server) handleLogout(w http.ResponseWriter, r *http.Request) { idTokenHint := r.FormValue("id_token_hint") postLogoutRedirectURI := r.FormValue("post_logout_redirect_uri") state := r.FormValue("state") clientID := r.FormValue("client_id") // Optional: logout from specific client // Get auth session from cookie authSession, _ := s.getAuthSessionFromCookie(r) // Validate id_token_hint if provided var hintUserID, hintConnectorID string if idTokenHint != "" { claims, err := s.validateIDTokenHint(idTokenHint) if err == nil { hintUserID = claims.Subject // Extract connector from token if possible } } if authSession != nil { if clientID != "" { // Logout from specific client only delete(authSession.ClientStates, clientID) s.storage.UpdateAuthSession(ctx, authSession.ID, ...) } else { // Logout from all clients - delete entire auth session s.storage.DeleteAuthSession(ctx, authSession.ID) } // Revoke refresh tokens for logged-out clients // ... } // Clear cookie and redirect s.clearSessionCookie(w) // Show logout confirmation or redirect if postLogoutRedirectURI != "" && s.isValidPostLogoutURI(postLogoutRedirectURI, idTokenHint) { u, _ := url.Parse(postLogoutRedirectURI) if state != "" { q := u.Query() q.Set("state", state) u.RawQuery = q.Encode() } http.Redirect(w, r, u.String(), http.StatusFound) return } // Show logout confirmation page s.templates.logout(w, r) } ``` -------------------------------- ### server.csr.cnf Configuration Source: https://github.com/dexidp/dex/blob/master/pkg/httpclient/readme.md Configuration file for generating a Certificate Signing Request (CSR). Specifies key parameters like bit length, hash algorithm, and distinguished name. ```ini [req] default_bits = 2048 prompt = no default_md = sha256 distinguished_name = dn [dn] C=US ST=RandomState L=RandomCity O=RandomOrganization OU=RandomOrganizationUnit emailAddress=hello@example.com CN = localhost ``` -------------------------------- ### Global Authentication Policy in Dex Source: https://github.com/dexidp/dex/blob/master/docs/enhancements/cel-expressions-2026-02-28.md Define global authentication rules that deny requests if an expression evaluates to true. Policies are evaluated in order, and the first match determines the outcome. ```yaml authPolicy: - expression: "!identity.email.endsWith('@example.com')" message: "'Login restricted to example.com domain'" - expression: "!identity.email_verified" message: "'Email must be verified'" ```