# Changelog
Source: https://docs.strata.io/changelog
Release notes for both the Maverics Orchestrator and Maverics Console, organized by year in reverse chronological order.
The Orchestrator uses calendar versioning in `vYYYY.MM.BUILD` format (e.g., v2026.02.1), where `BUILD` is the sequential build number within that month. The Console uses a similar `vYYYY.MM.DD` format, where `DD` is the day of the month the release was published. The Orchestrator transitioned from semantic versioning (v0.x.x) to CalVer starting with v2025.05.1.
## Orchestrator Releases
Latest Orchestrator releases
CalVer transition and v0.100+
v0.26 through v0.27
v0.23 through v0.25
## Console Releases
Latest Console releases
Console UI overhaul and AI Identity Gateway
Early Console releases
# 2024
Source: https://docs.strata.io/changelog/console/2024
* Email form now validates email address format
* Email is now treated as case insensitive
* When you log out you will be redirected to the /sign-in page
* Resolves an issue that may have occurred if you deployed a user flow between March 11, 2025 and March 18, 2025, and were not observing health data on the Orchestrator Telemetry page
* Maverics now supports OIDC hybrid flow with an opt-in for Implicit Grant Type
* The Pendo resource center has been removed and replaced with the document center
* You can now define an errorPageURL in the Auth0 OIDC identity fabric configuration
* Maverics now supports using a URL as a claim name for policies and OIDC/SAML claims
* You can now add an attribute provider service extension to a rule when defining an access policy
* New option to sign in using your email address and a one-time passcode (OTP)
* Redesigned landing page with single form field
* On deployment of a OIDC app type user flow, the default end session and revoke endpoints will be properly set in the config
* The ARN value no longer requires the full Amazon Resource Name path
* Resolved an issue preventing the orchestrator from connecting to AWS Secrets Manager
# 2025
Source: https://docs.strata.io/changelog/console/2025
* Simplified Members list combining pending user invites and active members into one list
* Fixed an issue where proxy outbound TLS CA file path was not being properly saved or deployed
* When hosting multiple MCP Bridge apps in an AI Identity Gateway deployment, you can now assign unique namespaces to each app's tools
* This prevents tool name conflicts across multiple MCP servers
* Introducing Server Name Indication (SNI) TLS configuration
* Configure TLS settings for individual host domains in addition to the global TLS settings
* Enhanced Token Lifecycle Control for AI Agent Operations
* Fine-grained control over token issuance and lifecycle for AI agent operations including:
* Delegation
* Refresh token lifetime
* Access token lifetime
* Enhancements to Rego and OpenAPI spec views and drag-n-drop
* MCP Bridge Provider now supports environment variables in URLs
* Bug fixes for SAML and OIDC authentication policies
* Drag N Drop OpenAPI specs and Rego policy definitions when defining a MCP Bridge app
* SAML Apps unauthorized page field no longer requires a full URL
* When defining the tools you want to expose in your MCP, you can now directly edit OpenAPI Spec as YAML or JSON format
* Note: supports v3.0 (v3.1 or higher not supported)
* The AI Identity Gateway: MCP Bridge is now available
* Enables teams to let AI agents interact with internal or external APIs safely, with identity, authorization, and policy enforcement
* Resolved an issue where the disable hashing option was not propagated in a deployment
* You can now disable the feature-specific prefix typically prepended to cache keys, enabling shared Redis cache for external data integration
* Requires Orchestrator v2025.11.1 or higher
* The LDAP provider and related LDAP service extensions are now generally available in the UI
* You no longer need to contact support to enable it
* Resolved an issue that prevented users from being able to accept account invitations
* Resolved an issue that prevented new users from being able to sign up
* Fixed config generation when multiple Continuity Strategies in a single deployment
* Improved how TLS certificates and TLS policies (e.g., min TLS version, enabled ciphers) are configured
* More flexibility and better security controls
* You can sort and name search for applications, identity fabric, and user flows from the dashboard
* Resolved issues in Identity Service Health Monitoring not generating correct config
* The proxy user flow editor now lets you attach a user flow to a deployment
* New list of deployments view
* Resolved an issue where proxy user flows failed with service extensions with null metadata
* New UI for the proxy application user flow editor with show view and edit slide out window
* Adopted new list experience for applications including:
* Search by name
* Create new
* View the associated user flow
* Fixed PKCE toggle in OIDC Identity Fabric
* When creating an OIDC based identity fabric, PKCE is enabled by default and the toggle now correctly shows enabled state
* Improved warning experience when trying to delete a service extension that is in use
* Added CORS configuration to OIDC applications
* You can now enter multiple login and logout redirect URLs for Microsoft Entra ID OIDC and other OIDC identity fabric services
* Updated look and feel of the Identity Fabric page
* Deployments now support Azure Government Cloud blob storage
* Requires Orchestrator version v2025.08.2 or higher
* In the LDAP authentication fabric settings you can now customize login flows by uploading custom HTML pages and localizations
* You can now perform a name search from the Identity Fabric list and on creation
* From the Deployment Manager you can now configure TLS settings for inbound connections on the orchestrator host
* Requires manual orchestrator restart
* Resolved an issue where metadata value edits were not deploying
* You can now add filters to suppress log messages from Observability Settings
* Each filter defines a function that tests potential log output
* In an OIDC app type definition you can now define a redirect URL fallback when an app's authorization request does not include a redirect\_uri parameter
* Improved user flow list view with search and filtering
* You can now set a file path on host to the SAML Private Key and SAML Public Key (Certificate)
* Requires Orchestrator version 2025.06.4 or higher
* Resolved an issue preventing users from switching accounts
* Updated the system to use the latest Orchestrator Telemetry configuration
* The new Deployments capability is now available in all accounts
* Includes:
* Deployments Workflow
* Deployment Manager
* Configuration Preview
* Attribute Provider definition in a user flow has been expanded and renamed to Dependencies
* You can now attach identity providers, service extensions, and attribute providers to a user flow
* You can now define multiple Entity IDs when defining a SAML application
* In an OIDC app you can now mark an app as a public client
* Public clients, such as SPAs, do not require a client secret
* Requires Orchestrator release v2025.05.2 or higher
* View the latest Orchestrator Release Version number, date, and go directly to the release notes
* Orchestrator Version Inspection to check compatibility
* Added support for editing metadata values for service extension points in Proxy User Flows
* You can now define an app specific unauthorized (403) URL for SAML apps
* Requires Orchestrator Release v0.113.0
* Publish Preview actions are now on each app in SAML and OIDC user flows
* SAML apps can define default and multiple Assertion Consumer Service (ACS) URLs
* OIDC Apps now support allowedAudiences
* Bug fixes for user flow metadata and SE function names
* New Deployments Workflow, Deployment Manager, Configuration Preview, and Enhanced SAML App Configuration
* Gradually rolling out to existing accounts
* Improved text formatting and layout of the deployment manager
* Resolved issues where a user could not accept an invitation to another account
* When defining an OIDC app you can now require demonstrating proof of possession (DPoP)
* App Centric Migrations to prepare for future UI updates
* New users can sign in with a passkey as an alternative to the HYPR app
* Each application is now restricted to one user flow to simplify application deployments
# 2026
Source: https://docs.strata.io/changelog/console/2026
* Added a warning in the publish drawer when a configuration override is active for a deployment
* Proxy app access policy editor now exposes the option to match on query parameters
* OIDC Identity Fabric providers now support CIMD (Client Initiated Metadata Document) and DCR (Dynamic Client Registration) configuration
* Fixed an issue where namespaces were not consistently applied to service extension claims
* OIDC apps now support access token claims mapping, letting you configure which claims are included in issued access tokens
* Fixed an issue in the configuration inspector where OIDC CIMD app types and token broker authentication were not handled correctly
* **OIDC CIMD App Type:** Administrators can now create and configure CIMD-type OIDC applications directly in the Console. The Orchestrator fetches and validates the client's published metadata document at runtime, completing the full authorization-code + PKCE flow with no prior client registration.
* Service extension claims are now available as options in the Username Mapping dropdown
* Username Mapping now accepts free text input in addition to selector options
* Dropdown fields can now be cleared to unselect the current value
* MCP Proxy apps now support tool filtering to control which tools are accessible per app configuration
* You can now configure an Authenticate SE as the username mapping source for an attribute provider resource
* The Maverics Storage used for evaluation purposes has been removed. Instead, use one of the supported configuration storage providers. See [Config Publishing](/reference/console/config-publishing) for more details.
* SAML Provider private and key configuration now accepts a single key; key reordering has been removed from the key management drawer.
### Improvements
* OIDC provider private keys now respect configured ordering, enabling key rotation.
### New
* Now that Strata Identity has joined Rubrik, there is a prompt to accept the Rubrik Terms of Service and Privacy Policy.
* Claim and attribute mapping fields now accept free text input in addition to selector options
* Removed "Log in with Microsoft" as a social sign-in option from the Maverics Console
* Fixed an issue where Generic OAuth could not be used as an authentication provider
## Filter MCP tools by access token
MCP Proxy apps can now apply an OPA connection authorization policy that decides, per upstream MCP server, whether the gateway connects to it and lists its tools — evaluated against the caller's access token. Instead of surfacing every upstream's tools to every client, you can scope which tools each session sees based on identity.
See the [MCP Proxy reference](/reference/orchestrator/applications/mcp-proxy) for full configuration details.
### Proxy app type editing improvements
* User flows have been completely phased out and will no longer appear in list views.
* All configuration for a Proxy app — upstream, route patterns, location access policies, and global request headers — now live in the app editor.
* Resources (formerly Dependencies) define the identity fabric and service extensions you reference in access policies and claims. Define your Resources first, and they'll be available in the relevant drop-downs throughout the Proxy app editor.
### Fixes
* Added a warning in the configuration inspector when `http.writeTimeoutSeconds` is set for deployments using an MCP provider
* Resolved an issue where SAML and OIDC claims mappings were omitted during a deployment
* Added WSO2 to the supported identity provider filters for the OIDC protocol
* Attribute providers can no longer be selected as authentication sources for OIDC and SAML apps
* Fixed an issue where long policy metadata values were not properly truncated
* Added support for multiple identity providers in authentication policies for OIDC and SAML apps
* Added a scopes field to the OAuth connector in the Identity Fabric
* Fixed the OIDC offline access toggle always showing as disabled in the edit form
* Fixed uploaded service extension assets not being included in deployment bundles for OIDC and SAML apps
* Fixed namespace handling for service extension claims in OIDC and SAML claims mapping
## Token brokering for OIDC apps
OIDC apps can now broker tokens from an upstream provider. Configure token brokering directly in the OIDC app editor.
Token brokering is experimental and may change in a future release.
## Generic OAuth connector
A new **Generic OAuth** connector is available from the Identity Fabric. Use it to broker tokens against SaaS upstreams that expose OAuth but no OIDC discovery — for example, Databricks account-wide federation or GCP Workload Identity Federation.
## RFC 7638 key IDs for OIDC Provider JWKs
The OIDC Provider JWK editor now includes a toggle for RFC 7638-compliant key ID (KID) generation. Existing keys keep their current KID; new keys use the spec-compliant algorithm.
## Fixes
* Removing a Resource from a SAML or OIDC app no longer fails to save when an attribute provider still references it. Stale references now clear automatically, and the editor flags any that still need attention before you save.
* Fixed SAML v2 request verification certificate handling.
* Added URL validation to the Generic OAuth connector in the Identity Fabric.
### SAML app type editing improvements
* User flows are being phased out and will no longer appear in list views.
* All configuration for a SAML app — service provider configuration, protocol & assertion settings, access policies, and attribute mappings — now live in the app editor.
* Resources (formerly Dependencies) define the identity fabric and service extensions you reference in access policies and claims. Define your Resources first, and they'll be available in the relevant drop-downs throughout the SAML app editor.
## OIDC app type editing improvements
* **User flows are being phased out.** All configuration for an OIDC app — client details, access policies, claims, and OAuth 2.0 scopes — now lives in a single view.
* **Resources** (formerly Dependencies) define the identity fabric and service extensions you reference in access policies and claims. Define your Resources first, and they'll be available in the relevant drop-downs throughout the OIDC app editor.
## Custom Telemetry Exporters for Metrics
Ship Orchestrator metrics to any OTLP-compatible backend directly from the Observability settings page — no external collector required.
The **Custom Telemetry Exporters** section lets you add one or more metrics destinations alongside Maverics Cloud Telemetry. Each exporter is configured with a name, protocol (OTLP over HTTP or gRPC), endpoint, optional auth headers, and advanced tuning for compression, temporality, histogram aggregation, and export interval/timeout. See the [metrics telemetry reference](https://docs.strata.io/reference/orchestrator/telemetry/metrics#metrics) for the full field list.
**Exporter types**
* **New Relic** — preset tuned for New Relic's OTLP ingest (`otlp.nr-data.net`, delta temporality, base2 exponential histograms, gzip).
* **Generic OTel** — works with any OTLP receiver. Point it at your own OpenTelemetry Collector or directly at a SaaS backend that accepts OTLP, including Datadog, Grafana Cloud, Honeycomb, Splunk Observability Cloud, Dynatrace, AWS CloudWatch (via ADOT), Microsoft Azure Monitor, Google Cloud Observability, and Chronosphere.
**Why it matters**
Previously, fanning metrics out to a vendor meant standing up an OpenTelemetry Collector in front of the Orchestrator and managing exporter config in YAML. Now operators can wire up multi-destination metrics from the admin UI in under a minute, with per-exporter tuning of headers, interval, temporality, and histogram shape.
**Notes**
* Observability settings are now grouped under **Orchestrator Settings**.
* Each exporter runs independently — a slow or unreachable destination won't block the others.
* Maverics Cloud Telemetry remains available and is unaffected by custom exporter configuration.
* Resolved an issue where SSO configuration changes were not applied
* Fixed sidebar navigation active state on Identity Fabric and Service Extension detail pages
* Dropdowns with 10+ items now include a search filter so you can quickly find what you need
* Fixed an issue where dropdown selections couldn't be changed
* Added search and filter support to dropdown selectors
* Resolved issues preventing successful signup and user invitation flows
* The code editor for service extensions, OPA policies, and OpenAPI code has been upgraded to Monaco Editor for an improved editing experience
* Configure JSON output logging for deployments
* SAML apps now support configuring NameID element qualifiers
* The Console now validates Rego policy scripts for compilation errors when saving OPA policies
* The OIDC Identity Fabric connector now shows a detailed error view and validates that the connected Orchestrator meets the required minimum version
* Resolved an issue where account re-registration was blocked after deleting an account
* **API App Type Moves to Service Extensions:** API App Types have been relocated from the Applications area to the Service Extensions area in the Maverics Console, unifying the experience for managing APIs and service extensions under a single interface.
* All existing API App Types automatically appear in the Service Extensions area alongside your other extensions.
* Creating a new API is straightforward — select "API" from the Service Extensions area and provide your configuration details.
* API App Types can now be attached to deployments directly.
* Existing deployments that already have APIs associated with them will find those APIs in a new dedicated APIs section within the deployment configuration. No migration or reconfiguration is required.
* Added OIDC callback error handling configuration for the [Entra ID](/reference/orchestrator/identity-fabric/azure-ad#callback-error-handling) and [Generic OIDC](/reference/orchestrator/identity-fabric/custom-oidc) Identity Fabric connectors. Requires Orchestrator v2026.03.3 or higher.
* Service extension asset uploads now support files up to 5 MB
* Fixed an issue where dependencies and library settings were not deployed with API service extensions
* The Console will now validate the SAML certificate and key pair when uploading to a deployment. We recommend doing this only for testing purposes; for production, always use a secrets provider.
* LDAP configuration no longer shows a custom login file path option
* HTTP Server TLS configuration now supports `None` as a client authentication type
* Resolved issues when attaching service extensions to a deployment
* Resolved issues when typing spaces or enter the Rego policy editor
* Service Extensions list header is now properly titled
* Fixed an issue where service extensions were not working as a Name ID source in SAML user flows
* Authentication service extensions are no longer listed in the user flow dependency list
* Audit Log (Beta) is now available
* Resolved email case sensitivity issues when signing in and accepting user invitations
* Maverics Console no longer applies an automatic namespace prefix when a Service Extension is the source for a NameID attribute value. This resolves Orchestrator runtime errors that produced "connector does not exist" and "missing claim mapping" messages, which prevented SAML authentication from completing.
* **Action Needed:** SAML user flows that use a Service Extension to populate the NameID value may require a manual update to the NameID mapping field.
* You can now remove members who declined a team invitation
* Resolved an issue whereby screens refresh unexpectedly causing a loss of edits
* Audit logs now capture login and logout events
* Audit log events now include event type, category, and target metadata in the admin API
* Audit logs table now shows the target type alongside the target name
* Service extensions listed in user flow dependencies now show available metadata
* Audit Logs navigation item is pinned to the bottom of the sidebar
* Fixed sorting issues across listing views for consistent ordering
* Fixed an issue where dependency metadata was not preserved when updating a user flow
* Fixed the Service Extension editor shuffling metadata fields
* Audit log timestamps are now formatted for readability
* Session creation audit log events no longer include query parameters
* Configure the maximum TLS version for deployment TLS settings (requires Orchestrator v2026.02.3 or higher)
* Resolved an issue preventing login with Email OTP
* Added a Target Name column to the audit logs table for easier identification of affected resources
* User details are now included in membership audit log events
* Configure HTTP Server timeouts and access logging in Deployments
* Configure outbound authorization for MCP protocol operations (`initialize` and `tools/list`) for MCP Proxy apps (requires Orchestrator v2026.02.2 or higher)
* Improved UX when deploying HTTP Server settings, including default placeholders and endpoint timeout validation
* Resolved TLS configuration issues with client CA files, Windows certificate store persistence, and cipher suite persistence
* Your Console account is now linked to one sign-in method (the last one you used) -- use that same method every time you log in
* Sign-in options: Maverics Account passwordless (Email OTP or HYPR), social sign-in (Google or Microsoft Account), or Enterprise SSO (bring your own IdP)
* GitHub sign-in has been removed as a login option
* If you try a different sign-in option, you'll see a message that the email is already associated with another identity provider
* Redis Cache now supports enabling TLS configuration in the Console without having to set a CA file path
* A new toggle lets you enable or disable TLS for the Redis cache connection
* Set the minimum TLS version (1.2 or 1.3)
* Resolved an issue preventing SSO users from reliably signing into Maverics Console
* Resolved a critical issue where CA (Certificate Authority) and mutual TLS configuration was not persisting in proxy applications
* The system now properly saves and deploys the configuration
* Fixed an issue where the proxy outbound TLS CA file path was not being properly saved or deployed
* The sign up and sign in flows have been redesigned for a cleaner, more efficient user experience
* The Orchestrators Main Menu has been removed -- all orchestrator settings are now accessible from the Deployment Manager
* You can now configure JWT client authentication for OIDC apps
* Requires Orchestrator v2026.01.3 or higher
* JWT Client Authentication Configuration for the Generic OIDC Connector
* Requires Orchestrator release v2026.01.3 or higher
* Resolved issues preventing the attachment of service extensions to OIDC, SAML, or Proxy app type user flows
* Resolved issues preventing deletion of applications or user flows that were not attached to a deployment
* MCP Proxy App Type is now available
* You can now create and configure MCP Proxy apps directly from the Maverics Console
# 2023
Source: https://docs.strata.io/changelog/orchestrator/2023
* Fix panic when cert not found in Windows cert store
* Correctly set RelayState during IDP initiated login
* Add env vars for Windows Certificate Store
* Improve error handling in OIDC connectors
* Add support for reloadable cache
* Allow SAML client to support both IDP initiated login and verified SP login
Internal improvements and maintenance updates.
* Add windowsclientauthenticator connector to orchestrator
* Expose jose.JSONWebKeySet in v2 SE
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
* Add support for GetFloat and SetFloat in Service Extensions
* Add support for GetTime and SetTime in Service Extensions
Internal improvements and maintenance updates.
* Add support for GetInt and SetInt in Service Extensions
* Fix issue of cache manager not being repopulated on reload
* Add support for GetBool and SetBool in Service Extensions
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
* Set maverics cookie in proxy apps and API SEs
* OIDCProvider validate HTTP method used in token and auth endpoints
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
* Correct policy matching in proxy apps to be case-insensitive
* Add optional nameIDFormat configuration to samlprovider app
* Register SAML endpoints in case-insensitive manor
* OIDC endpoints should are registered in case-insensitive manor
Internal improvements and maintenance updates.
* Implement TAIProvider interface for Service Extensions
* Update log package to fix panic observed when running as non windows admin
* Rotate refresh tokens on use per OAuth security best practices
Internal improvements and maintenance updates.
* Implement token revocation for JWT
* Store JWT tokens in the cache
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
* Expose GetBytes, GetAny, and SetBytes on Service Extension session provider implementations
Internal improvements and maintenance updates.
* SAMLProvider validates signed authn requests received via HTTP-Redirect binding
* Implement v2.Session API for Service Extensions for OIDC Provider
* Add post logout redirect URL to proxy apps
* Return all claims for opaque access token
* Add logout to proxy apps
Internal improvements and maintenance updates.
* Add clock skew leeway for SAML Authn requests
* Stop Maverics process on failure to bind to a port
* Add support for IDP initiated login for app of type SAML
* Add support for HTTP Redirect binding in the SAML auth provider
* Organize LDAP Provider in preparation for SASL / GSS-SPNEGO / NTLM work
* Improve attribute loading error handling in proxy apps
* Add query params matching in proxy apps policies
* Add handleUnauthorizedSE to proxy apps
* Add upstream login extension to proxy apps
* Add support for IDP initiated login for the SAML provider
* Add ModifyRequest and ModifyResponse Service Extensions to proxy apps
* Add LoadAttrsSE to proxy apps
* Expose 'goPath' on v2 Service Extensions
* Add CreateHeader service extension to proxy apps
* Add IsAuthorized service extension to proxy apps
* Add IsAuthenticated and Authenticate extensions to proxy apps
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
* Add TLS to proxy apps
Internal improvements and maintenance updates.
* Resolved CVE-2023-45683
* Support multiple route patterns on a proxy app
* Add Orchestrator Groups cache support
* Add regexp policy matching to proxyapps
* Add attribute provider to proxy apps
* Resolved CVE-2023-39325
Internal improvements and maintenance updates.
* Support policy-level header definitions on proxy apps
# 2024
Source: https://docs.strata.io/changelog/orchestrator/2024
* **TLS:** Use Go's native implementation of 'x509.SystemCertPool' on Windows
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
* **Dependencies:** Resolved CVE-2024-45338
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
* **ldapProvider:** Correctly surface 'getHashedCredentialsSE' error
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
* **Secret provider:** Make CA not required for cert auth in HashiVault
* **Dependencies:** Resolved CVE-2024-45337
* Fix Missing Folder for Artifactory Cleanup Workflow
Internal improvements and maintenance updates.
* **Connectors:** Allow multiple OIDC callback URLs to be defined
Internal improvements and maintenance updates.
* **Dependencies:** Resolved CVE-2024-53259
* **Service Extensions:** Implement HTTP interface of Orchestrator API.
* **OIDC Connector:** Dynamically generate oauth logout callback URLs
* **SAML Provider:** Fix issue where authentication requests required an ACS URL
* **OIDC Provider:** Add support for 'ES256' key algorithm for client authentication
* **HTTP:** Add global endpoint timeout.
* **HTTP:** Add configurable HTTP server timeouts with sane defaults.
* Respect env variables and CLI flags when reloading logger
* **Proxy Apps:** Improve logging when required attributes are missing and not loadable
* **OIDC Connector:** Dynamically generate oauth callback URLs
* **OIDC Provider:** Improve logging during JWT bearer client authentication
Internal improvements and maintenance updates.
* Enable use of JWT for client authentication with client\_credentials grant
* **Container:** Resolved CVE-2024-9143
* **SAML APP:** Support multiple ConsumerServiceURLs per SAML app
Internal improvements and maintenance updates.
* **SAML Connectors:** Use POST binding if available during SAML login
* **Secret providers:** Support Hashicorp Vault cert auth on Windows
* **Config Reload:** Make logger reloadable
* **TLS:** Add support for ECDH algorithms on Windows
* Add CRL revocation support to tls config
* **SAML Provider:** Support compressed AuthnReq via POST binding
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
* **SAML & OIDC Providers:** Enable service extensions to be used in conjunction with attribute providers
Internal improvements and maintenance updates.
* Add OCSP revocation check
* **Logger:** Add error logger to HTTP server
* **OIDC Provider:** Require openid scope to access userinfo endpoint
* Support Hashicorp Vault cert auth on Linux
Internal improvements and maintenance updates.
* **Health service:** Make health service reloadable
* Update PR template to hide instructions
* **Connectors:** Generic SAML health check add cookies jar
* **QKSLVR-1987:** Upload additional artifacts JFrog
* **OIDC Provider:** Allow "sub" and "client\_id" claims to be overwritten via service extension
* Add Single Logout JSON Schema
Internal improvements and maintenance updates.
* Add deb build target in Makefile
* **OIDC Provider:** Dynamically build userinfo response
* **OIDC Provider:** Add association from token cache to userinfo cache
* **OIDC Provider:** Store userinfo data only once
* **Connectors:** Infer correct protocol binding from SAML metadata
* Expose 'jose.ContentType' in service extensions
* **Connectors:** Add support for login hint via subject in PingFed SAML
Internal improvements and maintenance updates.
* Update github PR template
* **Connectors:** Implement login\_hint in query for Azure SAML
* **SE:** Add 'postLogoutSEV2' service extension
* Ensure mTLS can not be bypassed by spoofing the Host header.
* **Connectors:** Restore SAML login in PingFed
* **Connectors:** Add login hint to OIDC connectors
* **Proxy apps:** Allow secrets loading in policy locations
* **SE:** Introduce v2 service extension signature for 'evalIdleTimeoutSE'
* Support retrieving AWS secrets via ARN
Internal improvements and maintenance updates.
* **TLS:** Add support for SNI via 'http.hosts'
* **SE:** Introduce v2 session evalMaxLifetime
* **Service Extensions:** Fix route registration issue
* Add newline delimiter option in CCP as workaround for multi-line secrets.
* Format the Hypr HTML to make it more readable
* **DSO-1348:** Add Uploading Artifacts for Services Team
* SAML App inherits signing cert from SAMLProvider
* **HTTP:** Rework HTTP initialization logic to support SNI
Internal improvements and maintenance updates.
* SAMLProvider fix panic when claims mapping attribute does not use connector notation
* Fix OIDCProvider panic when claims mapping attribute does not use connector notation
* **Bundle Validation:** Improve error handling when loading public key
* **TLS:** Rename 'clientCAs' to 'clientCAFiles' in TLS config
* **Continuity:** Improve reload behavior
* **Continuity:** Check for duplicated status codes
* **Continuity:** Add health check to ADFS
* **Connectors:** Make cert and keys paths optional for ADFS
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
* Support LoadAttributesSE for OIDC Apps
* Enable service extensions for oidc provider authorization
* Support multiple secrets for OIDC client authentication
* Add load attributes service extension to SAML apps
* Ensure OIDC clients are unique by client ID
* Expose make commands in make help
* **SAML Apps:** Support app level 'disableSignedAssertion' and 'disableSignedResponse'
* Add authorization rules to OIDC apps
Internal improvements and maintenance updates.
* **SAML Apps:** Support app-specific signing certs
* Support client defined grant types for OIDC apps
* **Continuity:** Remove body matching response logging
* Update mitchellh/mapstructure to go-viper/mapstructure/v2
* **Apps:** Validate 'name' uniqueness
* Support ROPC flow for OIDC apps via backchannel authenticate SE
* **Continuity:** Increase state parameter length in generic OIDC health check
* **Continuity:** Add TLS to custom health check
Internal improvements and maintenance updates.
* Support IsAuthorizedSE in SAML apps
* Add permissions for id-token for Jfrog Artifactory GitHub Workflow
* **Continuity:** Add custom health check response body matching
* Use the correct HTTP client for SAML health check
* **Continuity:** Add headers to custom health check endpoint
* Add QR authentication mode for Hypr connector
* Add GitHub workflow for uploading artifacts to JFrog Artifactory
* Update Artifactory GitHub Workflow to reference branch
* **Continuity:** Add ability to define custom health check
* **Continuity:** Change the default health check interval
* **Continuity:** Add un/healthy threshold
* Enforce authorization rules in SAML Apps
* **Continuity:** Support health checks in PingFederate connector
* Reimplement Cyberark Conjur Secret Provider
Internal improvements and maintenance updates.
* Add state to continuity enabled connectors
* Remove legacy LDAP 'attrproviders' implementation
* **Continuity:** Update IdP healthcheck metric prefix to include namespace
* **SAML APP:** Query for nameID attributeMapping attribute if not on session
* Update log level to error when referenced secret is not found
* **Continuity:** Add IDP health check to Auth0
* **Continuity:** Add IdP health metrics
* Expose ldap.Control
* Implement SAML health check in Okta
* Implement SAML health check in Azure
* Add AWS Secrets manager secret provider support
Internal improvements and maintenance updates.
* **Continuity:** Add generic SAML health check
* **Telemetry:** Update local Docker Compose telemetry environment for development
* Support reload for single logout config
* **Continuity:** Leverage generic OIDC health check in Okta and Azure
* **Continuity:** Add meter and tracer to health check service
* **Continuity:** Parse health check values as duration
* Protect session store with mutex and add session service to config reloader
* Implement session config reload
Internal improvements and maintenance updates.
* **Service Extensions:** Expose symbols for JWT encryption
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
* **MSI:** Fix file contention issue
Internal improvements and maintenance updates.
* **Continuity:** Add health check to OIDC connector
Internal improvements and maintenance updates.
* **OIDC & SAML Apps:** Remove legacy resilience implementation
* **Proxy apps:** Remove legacy resilience implementation
Internal improvements and maintenance updates.
* Redirect SAML SSO error responses correctly
* **Continuity:** Add health check to AD
* **Continuity:** Add health check to LDAP
* SAMLProvider support LogoutRequest via POST binding
Internal improvements and maintenance updates.
* **Connectors:** Gracefully handle failure to retrieve OIDC well-known metadata
* Verify Signed SAML Logout requests via Redirect binding
Internal improvements and maintenance updates.
* **SAML Apps:** Store logout request in cache
* Fix SAMLProvider cacheState storage when using multiple IDPs
* Add support for namespace in HashiVault
* **Resilience connector:** Add support for logout
* Unregister SAMLProvider SLO endpoint during stop
* **Connectors:** Better handle logout errors
* **Resilience connector:** Implement Query
Internal improvements and maintenance updates.
* Append query parameters to authn request during IDP Initiated SAML
* Validate bundle file in MSI installer
* **SAMLProvider:** Add SingleLogoutService to metadata when sloEndpoint is defined
* **SAMLProvider:** Implement SP initiated SLO
* **MSI:** Fix service restart when change and add default remote configs.
* **Service Extensions:** Expose symbols to enable JWT generation
Internal improvements and maintenance updates.
* **Connectors:** Set transport properties on health check HTTP client
* **SAML Connectors:** Fix panic observed when generating unsigned logout requests
* **Resilience Connector:** Add meter and tracer
* **Resilience Connector:** Add attributes mapping
* **Resilience Connector:** Add 'enabled' property and remove dependency on feature flag
* Add instructions on setting up the dev environment for the MSI Installer
* **Resilience connector:** Implement failover strategy
* Improve specificity of pull request instructions
* **Resilience Connector:** Add base config and validation
* **Resilience Connector:** Implement base lifecycle
* **SAML Apps:** Call BuildRelayState extension post-authentication
* **Resilient Connector:** Scaffold connector implementation
Internal improvements and maintenance updates.
* **SAML Apps:** Expose NameID configuration
* Include allowedProtectedPackages option for Service Extensions
* Introduce cache to SAMLProvider
* **SAML Apps:** Expose BuildRelayState service extension for IDP-initiated login flow
* MSI - Separate HTTP address field into IP and Port.
* **SAML Apps:** Allow IDP-initiated 'relayStateURL' field to be optionally defined
* MSI - Add documentation hyperlink to complex properties.
Internal improvements and maintenance updates.
* MSI - Auto set MAVERICS\_RELOAD\_CONFIG=true
* Fix log key to have correct attrProvider name
* MSI - Fix double configuration source error.
* MSI - Migrate system environment variables.
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
* **SAML & OIDC Apps:** Organize authprovider pkg and improve logging
* Manually validate timestamp assertions in SAML
Internal improvements and maintenance updates.
* Implement generic SAML in 1Kosmos and add cache
* Improve MSI UX flow for Bundle Key File selection.
* MSI - Find certificate should have empty selection.
* **SAML Apps:** Validate SP audience is unique before creation
* **Proxy Apps:** Add support for HTTP request methods in policy
* **OIDC Apps:** Add 'Authorization' to list of 'Access-Control-Allow-Headers' to fix CORS issue
* Resolved CVE-2024-22189
* Make Ping Fed use generic SAML package and introduce cache
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
* Fix remote config box gets cleared after selecting bundle public key file.
* **SAML Connectors:** Only sign SAML AuthnRequest if signing certs are provided
* OIDC ClaimsMapping -> LogicNodes
* Implements new MSI UI flow
* Minor changes to improve azure and connector behaviors
* Rename LogicNode IDP to Value
* Enhance SAML metadata parsing to support formatted certificates
* Support api.App in IsAuthenticatedSE, AuthenticateSE and v2/BuildClaimsSE for saml apps
* Support api.App in IsAuthenticatedSE, AuthenticatedSE, BuildAccessTokenClaimsSE, BuildIDTokenClaimsSE for oidc apps
* Add support RP-initiated logout in OIDC provider
* **NG-LDAP Provider:** Correctly handle a bind after the SASL security layer is active (Conformance)
* **NG-LDAP Provider:** Various improvements to logging and user config.
* Allow loading certs from Windows store in CyberArk CCP
* Support api.App in loginSE and isLoggedInSE for proxy apps
* Support api.App in createHeaderSE for proxy apps
* Support api.App in loadAttrsSE for proxy apps
* **NG-LDAP Provider:** Update Stability to Beta
Internal improvements and maintenance updates.
* **NG-LDAP Provider:** Fix context within SEs
* **Service Extensions:** Add missing Cache WithTTL option to SE symbols
Internal improvements and maintenance updates.
* **NG-LDAP Provider:** Improve logging
* **NG-LDAP Provider:** Handle Unbind
* **NG-LDAP Provider:** Add SASL/GSS-SPNEGO/NTLM handling into the connection handler
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
* Update error returned when end\_session\_endpoint isn't configured
Internal improvements and maintenance updates.
* Okta OIDC connector resilience
Internal improvements and maintenance updates.
* Implement CyberArkCCP
Internal improvements and maintenance updates.
* **NG-LDAP Provider:** Map user config to runtime parameters
Internal improvements and maintenance updates.
* Ensure appropriate errors are returned instead of http.ServeMux panic
* **NG-LDAP Provider:** Attach secure connection handler to server
* **NG-LDAP Provider:** Add NTLM Handler (Part 2)
* Azure connector resilience
Internal improvements and maintenance updates.
* **NG-LDAP Provider:** Add NTLM Handler (Part 1)
* **NG-LDAP Provider:** Handle Extended StartTLS
Internal improvements and maintenance updates.
* **Security:** Resolved CWE-409
* **NG-LDAP Provider:** Handle Search
* **NG-LDAP Provider:** Handle Simple Bind
* Expose service extension utility to enable WebLogic integration
Internal improvements and maintenance updates.
* **NG-LDAP Provider:** Add Simple Bind skeleton
* Pass query params from logoutURL to postLogoutRedirectURL
* **NG-LDAP Provider:** Add first packet processing layer
* **NG-LDAP Provider:** Fix panic on Orchestrator shutdown
* **NG-LDAP Provider:** Add initial connection skeleton
* Add capability to choose idp for authn with LogicNode
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
* **NG-LDAP Provider:** Add initial server connection logic
* Add LogicNode as path to enhancing IDP logic
* **NG-LDAP Provider:** Add SASL Security Layer (Security Sensitive)
Internal improvements and maintenance updates.
* **NG-LDAP Provider:** Add initial OIDs and message structure
Internal improvements and maintenance updates.
* **NG-LDAP Provider:** Add runtime params
Internal improvements and maintenance updates.
* **NG-LDAP Provider:** Add end-user config
* Add Service Extension symbols to enable AVP use case
Internal improvements and maintenance updates.
* **NG-LDAP Provider:** Add initial Service Extension signatures and parsing logic
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
* Parse Auth request properly to generate proper state param
* Move nested policy so that it can be reused across constructs
Internal improvements and maintenance updates.
* **NG-LDAP Provider:** Implement minimal lifecycle
Internal improvements and maintenance updates.
* Add LDAP provider to root of the config
* Create an initial structure for the next generation of the LDAP Provider
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
* Add configuration options to MSI installer and fix upgrade behavior
* Support loading service extension assets as a file system
* Add offline\_access to scopes\_supported in OIDC well-known endpoint
* Implement Context interface for service extensions
* Support retrieving App name from some v2 Service Extensions
* Expose orchestrator cache to service extensions
* Add client\_id to claims in access token
* Support login options in service extensions
* Resolved CVE-2023-49295
* Fixes refresh token length configuration
* Closes HTTP response body in connectors
* Omit the attempt to substitute env var if the line starts with '#'
* Close response body when making token request
* Resolved CVE-2023-48795
# 2025
Source: https://docs.strata.io/changelog/orchestrator/2025
* **MCP Proxy:** Harden implementation
* **MCP Proxy:** Proxy inbound client info when initializing session with upstream server
* **MCP Proxy:** Add networking configurations with reasonable defaults
* **Security:** Resolved CVE-2025-64702
* **MCP Provider:** Add namespacing for tools
* **MCP Proxy:** Expose streamable MCP Proxy app config
* **MCP Provider:** Remove default tools
* **OIDC Connector:** Use contextual logger when handling callback errors
* **MCP Proxy:** Add base proxy functionality
* **Service Extensions:** Fix ROPC initiated from within LDAP Provider SEs bug
* **MCP Proxy:** Add inbound and outbound authorization to tool calls
* **MCP Provider:** Update streamable MCP server and client to use custom Orchestrator logger
* **MCP Provider:** Make the MCP Provider server name configurable
* **MCP Proxy:** Add support for custom client TLS configurations
* **MCP Provider:** Add support for delegated token exchange to bridge apps
* **OIDC Provider:** Add support for X-Maverics-Oauth-Access-Token-Lifetime
* **MCP Provider:** Add per-tool access token lifetime configuration
* **Security:** Resolved CVE-2025-47914 and CVE-2025-58181
* **OIDC Provider:** Remove inherited audience in token exchange grant
* **OIDC Provider:** Add support for delegated token exchange
* **OIDC Provider:** Clean up logs made by session-less access token generation
* **OIDC Provider:** Add evaluation of access token minting policies to implicit/hybrid grants
* **OIDC Provider:** Add access token minting policies to ROPC grant
* **Security:** Resolved CVE-2025-47913
* **OIDC Provider:** Populate access token minting policy fields
* **LDAP Provider:** Add ability to determine the bound DN in Service Extensions
* **OIDC Provider:** Add access token minting policies to authorization code grant
* **Config Bundle:** Handle filesystem error and prevent panic
* **OIDC Provider:** Add access policy evaluation to refresh\_token grant
Internal improvements and maintenance updates.
* **OIDC Provider:** Handle authorization requests when made via POST
* **MCP Provider:** Add initial MCP proxy app config structure
* **OIDC Provider:** Add support for custom access token minting policies
* **Cache:** Add ability to disable key-prefixes on cache entries
* **config:** Ensure that multiple env vars are read in separately via json
* **MCP Provider:** Support inlined OpenAPI specs for MCP Bridge apps
* **OIDC Provider:** Support custom scopes with ROPC grant
* **OIDC Provider:** Preserve backwards-compatibility with unrecognized cu…
* **OIDC Provider:** Enable custom scopes for the authorization\_code grant type
* **MCP Provider:** Enable graceful shutdown of MCP clients via HTTP BaseContext
* **OIDC Provider:** Add support for custom scopes with the client\_credentials grant
* **OIDC Provider:** Add support for custom scopes with the refresh\_token grant
* **OIDC Provider:** Add support for custom scopes with the implict and hybrid grant types
* **OPA:** Update input schema for Rego policies
* **MCP Provider:** Add reload capability
* **Security:** Resolved CVE-2025-59530
* **OIDC Provider:** Add access policies to token exchange grant
* **FIPS:** Build a FIPS compliant version of the Debian package
* **MCP Bridge:** Add support for loading OPA policies from the filesystem
* **OIDC Provider:** Add custom scopes to token exchange grant
* **MCP Provider:** Add support for token exchange to bridge apps
* **OPA:** Setup OPA to be used across multiple Orchestrator components
* **MCP Provider:** Add support for loading OpenAPI files using relative paths
* **FIPS:** Build FIPS version of the RPM package
* **FIPS:** Build FIPS compliant version of the maverics docker image
* **Config:** Merge TLS settings from environment variables with Maverics config
* **MCP Provider:** Separate inbound and outbound authorization in support of token exchange
* **Connectors:** Add token exchange to OIDC connector
* **Config:** Merge TLS settings with Windows environment variables
* **MCP Provider:** Enhance observability and context around policy decisions
* **MCP Provider:** Add ability to make policy decisions based on the source IP address
* **MCP Provider:** Add base MCP docs for provider and bridge apps
* **MCP Broker:** Improve documentation
* **MCP Provider:** Use context bound logger in bearer token middleware
* **Security:** Fix mTLS security issue by starting with an empty cert pool when constructing 'ClientCAs' used in TLS configs
* **OIDC Provider:** Add option to configure refresh token lifetime
* **MCP Bridge:** Add basic Rego authorization policy
**Resolved Issues**
* Fixed an issue that prevented the Orchestrator from starting when loading configuration bundles larger than 1 MB from a GitHub repository.
**New Features**
* **Service Extensions:** Expose functions from the secp256k1 pkg to Service Extensions
**Resolved Issues**
* **OIDCProvider:** Support token revocation from `client_credentials` grant
* **Config:** Allow float when setting TLS Min Version
**Resolved Issues**
**OIDC Provider**
This release resolves an issue with the end-session endpoint not supporting POST requests. As per the [spec](https://openid.net/specs/openid-connect-rpinitiated-1_0.html), both GET and POST requests are now supported.
This release also resolves an issue with how redirect URIs are matched. The matching logic has been updated to not consider query params when validating the requested redirect URI against the pre-defined set of allowed redirect URIs.
**New Features**
**OIDC applications**
OIDC apps now support defining allowed origins and allowed credentials for CORS requests. For more information, please see the [CORS](https://developer.strata.io/orchestrator/configuration/app/oidc/#cors) documentation.
**New Features**
**Cloud Configuration Storage Providers**
Blob Storage in Azure Gov Cloud cloud can now be defined as a configuration storage provider. For more information, [read the docs](https://developer.strata.io/orchestrator/setup/remote-config/#azure-blob-storage).
**Secrets Providers**
Key Vault in Azure Gov Cloud can now be defined as a secret provider. The entraIDHost query parameter as part of the MAVERICS\_SECRET\_PROVIDER environment variable connection string. For more information, please see the [Azure Key Vault docs](https://developer.strata.io/orchestrator/setup/secrets-management/#entra-id-host-option).
**OIDC Provider**
The OIDC provider can now optionally correlate back-channel requests with the resource owner’s session. This can help you trace backchannel token requests to the resource owner. For more information, please see OIDC Provider [Session Correlation](https://developer.strata.io/orchestrator/configuration/providers/oidcprovider/#session-correlation).
**OIDC applications**
OIDC apps now support the insecureSkipPKCE option. This field can be used to bypass using PKCE when using the Authorization Code grant type for public clients.
**ATTENTION**:
Per [OAuth 2.0 Security Best Current Practice](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics#section-2.1.1), public clients MUST use PKCE when using the Authorization Code grant type. The insecureSkipPKCE option should only be used for legacy apps that are unable to use PKCE. Avoid using this configuration unless absolutely necessary.
**New Features**
**Connectors**
The offline access [feature](https://developer.strata.io/orchestrator/configuration/connectors/oidc-connector/#offline-access) found on OIDC connectors now ensures revoked ID token claims do not remain on the user's session. This change bolsters security by guaranteeing claims removed at the IDP do not remain on a user's session after a successful refresh request.
**Resolved Issues**
**Connectors**
SAML connectors now set the Maverics session cookie as part of SAML login flows. This fix ensures sticky session configurations that use application cookie persistence will continue to operate as expected.
**OIDC Provider**
The OIDC Provider now removes whitespace around redirect URLs.
**New Features**
**Connectors**
The OIDC and Azure connectors now support silently refreshing a resource owner's ID token and access token without user interaction. For more information, please see the [docs](https://developer.strata.io/orchestrator/configuration/connectors/oidc-connector/).
**OIDC Apps**
This release adds basic support for the token exchange grant (RFC 8693). Future releases will include additional functionality for the handling of custom scopes and for defining advanced access policies. For more information, please see the [docs](https://developer.strata.io/orchestrator/configuration/providers/oidcprovider/).
**New Features**
**Applications**
All application types now support aggregating authorization policy rules with different logical operators. This feature enables the creation of advances policies. For more information, please see the application [docs](https://developer.strata.io/orchestrator/configuration/app/).
**Security enhancements**
Patched security and performance related issues. Contact your account representative for a detailed overview.
**New features**
**Session Management**
This release introduces revamped session management in order to improve security, enhance performance, and to enable pluggable backing data stores. For more information, read the docs: [https://developer.strata.io/orchestrator/configuration/globalsettings/sessions-user-state/](https://developer.strata.io/orchestrator/configuration/globalsettings/sessions-user-state/)
**Resolved Issues**
* Resolved CVE-2025-49140 and CVE-2025-49140
**New Features**
**OIDC Applications**
OIDC applications can now be configured to use a default redirect URL. This option can be used for applications that are unable to set the `redirect_uri` parameter on the authorization request. For more information, see the [docs](https://developer.strata.io/orchestrator/configuration/app/oidc/#default-redirect-url)
ATTENTION: Per the OIDC RFC, the `redirect_uri` is a [required](https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest) parameter. The `allowDefaultRedirectURI` option should only be used for apps that are unable to provide a redirect URI. Strata recommends to avoid using this configuration unless absolutely necessary.
**New Features**
**SAML Provider**
The SAML Provider now has the ability to load the signing certificate and key from the filesystem. For more details, please see the [docs](https://developer.strata.io/orchestrator/configuration/providers/samlprovider/#signature).
**Service Extensions**
Service extensions can now leverage the `IsAvailable` method on the `idfabric.IdentityProvider` interface. This feature enables service extensions to determine whether a given IDP is available. For more info, please see the [docs](https://github.com/strata-io/service-extension/blob/main/idfabric/idfrabric.go#L19-L22).
**Resolved Issues**
**OIDC Apps**
This change adds the missing `at_hash` and `c_hash` claims to ID token during hybrid and implicit flows. These claims were previously missing and are required by the RFC.
**Service Extensions**
When calling `Login` with a nil HTTP request or response writer a runtime panic will no longer occur.
**New Features**
**Support for ROPC login option in Azure and Continuity identity services**
The Azure and Continuity identity services have been updated to support authentication via the Resource Owner Password Credentials (ROPC) grant. Service extensions can leverage the `WithGrantTypeROPC` login option to specify an ROPC flow for authenticating a user. This flow is typically used for legacy applications that require a username and password to authenticate the user directly.
For more information, please see the [docs](https://github.com/strata-io/service-extension/blob/main/idfabric/idfrabric.go#L95-L99).
**New Features**
**Support for ROPC login option in OIDC identity service**
Service extensions can now leverage a new login option that enables authentication via the Resource Owner Password Credentials (ROPC) grant. The `WithGrantTypeROPC` function specifies the ROPC flow for authenticating a user. This flow is typically used for legacy applications that require a username and password to authenticate the user directly. For more information, please see the [docs](https://github.com/strata-io/service-extension/blob/main/idfabric/idfrabric.go#L95-L99).
NOTE: Strata does not recommend using the ROPC flow for public facing applications. The OAuth 2.1 spec suggests a more secure flow, such as Authorization Code (with PKCE).
For more information, see [https://pkg.go.dev/github.com/strata-io/service-extension@v0.22.0/idfabric#WithGrantTypeROPC](https://pkg.go.dev/github.com/strata-io/service-extension@v0.22.0/idfabric#WithGrantTypeROPC)
**New Features**
**Support for multiple SAML entity IDs**
This release introduces support for defining multiple entity IDs on a SAML app. This functionality is compatible with both SP-initiated logins and IDP-initiated logins. For more information, please see the [docs](https://developer.strata.io/orchestrator/configuration/app/saml/).
**New Features**
**HYPR**
The HYPR connector now exposes a dynamic link and QR fallback code that can be used in custom login page templates. These fields serve as backup mechanisms for when scanning the QR code via the HYPR app fails. For more info, please see the [docs](https://developer.strata.io/orchestrator/configuration/connectors/hypr-connector/#custom-interstitial-page).
**New Features**
**OIDC Apps**
OIDC apps now support PKCE for public clients. This functionality enables applications that cannot securely store client credentials to interact with the Orchestrator as an OIDC Provider. For more information, please reference the [documentation](https://developer.strata.io/orchestrator/configuration/app/oidc/#public).
**New Features**
**Config Parsing**
This release introduces strict configuration validation. Any unknown fields, misspellings, or unrecognized keys will cause an immediate validation failure. These changes are intended to ensure configuration correctness and eliminate silently ignored errors that may lead to unexpected behavior.
**Breaking Changes**
Orchestrator v2025.05.1 removes many long-deprecated features. All removed features have a migration path to a supported substitute feature set. For more information, please reference the deprecation advisory notice issued in November 2024
**New features**
**Use Authorization Service Extension and Conditional Policies for authorization**
This release introduces the ability to use the IsAuthorized service extension and authorization rules together. This allows more granular control of user authorization to protected resources. This feature is supported on SAML, OIDC, and Proxy apps.
Note: Both the authorization service extension and the authorization rules must be validated as true to grant a user access. If either validates as false, the user is denied access.
For more details see [Authorization](https://developer.strata.io/orchestrator/configuration/app/oidc/#isauthorized-service-extension).
**Custom Unauthorized Page for SAML Apps**
SAML apps now support an error page for unauthorized users. Custom unauthorized pages for SAML apps will be configurable from the user interface in an upcoming release of the Maverics Console.
**New features**
**Support for custom query parameter in Entra ID (OIDC) and generic OIDC identity services**
Orchestrator now supports routing a custom query parameter to a declared Entra ID or OIDC IDP via service extension. Orchestrator passes the query parameter which then gets captured by the browser.
Service extensions should be updated per the Go documentation for idfabric: [https://pkg.go.dev/github.com/strata-io/service-extension@v0.20.0/idfabric](https://pkg.go.dev/github.com/strata-io/service-extension@v0.20.0/idfabric)
**Field ordering of orchestrator logs**
Readability of orchestrator logs can be improved by enabling `fieldOrdering` (optional). `fieldOrdering` organizes the fields in the log output, setting values in the following order: `ts` , `level`, `service`, `traceID`, `sessionID`, and `msg`.
Please note that enabling `fieldOrdering` will impact orchestrator performance. If performance must remain optimal, Strata recommends leaving this option disabled. For more information, see [Logging](https://developer.strata.io/orchestrator/configuration/monitoring/logger/#field-ordering).
**New features**
**Orchestrator heartbeat**
The Orchestrator now includes a heartbeat. This lightweight service logs runtime details at a configurable time interval. Enabled by default, the heartbeat service prints a log message containing the orchestrator ID, orchestrator version, orchestrator config version, as well as CPU count, usage, and total memory. By default, the heartbeat service logs at the info level.
The heartbeat service is part of the Health configuration block. It will be configurable from via user interface in an upcoming release of the Maverics Console. For more information, see [Heartbeat](https://developer.strata.io/orchestrator/configuration/monitoring/health/#heartbeat).
**Access logs enabled by default**
HTTP access logs are now enabled by default. This change is meant to provide customers with greater insight into how requests flow through the system and can be used to confirm that all requests result in a corresponding response.
By default, access logs are logged at the debug level. If desired, access logs can be disabled via the orchestrator config. Access logs will be configurable from via user interface in an upcoming release of the Maverics Console. For more information, see [Access Logs](https://developer.strata.io/orchestrator/configuration/globalsettings/http-server/#accesslog).
**LDAP custom login page and localization**
Orchestrator v0.111.0 introduces support for an optional custom login page when using LDAP as an IDP. By defining `customLogin` in the orchestrator configuration, the orchestrator delivers a custom HTML page stored in the filesystem.
In addition, the custom login page now supports standards-based language localization (BCP 47). By default, the localization selection is driven from the `Accept-Language` header, but can be customized to meet deployment specific needs.
LDAP custom login and localization will be configurable from via user interface in an upcoming release of the Maverics Console. For more information, see [Custom Login](https://developer.strata.io/orchestrator/configuration/connectors/ldap-connector/#custom-login).
**New features**
**Logging enhancements**
* Logs in the `CreateHeader` service extension have been updated to include `traceID`, `sessionID`, and `service` attributes.
* API service extensions can now leverage a newly exposed function that allows for retrieving a logger from the context of a request. The `log.WithRequest` function can be used to ensure logs include the `traceID` and `sessionID` attributes. For more information, refer to the [API examples](https://docs.strata.io/orchestrator/configuration/api/#examples).
INFO
Customers running API service extensions must update their service extensions to use the new function ONLY if they want to their logs to include `traceID` and `sessionID`. Strata advises customers to first test this new orchestrator release against their existing API service extensions in a lab or lower environment to ensure their service extensions continue to operate normally. For more information, refer to [Serve Service Extension](https://docs.strata.io/orchestrator/configuration/api/#serve-service-extension).
**Resolved issues**
This release resolves an issue in which orchestrator telemetry data was being sent to the Maverics Console even though telemetry was disabled. This issue was introduced in v0.107.0 and only impacts customers that are using Maverics Console.
**New features**
**Logging enhancements**
Logs in the following identity services have been updated to include `traceID` and `service` attributes:
* 1Kosmos
* HYPR
* PingFederate
* SAML
* Windows Client Authenticator (WCA)
* WSO2
API service extension logs have been updated to include `traceID`, `service`, 'seName', 'seFuncName', and 'seChecksum' attributes.
**Resolved issues**
* This release resolves an issue in which re-authentications triggered by session expiry would fail when an OIDC identity provider using PKCE.
* **APIs:** Enhance API SE logger with attributes by (#2879)
* **Connectors:** Use contextual logger in PingFederate connector (#2873)
* **Connectors:** Use contextual logger in SAML connector (#2876)
* **Connectors:** Use contextual logger in 1Kosmos connector (#2872)
* **Connectors:** Use contextual logger in WSO2 connector (#2877)
* **Connectors:** Use contextual logger in HYPR connector (#2869)
* **Connectors:** Use contextual logger in WCA connector (#2875)
* **Session:** Resolved issue causing newly Set attributes to have an expiry in the past (#2878)
**New Features**
Orchestrator v0.108.0 adds improvements to observability, including HTTP access logs, contextual logging, tracing, and standard telemetry. These changes provide more detailed logs for better insight into transactions from all areas of the orchestrator including service extensions.
**HTTP Access Logging**
All HTTP requests and responses are now optionally logged. Access logs are logged at debug level by default. Currently, access logs can be enabled/disabled in the orchestrator config. Access logging can be enabled/disabled from the user interface in a forthcoming update to Maverics Console. For more info, please see the [reference docs](https://docs.strata.io/orchestrator/configuration/globalsettings/http-server/#accesslog).
**Logging**
The logger now includes a `traceID` attribute in log messages that can be used to trace requests through the system. Additionally, logs now include the `service` key to help clearly identify the source of logs. For service extensions, the `seName`, `seFuncName`, and `seChecksum` keys are also now included.
**Security enhancements**
* **Security:** Resolved CVE-2025-22872
Internal improvements and maintenance updates.
* **Security:** Resolved CVE-2025-29923
* **Session v2:** Fix Cache Store Configuration
* **Dependencies:** Resolved CVE-2025-22870
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
* **OIDC Provider:** Expose config to disable the DPoP nonce
* **Connectors:** Preserve query parameters during LDAP logout
* **OIDC Provider:** Add customizable response\_mode to implicit flow
Internal improvements and maintenance updates.
* **Connector:** Implement LDAP connector Logout method
* **OIDC Provider:** Correct 'response\_types\_supported' and 'grant\_types\_supported' attributes of well-known response
* disable jfrog and e2e for testing orchestrator release process change
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
* **OIDC Provider:** Add implicit grant type
Internal improvements and maintenance updates.
* **Security:** Resolved CVE-2025-27144
Internal improvements and maintenance updates.
* **OIDC Provider:** Fix introspect endpoint not handling custom nested claims
* **Security:** Resolved CVE-2025-22869
* **Connectors:** Add support for error page to Auth0 connector
* **Connectors:** Add support for silent authentication to Auth0 connector
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
* **OIDC Provider:** Ensure reload works successfully when the end session endpoint is defined
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
* **Secret Provider:** Add support for multiple secret paths in hashicorp vault secret provider
* **Secret Provider:** Load Hashicorp Vault secrets lazily
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
* **OIDC Provider:** Expose DPoP-Nonce header to support CORS
* **OIDC Provider:** Harden DPoP implementation
Internal improvements and maintenance updates.
* **OIDC Provider:** Add support for dpop nonce validation
* **Observability:** Add new telemetry config format for metrics
Internal improvements and maintenance updates.
* **OIDC Provider:** Add support for dpop checking at userinfo endpoint
* **OIDC Provider:** Add support for DPoP bound refresh tokens
* **Proxy Apps:** Resolved attribute providers config not being respected
Internal improvements and maintenance updates.
* **OIDC Provider:** Add support opaque access tokens when using DPoP
* **Security:** Resolved CVE-2024-45339
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
* **OIDC Provider:** Update metadata endpoint to return DPoP signing algorithms
* **OIDC Provider:** Add support for DPoP bound access tokens
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
Internal improvements and maintenance updates.
# 2026
Source: https://docs.strata.io/changelog/orchestrator/2026
* **OAuth Connector:** Accept `expires_in` as a quoted string in token responses, fixing compatibility with identity providers that return the field as a string value rather than a number.
* **OAuth Connector:** Fix scopes not being sent during dynamic client registration.
* **OIDC Connector:** Add [RFC 7591 Dynamic Client Registration](/reference/orchestrator/identity-fabric/oauth#dynamic-client-registration) support. OIDC connectors can now register with identity providers dynamically, removing the need to pre-configure a static client ID and secret when the IdP supports Dynamic Client Registration.
* **OIDC Connector:** Add [Client ID Metadata Document (CIMD)](/reference/orchestrator/identity-fabric/oauth#client-id-metadata-document) support. OIDC connectors can now authenticate using URL-based client IDs, with the connector fetching and validating the Client ID Metadata Document at runtime.
* **OPA:** Add `jwt.parse_bearer` built-in function for Rego policies. Policies can now parse and inspect JWT bearer tokens directly without a service extension.
* **MCP Provider:** Fix intermittent tool listing failures when multiple concurrent requests were in-flight simultaneously.
### Security Improvements
### Proxy apps
* Authorization policy is now evaluated against the same normalized request path that is forwarded upstream, giving consistent policy matching for URLs that contain encoded characters or path parameters.
* The mutual-TLS host guard now normalizes the Host header (case and port) before matching a request to its virtual host, so requests are consistently associated with the intended host configuration.
### OIDC Provider
The form\_post authorization response now HTML-escapes the redirect URI when rendering the auto-submitting form, ensuring redirect URIs containing reserved characters are handled correctly.
### Feature Deprecations
The following features have been removed from the Orchestrator and are no longer supported:
* (Experimental) Orchestrator Clusters
* LDAP Provider: Remove SASL, GSS-SPNEGO, and NTLM authentication mechanisms
### Enhancements
* OIDC Provider: Add support for complex types in access token claims mapping
* OIDC Provider: CIMD apps now only issue refresh tokens when explicitly requested and when administrator-enabled
### Bug Fixes
* **Config:** Pre-flight config validation prevents startup loop. The Orchestrator now validates configuration before starting up, preventing a bad config from causing a crash-restart loop. Invalid configurations are rejected at startup with a clear error instead.
* **MCP Proxy:** MCP tools list correctly handles unreachable upstreams. list-tools calls no longer fail when one or more upstream MCP servers are unreachable. Available tools are returned from reachable upstreams while unreachable ones are skipped gracefully.
* **MCP Provider:** `WWW-Authenticate` header uses absolute URL for `resource_metadata`. The `resource_metadata` field in `WWW-Authenticate` challenge responses now correctly returns an absolute URL, fixing compatibility issues with MCP clients that use it to locate the protected resource metadata document.
* **OIDC Provider:** Access token claims mapping applied to CIMD clients. `accessToken.claimsMapping` configuration is now correctly applied when issuing tokens to OIDC CIMD apps. Previously, claims mapping was accepted by the config but silently ignored for CIMD clients.
* **OIDC Provider:** Add support for claims mapping for access tokens
* **OAuth Connector:** Improve login callback validation and avoid unnecessary JWKS fetches during authentication
* **OIDC Connector:** Fix PKCE generation to exclude special characters
* **MCP Provider:** Reconcile proxied tools per session, ensuring MCP clients see a consistent and current tool list throughout a session.
* **Orchestrator:** Add support for graceful process restarts, reducing downtime during config changes and enabling everything except ports to be updated without a full restart.
* **OIDC Provider:** Refresh upstream access tokens during passthrough token brokering
* **Licensing:** Updated terms and conditions URL in startup event log to point to the current Rubrik–Strata service agreement
* **Authenticate Service Extension:** Add `idfabric.WithForceAuthentication()` support. When called from `authenticateSE`, the connector is instructed to actively re-authenticate the user with the IdP even if an existing session is present. The SAML connector is the first to implement this, sending `ForceAuthn="true"` on the AuthnRequest. See the [documentation](/reference/orchestrator/service-extensions/proxy#force-re-authentication-on-every-login) for configuration details.
* **MCP Proxy:** Add OPA-based tool listing control via a new `listing` authorization block. The policy is evaluated once per tool in every `tools/list` response from the upstream server; only tools where the policy returns `allowed=true` are forwarded to the client. Policies evaluate against upstream tool names before namespace prefixing, keeping them consistent with `inbound` call-time policies. See the [documentation](/reference/orchestrator/applications/mcp-proxy#tool-filtering-opa) for configuration details.
## \[Experimental] Client ID Metadata Documents (CIMD)
The Orchestrator now supports dynamic OAuth client registration via URL-based client IDs, implementing `draft-ietf-oauth-client-id-metadata-document`. AI agents and MCP clients (Claude Code, ChatGPT) can authorize without being pre-registered — the Orchestrator fetches and validates the client's metadata document at runtime.
Configure using the new `oidcCimd` app type. See the [full documentation](https://docs.strata.io/reference/orchestrator/experimental/client-id-metadata-documents) for configuration reference and examples.
### Security
* Resolved security issues
## Hardened encryption of Redis-cached values
This release strengthens how the Orchestrator encrypts values stored in an external Redis cache. The on-disk format of cached entries has changed as a result.
No action required on upgrade. The Orchestrator adopts the new format automatically. Entries written by earlier versions are ignored and expire on their own TTL if configured with a TTL. You do not need to flush or modify Redis, and no users are signed out — session stores do not use the Redis cache.
**What to expect after upgrading:**
* **OIDC Provider.** Refresh tokens issued before the upgrade are invalidated. Applications re-authorize on their next refresh; for users with an active session this is seamless, with no sign-in prompt. Existing JWT access tokens remain valid until they expire. The transition completes within your refresh-token lifetime (default 24 hours). Clients that authenticate without a user session, such as machine-to-machine clients, may need to re-authenticate once. Existing opaque access tokens will need to be re-issued.
* **SAML Provider.** Flows in progress at the moment of upgrade may need to be retried. Established sessions are unaffected.
* **Service Extensions.** Cached entries from before the upgrade are treated as misses and repopulated on next use. If an extension combines direct key access (disable-prefix) with value encryption, re-write previously stored values, as they are unreadable in the new format.
* **Multi-node deployments.** Complete the rollout promptly. Mixed-version clusters may not share cached entries, causing a temporary rise in re-authentications until all nodes are upgraded.
### Fixes
* **OIDC Provider:** Return HTTP 400 for login callback failures caused by client errors
Internal improvements and maintenance updates.
## Filter MCP tools by access token
MCP Proxy apps can now apply an OPA **connection authorization** policy that decides, per upstream MCP server, whether the gateway connects to it and lists its tools — evaluated against the caller's access token. Instead of surfacing every upstream's tools to every client, you can scope which tools each session sees based on identity.
* **MCP Proxy:** Add OPA policy support for connection authorization, filtering which upstream MCP tools are exposed to a session based on the access token
## Deployments
* **Google Cloud Config Storage:** Add read-only scope and workload identity support for the GCP config provider
### Fixes
* **MCP Provider:** Fix HTTP deadline not being cleared when MCP is enabled, which could cause requests to time out unexpectedly
* **MCP Proxy:** Clean up upstream MCP sessions when the downstream session ends
* **Service Extensions:** Fix configuration bundle asset access for proxy app's `CreateHeader`, single logout's `ParsePostLogoutSE`, and session's `ParseEvalIdleTimeoutSE` and `ParseEvalMaxLifetimeSE` service extensions
* **OIDC Apps:** Allow non-identity-provider namespaces to be used in token brokering exchange template interpolation
* **MCP Proxy:** Fixed token audience validation so a token is accepted when any one of its listed audiences matches an expected value, instead of being rejected unless all audiences matched.
* **MCP Proxy:** Fixed a signature verification issue that could block requests when multiple MCP servers are configured.
* **Token Brokering (experimental):** Add [Federated Exchange](/reference/orchestrator/experimental/token-brokering) flow, where the Orchestrator mints a short-lived JWT and exchanges it with an upstream authorization server (e.g., Databricks, GCP Workload Identity Federation). Mappings also support dynamic claim values via templating interpolation.
* **OIDC Connector:** Add `disableClientAuthentication` for federation flows where the upstream authenticates via the subject token alone (e.g., Databricks account-wide federation)
* **OIDC Provider:** Add support for RFC 7638-compliant JWK thumbprints as the `kid`. Opt in per signing key with `useRFC7638Thumbprint: true` — coordinate with relying parties first, since the `kid` will change.
* **OIDC Client:** Cache the actor token used in `client_credentials`-backed token exchange requests
* **OIDC Provider:** Allow clients with only non-interactive grants to omit authentication
* **Telemetry:** Add support for v1 OTel configuration
* **Security:** Resolved security issues
* **Config:** Fixed `MAVERICS_DEBUG_MODE=true` being silently ignored when a `logger:` block was configured. Setting the env var now correctly forces DEBUG-level logging as documented.
## What's new
**MCP**
Significantly expanded MCP observability so operators can run at info and still get full session traceability and audit coverage — no more flipping to debug to reconstruct what happened.
* Every MCP request log now carries a hashed mcpSessionID, giving you end-to-end correlation across a client-to-Maverics session without exposing the raw Mcp-Session-Id credential.
* Proxy-path logs also carry an upstreamMCPSessionID, so you can follow a single interaction from the client, through Maverics, to the upstream MCP server on the same line.
* Every tool call emits a single tool call completed log at info with an outcome of success, tool\_error, or failed — consistent across bridge and proxy modes.
* Every list-tools call emits a single list tools completed log at info with the outcome and tool count.
* Session register/unregister and upstream session established/terminated events are now surfaced at info.
* Raw session IDs never appear in logs or traces.
### Fixed
**MCP Proxy**
Fixed an issue where responses from upstream MCP servers using gzip compression could reach the client corrupted or unreadable. Compressed responses are now handled correctly.
### Improvements
**Logging**
Audit and security events now log at info level. This makes them visible in standard log pipelines without needing to lower global log thresholds, so your SIEM and observability tooling will pick them up by default.
* **Logout:** Fix bug where logout redirect URLs containing pre-existing query parameters (e.g., Azure B2C custom policy endpoints with `?p=`) produced malformed URLs with duplicate `?` characters, causing downstream parameters like `id_token_hint` and `state` to be silently dropped
* **MCP Proxy:** Fix path parameter handling and improve tolerance for common schema quirks in MCP bridge apps built from OpenAPI specs
* **OIDC Provider:** Add [token brokering](/reference/orchestrator/experimental/token-brokering) (experimental) to the OIDC provider. Clients can exchange a Maverics access token for upstream service tokens using standard RFC 8693 token exchange. The initial release supports session passthrough mode, which returns a cached upstream token. Token brokering integrates with existing OPA token minting policies for authorization.
* **Telemetry:** Add W3C `traceparent` header propagation to maintain a stable traceID across the entire request lifecycle. When a request enters the Orchestrator, the traceID is preserved and forwarded to all downstream services — including identity providers and MCP endpoints — enabling true end-to-end distributed tracing with a single, consistent identifier. This is especially valuable when the Orchestrator acts as an auth provider to an AI Identity Gateway, where a single user prompt can trigger a chain of token exchanges, policy evaluations, and tool invocations across multiple services. With a stable traceID, operators can trace an AI gateway request from initial authentication through policy evaluation, token minting, and downstream MCP tool calls, correlating every hop in a single distributed trace.
* **SAML Provider:** Make NameID name qualifiers optional
* **SAML Provider:** Fix WS-Fed name claim incorrectly being included in SAML assertions
* **SAML Provider:** Correct XML namespacing across all SAML response types
* **Telemetry:** Add stable Secure Orchestrator ID (`soid`) to all log entries and OTel telemetry (`service.instance.id`) for deployment correlation
* **OIDC Connector:** Add configurable error handling for authentication callbacks
* **OIDC Provider:** Fix state parameter encoding in form post response mode
* **Security:** Resolved security issues
* **MCP Proxy:** Gracefully re-establish session with the upstream MCP server and retry the request when the session is terminated
* **Proxy Apps:** Allow service extensions to be reused across all application types by loosening namespace validation
* **Connectors:** HYPR connector now reads custom HTML files from the configuration bundle
* **MCP Proxy:** Gracefully re-establish sessions with upstream and retry requests when a session is terminated
* **Proxy Apps:** Allow service extensions to be reused across all app types
* **Connectors:** Support reading custom HTML files from the configuration bundle for Hypr integrations
* **TLS:** Add max version configuration for all TLS settings
* **Session:** Fixed an issue where empty sessions were persisted when the SLO endpoint terminated an unestablished session
* **MCP Proxy:** Add configurable scopes and token lifetimes for all MCP protocol operations
* **Security:** Resolved security issues
* **Security:** Resolved CVE-2026-2405
* **MCP Proxy:** Respect outbound authorization policy when making list tools requests
* **SAML Apps:** Enable claims mapping and the BuildClaims service extension to be used together
* **MCP Proxy:** Explicitly handle session termination errors that are returned from the upstream
* **OIDC Connector:** Add client assertion authentication mechanism (rfc 7523)
* **OIDC Connector:** Add support for JWT client assertion authentication as part of the token exchange grant
* **OIDC Provider:** Demonstrate JWT client authentication can be used with authcode, token-exchange grants
* **OIDC Provider:** Make openid scope and scope param optional
* **SAML Provider:** Ensure SAML Response elements are ordered correctly
* **OIDC Provider:** Add Subject and Actor token claims to token minting policy
# Connect ChatGPT to the AI Identity Gateway
Source: https://docs.strata.io/guides/ai-identity/connect/chatgpt
Connect ChatGPT to the AI Identity Gateway so that ChatGPT can discover and invoke MCP tools with full identity, authentication, and authorization on every call.
When ChatGPT connects to the AI Identity Gateway as an MCP client, it goes through the standard OAuth discovery flow -- discovering the authorization server from the Gateway's protected resource metadata (RFC 9470), authenticating the user, and obtaining an access token. From there, ChatGPT can discover and invoke any MCP tools the Gateway exposes through [MCP Bridge](/guides/ai-identity/mcp-bridge) or [MCP Proxy](/guides/ai-identity/mcp-proxy) apps.
## How ChatGPT's Token Works
ChatGPT authenticates the user and sends a standard OAuth access token where the `sub` claim is the authenticated user. The token does **not** include delegation semantics -- there is no `act` claim or separate agent identity. From the token alone, the Gateway cannot distinguish "ChatGPT acting on behalf of the user" from "the user directly."
This has implications for how the Gateway evaluates and processes requests:
* **Inbound authorization policies** operate on the token as received. Since ChatGPT does not perform a token exchange before calling the Gateway, inbound OPA policies see only the claims in the access token -- user identity claims (`sub`, `email`, `groups`, etc.) and the `client_id` identifying the OAuth client. The `client_id` is a required claim in JWT access tokens per [RFC 9068](https://datatracker.ietf.org/doc/html/rfc9068#name-data-structure), so admins can write policies that target ChatGPT traffic by matching on it. When using CIMD, the `client_id` is a URL (e.g., `https://chatgpt.com/oauth/{id}/client.json`) rather than a simple string -- see the policy example in [Harden Tool Access](#harden-tool-access-with-inbound-authorization-policies).
* **Outbound token exchange** is where the Gateway adds delegation semantics. When the Gateway performs [RFC 8693](https://datatracker.ietf.org/doc/html/rfc8693) token exchange to call upstream APIs via MCP Bridge or MCP Proxy, it can mint delegation tokens with an `act` claim that includes the agent's client identity. This gives upstream services visibility into both the user and the agent that initiated the request.
ChatGPT uses [OAuth Client ID Metadata Documents
(CIMD)](https://datatracker.ietf.org/doc/draft-ietf-oauth-client-id-metadata-document/)
natively, presenting a verifiable HTTPS URL as its `client_id`. This is a
meaningful improvement over agents that use self-asserted client identity
strings -- the Auth Provider Orchestrator fetches and validates the metadata
document, giving inbound policies a cryptographically grounded client
identity to match on.
## Prerequisites
* **A running AI Identity Gateway** -- Follow the [AI Identity overview](/guides/ai-identity/overview) to set up the Auth Provider Orchestrator and AI Identity Gateway Orchestrator with at least one MCP Bridge or MCP Proxy app configured.
* **OAuth authorization enabled on the MCP Provider** -- The Gateway's `mcpProvider.authorization.oauth` must be enabled so ChatGPT can authenticate. See the [AI Identity Gateway reference](/reference/modes/ai-identity-gateway) for configuration details.
* **ChatGPT Business or Enterprise/Edu account** -- Creating and publishing workspace apps requires a Business or Enterprise/Edu workspace. Owners and Admins can publish apps; individual members install them.
## Register ChatGPT as an OAuth Client
Configure the **Auth Provider Orchestrator** to accept ChatGPT using [Client ID Metadata Documents (CIMD)](/reference/orchestrator/experimental/client-id-metadata-documents). CIMD eliminates the need to pre-register a client ID, secret, redirect URLs, or scopes -- a single `oidcCimd` app with `allowedDomains: [chatgpt.com]` is all that is required. See the [CIMD reference](/reference/orchestrator/experimental/client-id-metadata-documents) for configuration steps and options.
## Connect ChatGPT to the Gateway
Once the Auth Provider Orchestrator is configured, a workspace Owner or Admin creates and publishes the ChatGPT app so that workspace members can install it. ChatGPT routes all MCP traffic through OpenAI's infrastructure, so the AI Identity Gateway and Auth Provider Orchestrator must both be accessible from the public internet.
ChatGPT connects to the AI Identity Gateway through OpenAI's infrastructure.
The Gateway and Auth Provider Orchestrator must both be publicly accessible --
local or private network URLs (e.g., `localhost`, `127.0.0.1`, private DNS)
will not work without tunneling.
**Admin setup:**
Go to **[chatgpt.com/admin/apps](https://chatgpt.com/admin/apps)**. You must be a workspace Owner or Admin to access this page.
Click **+ Create**. The **New App** dialog opens.
Enter a **Name** and optional **Description** for the app. Under **Connection**, ensure **Server URL** is selected and enter the AI Identity Gateway's MCP endpoint:
```
https://your-gateway.example.com/mcp
```
Click **Advanced OAuth settings** to open the OAuth configuration panel. Ensure **Authentication** is set to **OAuth** and that the **Registration method** shows **Client Identifier Metadata Document (CIMD)**. ChatGPT selects both automatically based on what the Auth Provider supports.
Check the **I understand and want to continue** box, then click **Create**. ChatGPT saves the app as a draft.
In the **Drafts** tab, click **Publish** next to your app. Review and acknowledge each security risk section, check both confirmation boxes, and click **Publish** to confirm.
The app moves to the **Enabled** tab with a **CUSTOM** label and becomes visible to all workspace members.
**Member setup:**
Each workspace member authenticates individually to ensure ChatGPT only accesses tools the member is authorized to use:
1. In ChatGPT, click **Plugins** in the left sidebar.
2. Click the workspace tab (your organization's name) to see apps published by your admin.
3. Find the AI Identity Gateway app and click **+** to install it.
4. Complete the OAuth flow -- authenticate with your identity provider when prompted.
Once connected, the Gateway's MCP tools are available in conversations.
## Verify the Connection
After connecting, verify that ChatGPT can discover and invoke tools from the AI Identity Gateway.
1. **Check tool discovery** -- Ask ChatGPT to list available tools. ChatGPT should display the MCP tools exposed by your MCP Bridge and MCP Proxy apps.
2. **Invoke a tool** -- Ask ChatGPT to call one of the discovered tools. The AI Identity Gateway authenticates the request, evaluates authorization policies, performs token exchange, and returns the result.
3. **Check the Orchestrator logs** -- The AI Identity Gateway Orchestrator logs show the complete request flow: agent authentication, OPA policy evaluation, token exchange, and upstream API call. Verify that all steps completed successfully.
If ChatGPT cannot discover tools or tool invocations fail, see the troubleshooting
sections in the [Expose APIs to Agents](/guides/ai-identity/mcp-bridge#troubleshooting)
and [Protect MCP Servers](/guides/ai-identity/mcp-proxy#troubleshooting) guides.
# Connect Claude to the AI Identity Gateway
Source: https://docs.strata.io/guides/ai-identity/connect/claude
Connect Claude Desktop, Claude Code, or claude.ai to the AI Identity Gateway so that Claude can discover and invoke MCP tools with full identity, authentication, and authorization on every call.
When Claude connects to the AI Identity Gateway as an MCP client, it goes through the standard OAuth discovery flow -- discovering the authorization server from the Gateway's protected resource metadata (RFC 9470), authenticating the user, and obtaining an access token. From there, Claude can discover and invoke any MCP tools the Gateway exposes through [MCP Bridge](/guides/ai-identity/mcp-bridge) or [MCP Proxy](/guides/ai-identity/mcp-proxy) apps.
## How Claude's Token Works
Claude authenticates the user and sends a standard OAuth access token where the `sub` claim is the authenticated user. The token does **not** include delegation semantics -- there is no `act` claim or separate agent identity. From the token alone, the Gateway cannot distinguish "Claude acting on behalf of the user" from "the user directly."
This has implications for how the Gateway evaluates and processes requests:
* **Inbound authorization policies** operate on the token as received. Since Claude does not perform a token exchange before calling the Gateway, inbound OPA policies see only the claims in the access token -- user identity claims (`sub`, `email`, `groups`, etc.) and the `client_id` identifying the OAuth client. The `client_id` is a required claim in JWT access tokens per [RFC 9068](https://datatracker.ietf.org/doc/html/rfc9068#name-data-structure), so admins can write policies that target Claude traffic by matching on it (e.g., `input.token.client_id == "claude"`). The token does not carry delegation semantics -- there is no `act` claim distinguishing "Claude acting on behalf of the user" from "the user directly."
* **Outbound token exchange** is where the Gateway adds delegation semantics. When the Gateway performs [RFC 8693](https://datatracker.ietf.org/doc/html/rfc8693) token exchange to call upstream APIs via MCP Bridge or MCP Proxy, it can mint delegation tokens with an `act` claim that includes the agent's client identity. This gives upstream services visibility into both the user and the agent that initiated the request.
Today, Claude's `client_id` is a self-asserted string (e.g., `"claude"`) with
no cryptographic proof of the agent's identity. Because Claude is a closed
platform, customers are limited to what Claude supports out of the box --
unlike custom agents or other AI clients, which can implement proof of
possession, delegation chains, workload attestation, and other advanced
identity patterns directly.
Several emerging standards aim to address agent identity and delegation:
* [**OAuth Client ID Metadata Documents (CIMD)**](https://datatracker.ietf.org/doc/draft-ietf-oauth-client-id-metadata-document/)
strengthen client identity by using an HTTPS URL as the `client_id`. The
authorization server fetches and validates the metadata document, providing
verified (rather than self-asserted) client identity for policy decisions.
* [**WIMSE**](https://datatracker.ietf.org/wg/wimse/about/) (Workload Identity
in Multi-System Environments) and [**SPIFFE**](https://spiffe.io/) (Secure
Production Identity Framework For Everyone) provide cryptographically
attested workload identity, enabling agents to prove who they are
independently of OAuth client registration.
* The [**AI Agent Authentication and Authorization**](https://datatracker.ietf.org/doc/draft-klrc-aiagent-auth/)
IETF draft ties these together, proposing that agents are workloads with
WIMSE/SPIFFE identifiers and that access tokens carry dual identity:
`client_id` as the agent's verifiable workload identity and `sub` as the
delegated user.
None of these standards solve delegation in isolation, but together they
define a path toward tokens that carry both verified agent identity and user
identity. Realizing this requires Claude to both establish a verifiable agent
identity (via CIMD, WIMSE, or SPIFFE) **and** perform a token exchange before
calling the Gateway -- producing a token that carries the user as the subject
and the agent as the actor. Without token exchange, the token represents only
the user regardless of how the agent identifies itself during the OAuth flow.
Until Claude natively supports these patterns, the Gateway's inbound policies
for Claude traffic can match on `client_id` and user identity claims but
cannot distinguish delegation from direct access. Customers can use
[service extensions](/reference/orchestrator/service-extensions) such as
`buildAccessTokenClaimsSE` to construct an `act` claim that simulates
delegation semantics by embedding the client identity as the actor. The
service extension should derive these values from a trusted source within the
Auth Provider's request context, not from upstream identity provider
attributes that could be manipulated.
## Prerequisites
* **A running AI Identity Gateway** -- Follow the [AI Identity overview](/guides/ai-identity/overview) to set up the Auth Provider Orchestrator and AI Identity Gateway Orchestrator with at least one MCP Bridge or MCP Proxy app configured. The Gateway must use the **Streamable HTTP** transport -- SSE is not supported by Claude's connector infrastructure.
* **OAuth authorization enabled on the MCP Provider** -- The Gateway's `mcpProvider.authorization.oauth` must be enabled so Claude can authenticate. See the [AI Identity Gateway reference](/reference/modes/ai-identity-gateway) for configuration details.
* **Claude Desktop, Claude Code, or a claude.ai account** -- Any Claude client that supports remote MCP servers works with this guide.
Claude requires an interactive OAuth flow where a user authenticates via the
browser. The `client_credentials` grant type (machine-to-machine OAuth with no
user interaction) is not supported by Claude's MCP connector infrastructure.
Register Claude with the `authorization_code` and `refresh_token` grant types.
See the [Anthropic Connectors Directory FAQ](https://support.claude.com/en/articles/11596036-anthropic-connectors-directory-faq)
for details on Claude's connector requirements.
## Choose a Client Type
When you register Claude as an OAuth client with the Auth Provider Orchestrator, you choose between a **confidential client** or a **public client**. This choice affects how Claude authenticates to the authorization server.
| | Confidential Client | Public Client |
| ------------------ | --------------------------------------------------- | --------------------------------------------------------------------- |
| **Authentication** | Client ID + client secret | Client ID + PKCE (no secret) |
| **Security** | Stronger -- the secret proves the client's identity | Weaker -- relies on PKCE alone to protect the authorization code flow |
| **Best for** | Claude Code (CLI), server-side integrations | Environments where a client secret cannot be securely stored |
| **Grant types** | Authorization Code, Refresh Token | Authorization Code (with PKCE), Refresh Token |
Use a **confidential client** whenever possible. Confidential clients authenticate
with a client secret, which proves the client's identity to the authorization
server and prevents unauthorized applications from exchanging authorization codes
for tokens. Public clients rely solely on PKCE, which protects against code
interception but does not authenticate the client itself.
[OAuth Client ID Metadata Documents (CIMD)](https://datatracker.ietf.org/doc/draft-ietf-oauth-client-id-metadata-document/)
address this gap by allowing public clients to use a verifiable HTTPS URL as
their `client_id`, giving the authorization server a way to verify the client's
identity without a shared secret. As the MCP ecosystem adopts CIMD and
authorization servers add support, public clients will be able to provide
verified identity comparable to confidential clients. Until then, use a
confidential client when the deployment allows it, and pair public clients with
[token minting policies](#harden-token-issuance-with-token-minting-policies) to
compensate.
## Register Claude as an OAuth Client
Register Claude as an OIDC application on the **Auth Provider Orchestrator** -- the same orchestrator deployment that issues tokens for the AI Identity Gateway. This gives Claude the credentials it needs to authenticate and obtain access tokens.
Go to **Applications** in the sidebar and click **Create**. Select **OIDC-based** from the application type list.
Enter a **Name** for the application (e.g., `Claude`).
Enter a **Client ID** (e.g., `claude`). Leave **Client Authentication Method** set to **Client Secret**. Click **Add Client Secret** and enter a strong secret or a [secret provider](/reference/orchestrator/configuration/secret-providers) reference (e.g., ``).
Store client secrets in a [secret provider](/reference/orchestrator/configuration/secret-providers) rather than entering them directly. Use secret reference syntax so the Orchestrator resolves the value at runtime.
Click **Add Redirect URL** and add the redirect URLs for the Claude clients you plan to use:
* **claude.ai and Claude Desktop:** `https://claude.ai/api/mcp/auth_callback` and `https://claude.com/api/mcp/auth_callback`
* **Claude Code:** `http://localhost:{PORT}/callback` where `{PORT}` is a fixed port you choose (e.g., `http://localhost:29352/callback`). Users must pass `--callback-port {PORT}` when adding the MCP server in Claude Code. See the [Connect Claude Code](#connect-claude-to-the-gateway) section for details.
* **Claude Desktop via mcp-remote:** `http://localhost:{PORT}/oauth/callback` (e.g., `http://localhost:3334/oauth/callback`). Note the `/oauth/callback` path -- this differs from Claude Code's `/callback` path.
Under **Grant Types**, ensure the following are checked:
* **Authorization Code** (under Recommended and Modern Flows)
* **Refresh Token** (under Recommended and Modern Flows)
Uncheck **Client Credentials** -- it is not needed for Claude's user-facing OAuth flow.
Leave **Type** set to **JWT**. Optionally set **Lifetime Seconds** (default is 1 hour).
Under **Refresh Token Settings**, toggle **Allow Offline Access** on. This lets Claude refresh expired access tokens without requiring you to re-authenticate.
Click **Save** to create the OIDC application.
Add a new OIDC app to the Auth Provider Orchestrator's configuration. The client uses the `authorization_code` and `refresh_token` grant types with a client secret for authentication.
```yaml maverics.yaml theme={null}
apps:
- name: claude
type: oidc
clientID: claude
credentials:
secrets:
-
grantTypes:
- authorization_code
- refresh_token
redirectURLs:
# claude.ai and Claude Desktop web connectors (routed through Anthropic)
- https://claude.ai/api/mcp/auth_callback
- https://claude.com/api/mcp/auth_callback
# Claude Code -- fixed port via --callback-port (connects directly from user's machine)
- http://localhost:29352/callback
# Claude Desktop via mcp-remote -- note /oauth/callback path differs from Claude Code
- http://localhost:3334/oauth/callback
accessToken:
type: jwt
lifetimeSeconds: 3600
refreshToken:
allowOfflineAccess: true
lifetimeSeconds: 86400
authentication:
idps:
- upstream-idp
claimsMapping:
email: upstream-idp.email
name: upstream-idp.name
sub: upstream-idp.sub
```
The `redirectURLs` include all Claude clients:
* **claude.ai and Claude Desktop** both use `https://claude.ai/api/mcp/auth_callback`. Include the `claude.com` variant as well to future-proof the configuration.
* **Claude Code** uses `http://localhost:{PORT}/callback`. By default, Claude Code picks a random port, but since redirect URLs must be pre-registered, you must choose a fixed port (e.g., `29352`) and have users specify `--callback-port 29352` when adding the MCP server.
* **Claude Desktop via mcp-remote** uses `http://localhost:{PORT}/oauth/callback` (note the `/oauth/callback` path, which differs from Claude Code's `/callback`). The default port is `3334`.
Store the client secret in a [secret provider](/reference/orchestrator/configuration/secret-providers). Never hardcode secrets in configuration files.
Go to **Applications** in the sidebar and click **Create**. Select **OIDC-based** from the application type list.
Enter a **Name** for the application (e.g., `Claude Public`).
Enter a **Client ID** (e.g., `claude-public`). You do not need to add a client secret -- public clients authenticate using PKCE instead.
Under **Application Security Settings**, toggle **Public Client** on. This disables client secret authentication and restricts the available grant types to Authorization Code (with PKCE), Refresh Token, and Implicit flows.
Public clients cannot authenticate themselves to the authorization server.
Any application that knows the client ID can initiate an authorization flow.
Only use public clients when you cannot securely distribute a client secret.
Click **Add Redirect URL** and add the redirect URLs for the Claude clients you plan to use:
* **claude.ai and Claude Desktop:** `https://claude.ai/api/mcp/auth_callback` and `https://claude.com/api/mcp/auth_callback`
* **Claude Code:** `http://localhost:{PORT}/callback` where `{PORT}` is a fixed port you choose (e.g., `http://localhost:29352/callback`). Users must pass `--callback-port {PORT}` when adding the MCP server in Claude Code.
* **Claude Desktop via mcp-remote:** `http://localhost:{PORT}/oauth/callback` (e.g., `http://localhost:3334/oauth/callback`). Note the `/oauth/callback` path -- this differs from Claude Code's `/callback` path.
Ensure the **Bypass Proof Key for Code Exchange (PKCE)** toggle is **off** (the default). Public clients must use PKCE to protect the authorization code flow.
Under **Grant Types**, ensure the following are checked:
* **Authorization Code** (under Recommended and Modern Flows)
* **Refresh Token** (under Recommended and Modern Flows)
Leave **Type** set to **JWT**. Optionally set **Lifetime Seconds** (default is 1 hour).
Under **Refresh Token Settings**, toggle **Allow Offline Access** on.
Click **Save** to create the OIDC application.
Add a new OIDC app to the Auth Provider Orchestrator's configuration with `public: true`. Public clients do not use a client secret -- they rely on PKCE to protect the authorization code flow.
```yaml maverics.yaml theme={null}
apps:
- name: claude-public
type: oidc
clientID: claude-public
public: true
grantTypes:
- authorization_code
- refresh_token
redirectURLs:
# claude.ai and Claude Desktop web connectors (routed through Anthropic)
- https://claude.ai/api/mcp/auth_callback
- https://claude.com/api/mcp/auth_callback
# Claude Code -- fixed port via --callback-port (connects directly from user's machine)
- http://localhost:29352/callback
# Claude Desktop via mcp-remote -- note /oauth/callback path differs from Claude Code
- http://localhost:3334/oauth/callback
accessToken:
type: jwt
lifetimeSeconds: 3600
refreshToken:
allowOfflineAccess: true
lifetimeSeconds: 86400
authentication:
idps:
- upstream-idp
claimsMapping:
email: upstream-idp.email
name: upstream-idp.name
sub: upstream-idp.sub
```
Public clients cannot authenticate themselves to the authorization server.
Any application that knows the client ID can initiate an authorization flow.
Only use public clients when you cannot securely distribute a client secret.
Registration is not complete until the application is bound to an identity connector, which tells the Orchestrator which IdP authenticates users. In the Console UI, you finish this from the application's own settings; in YAML, the `authentication.idps` field you already set on the app handles it directly.
If you haven't already, add your identity connector to the Auth Provider deployment's **Identity Fabric**. Navigate to **Identity Fabric** in the sidebar, click **Create**, and select your IdP's connector type (e.g., Entra ID, Okta, or Keycloak). The connector must exist before you can select it as an application's authentication source.
Navigate to **Applications** in the sidebar and open your Claude application.
In the application's **Resources** card, click **Edit**, then click **Add Resource** and select the identity connector you added in the previous step. Click **Save**. A connector must be added as a resource before it can be selected as an authentication source.
Find the **Access Control** card and click **Edit**. From the **Select an authentication source** dropdown, choose the connector you just added, then click **Save**.
Navigate to the deployment's **Settings** page and click **Publish Preview** in the footer bar. Review the configuration diff, optionally add a revision note, and click **Publish**. The Orchestrator picks up the new configuration on its next poll cycle.
See [Publishing Deployment Configs](/reference/console/config-publishing) for details on the publishing lifecycle.
No additional step is needed. The `authentication.idps` field in the OIDC app configuration (shown in the previous step) already binds the app to your identity connector. The Orchestrator reads this directly from the configuration file.
## Connect Claude to the Gateway
Once Claude is registered as an OAuth client and associated with your identity connector, configure your Claude client to connect to the AI Identity Gateway's MCP endpoint. Claude will automatically discover the authorization server via the Gateway's protected resource metadata and prompt you to authenticate.
How you connect depends on whether the AI Identity Gateway is publicly accessible or on a private network:
* **Publicly accessible Gateway** -- All client tabs below work. Use a **confidential client** (client ID + secret) so the secret proves the client's identity to the authorization server. The **Organization (Team / Enterprise)** tab configures a web connector that routes through Anthropic's infrastructure -- both the Gateway and Auth Provider Orchestrator must be reachable from the public internet.
* **Private / internal Gateway** -- Select the **Claude Code** or **Claude Desktop** tab below. These clients connect directly from your machine, so local and private network URLs work. Use a **public client** (client ID + PKCE, no secret) to avoid distributing and managing secrets across individual machines.
Add the AI Identity Gateway as a remote MCP server using the Claude Code CLI. Claude Code connects directly from your machine, so the Gateway does not need to be publicly accessible. The Auth Provider Orchestrator requires pre-registered OAuth clients rather than Dynamic Client Registration (DCR), giving administrators full control over which applications can request tokens. You must pass the OAuth client credentials explicitly when adding the server. You also need `--callback-port` to fix the OAuth redirect URI to match the pre-registered redirect URL.
If you registered Claude as a **public client** on the Auth Provider Orchestrator, pass only `--client-id`. Claude Code uses PKCE (Proof Key for Code Exchange) to protect the authorization code flow -- no client secret is needed.
```bash theme={null}
claude mcp add \
--transport http \
--client-id claude-public \
--callback-port 29352 \
ai-identity-gateway https://your-gateway.example.com/mcp
```
* `--client-id claude-public` provides the OAuth client ID so Claude Code can authenticate without DCR.
* `--callback-port 29352` fixes the OAuth redirect URI to `http://localhost:29352/callback`, matching the redirect URL registered in the OIDC app. Without this flag, Claude Code picks a random port that would not match.
Public clients are a good fit when Claude Code connects directly to a Gateway on a local or private network, since there is no client secret to manage or protect on each user's machine.
If you registered Claude as a **confidential client**, pass both `--client-id` and `--client-secret`. This is the recommended approach when the Gateway is publicly accessible, as the secret proves the client's identity to the authorization server.
```bash theme={null}
claude mcp add \
--transport http \
--client-id claude \
--client-secret YOUR_CLIENT_SECRET \
--callback-port 29352 \
ai-identity-gateway https://your-gateway.example.com/mcp
```
Replace `YOUR_CLIENT_SECRET` with the client secret you configured in the OIDC app on the Auth Provider Orchestrator.
* `--client-id claude` and `--client-secret` provide the OAuth credentials so Claude Code can authenticate without DCR.
* `--callback-port 29352` fixes the OAuth redirect URI to `http://localhost:29352/callback`, matching the redirect URL registered in the OIDC app. Without this flag, Claude Code picks a random port that would not match.
The `--client-secret` flag stores the secret in Claude Code's MCP configuration
file. For shared or production environments, consider using a secret
that can be rotated, and restrict file permissions on the configuration file.
When you start a Claude Code session, Claude connects to the Gateway, discovers the authorization server, and opens your browser for OAuth authentication.
**Managing the connection:**
```bash theme={null}
# List all configured MCP servers
claude mcp list
# View details for the Gateway server, including OAuth config
claude mcp get ai-identity-gateway
# Remove the server
claude mcp remove ai-identity-gateway
```
Inside a Claude Code session, use the `/mcp` slash command to check server status, authenticate, and manage connections:
* **Authenticate** -- Run `/mcp` and select the AI Identity Gateway to open the browser OAuth flow. Claude Code stores tokens securely and refreshes them automatically.
* **View available tools** -- After authenticating, Claude automatically discovers tools from the Gateway. Ask Claude to list available tools or use `/mcp` to check the server's connection status and tool count.
* **Clear authentication** -- Run `/mcp`, select the AI Identity Gateway, and choose **Clear authentication** to revoke the stored OAuth tokens. Use this when switching users, troubleshooting token issues, or revoking access.
* **Reauthenticate** -- After clearing authentication, run `/mcp` again and select the Gateway to start a fresh OAuth flow.
For more details on Claude Code's MCP support, see [Connect Claude Code to tools via MCP](https://docs.anthropic.com/en/docs/claude-code/mcp).
Claude Desktop routes all remote MCP traffic through Anthropic's cloud infrastructure. This means the AI Identity Gateway and Auth Provider Orchestrator must both be publicly accessible for Claude Desktop to reach them -- this applies to all remote MCP servers, not just those requiring OAuth. To connect Claude Desktop to the AI Identity Gateway, use one of the following approaches:
* **Organization web connector** (Team / Enterprise plans) -- See the **Organization (Team / Enterprise)** tab. Admins configure the Gateway URL and OAuth credentials centrally. Requires a publicly accessible Gateway.
* **mcp-remote proxy** -- Use the open-source [`mcp-remote`](https://github.com/geelen/mcp-remote) package as a local stdio proxy that handles the OAuth flow and MCP communication on your behalf. Because Claude Desktop treats `mcp-remote` as a local stdio server, the actual network connection to the Gateway happens directly from the user's machine -- so the Gateway does not need to be publicly accessible.
### Connect with mcp-remote
[`mcp-remote`](https://github.com/geelen/mcp-remote) is a local stdio proxy that bridges Claude Desktop to remote MCP servers. It handles OAuth discovery, PKCE, token storage, and token refresh locally, then forwards MCP requests to the Gateway. Because it runs as a local process, it connects directly from the user's machine, bypassing Anthropic's cloud infrastructure.
`mcp-remote` is an open-source third-party component not maintained by Strata.
Strata does not attest to its security, compliance, or suitability for any
purpose, and provides no warranty or guarantees regarding its use. Evaluate it
against your organization's security requirements before deploying.
If you are interested in a Strata-supported Claude Desktop extension that can be
centrally distributed across your enterprise, [contact us](https://www.strata.io/contact).
See [Building Desktop Extensions with MCPB](https://support.claude.com/en/articles/12922929-building-desktop-extensions-with-mcpb)
for background on the desktop extension model.
Open Claude Desktop and navigate to **Settings** > **Developer** > **Edit Config**. This opens the `claude_desktop_config.json` file.
Add an entry under `mcpServers` that runs `mcp-remote` as a local stdio server. Use the `--static-oauth-client-info` flag to provide the pre-registered OAuth client credentials, since the Auth Provider Orchestrator requires pre-registered clients rather than Dynamic Client Registration (DCR). Include a port number after the Gateway URL to fix the OAuth callback port -- by default `mcp-remote` uses port `3334`, but you can choose any available port. The redirect URL registered in the OIDC app must match `http://localhost:{PORT}/oauth/callback`.
Use `--transport http-only` since the AI Identity Gateway uses Streamable HTTP. Without this flag, `mcp-remote` defaults to `http-first` which attempts an SSE fallback on failure, potentially causing duplicate connections and authentication issues.
If you registered Claude as a **public client** on the Auth Provider Orchestrator, provide only the `client_id`. `mcp-remote` uses PKCE (Proof Key for Code Exchange) to protect the authorization code flow -- no client secret is needed.
```json claude_desktop_config.json theme={null}
{
"mcpServers": {
"ai-identity-gateway": {
"command": "npx",
"args": [
"mcp-remote",
"https://your-gateway.example.com/mcp",
"3334",
"--transport", "http-only",
"--static-oauth-client-info",
"{\"client_id\":\"claude-public\"}"
]
}
}
}
```
Public clients are a good fit when Claude Desktop connects to a Gateway on a local or private network, since there is no client secret to manage or protect on each user's machine.
To avoid JSON escaping issues in `claude_desktop_config.json`, you can
store the OAuth client info in a separate file and reference it with the
`@` prefix:
```json oauth_client_info.json theme={null}
{ "client_id": "claude-public" }
```
```json claude_desktop_config.json theme={null}
"args": [
"mcp-remote",
"https://your-gateway.example.com/mcp",
"--static-oauth-client-info",
"@/path/to/oauth_client_info.json"
]
```
If you registered Claude as a **confidential client**, provide both the `client_id` and `client_secret` in the static OAuth client info. This is the recommended approach when the Gateway is publicly accessible, as the secret proves the client's identity to the authorization server.
```json claude_desktop_config.json theme={null}
{
"mcpServers": {
"ai-identity-gateway": {
"command": "npx",
"args": [
"mcp-remote",
"https://your-gateway.example.com/mcp",
"3334",
"--transport", "http-only",
"--static-oauth-client-info",
"{\"client_id\":\"claude\",\"client_secret\":\"YOUR_CLIENT_SECRET\"}"
]
}
}
}
```
Replace `YOUR_CLIENT_SECRET` with the client secret you configured in the OIDC app on the Auth Provider Orchestrator.
The `client_secret` is embedded in the configuration file in plain text.
Restrict file permissions on `claude_desktop_config.json` and consider
using a secret that can be rotated. You can also store the credentials
in a separate file and reference it with `@/path/to/oauth_client_info.json`.
Close and reopen Claude Desktop to pick up the new configuration. When you start a conversation, `mcp-remote` connects to the Gateway, discovers the authorization server via protected resource metadata (RFC 9470), and opens your browser for OAuth authentication. Tokens are stored locally in `~/.mcp-auth/` and refreshed automatically.
For more details on configuring MCP servers in Claude Desktop, see [Connect to local MCP servers](https://modelcontextprotocol.io/quickstart/user).
On Claude Team and Enterprise plans, an organization **Owner** can add the AI Identity Gateway as a managed **web connector** that is available to all team members. This centralizes the configuration -- admins set the Gateway URL and OAuth credentials once, and individual members just click **Connect** and authenticate with their own identity.
Web connectors route traffic through Anthropic's infrastructure. The AI Identity
Gateway and Auth Provider Orchestrator must both be accessible from the public
internet. Local or private network URLs (e.g., `localhost`, `127.0.0.1`, private
DNS) will not work with web connectors. For private or internal gateways, use the
**Claude Code** or **Claude Desktop** tabs instead.
The **Add** dialog in Organization settings offers both **Web** and **Desktop**
connector types. Choose **Web** for the AI Identity Gateway. The **Desktop** option
is for uploading packaged desktop extensions (`.mcpb` files) that run locally on
users' machines -- it is not used for remote MCP servers.
**Admin setup:**
In claude.ai, go to **Organization settings** > **Connectors**.
Click **Add** and select **Custom** > **Web**. Enter the AI Identity Gateway's MCP endpoint URL:
```
https://your-gateway.example.com/mcp
```
Click **Advanced settings** and enter the **OAuth Client ID** and **OAuth Client Secret** from the OIDC app you registered on the Auth Provider Orchestrator. The Auth Provider Orchestrator requires pre-registered OAuth clients rather than Dynamic Client Registration (DCR), so Claude needs these credentials to authenticate.
Click **Add**. The connector now appears in the organization's connector list, visible to all team members.
**Member setup:**
Each team member authenticates individually to ensure Claude only accesses tools the member is authorized to use:
1. Go to **Settings** > **Connectors** in claude.ai.
2. Find the AI Identity Gateway connector (labeled **Custom**) and click **Connect**.
3. Complete the OAuth flow -- authenticate with your identity provider when prompted.
Once connected, the Gateway's MCP tools are available in conversations. Members can enable or disable the connector per conversation.
For details on plan requirements and connector management, see [Get started with custom connectors using remote MCP](https://support.claude.com/en/articles/11175166-get-started-with-custom-connectors-using-remote-mcp).
## Verify the Connection
After connecting, verify that Claude can discover and invoke tools from the AI Identity Gateway.
1. **Check tool discovery** -- Ask Claude to list available tools. Claude should display the MCP tools exposed by your MCP Bridge and MCP Proxy apps. Tool names include the namespace prefix (e.g., `my_api_listUsers`).
2. **Invoke a tool** -- Ask Claude to call one of the discovered tools. For example: "List all users using the my\_api\_listUsers tool." The AI Identity Gateway authenticates the request, evaluates authorization policies, performs token exchange, and returns the result.
3. **Check the Orchestrator logs** -- The AI Identity Gateway Orchestrator logs show the complete request flow: agent authentication, OPA policy evaluation, token exchange, and upstream API call. Verify that all steps completed successfully.
If Claude cannot discover tools or tool invocations fail, see the troubleshooting
sections in the [Expose APIs to Agents](/guides/ai-identity/mcp-bridge#troubleshooting)
and [Protect MCP Servers](/guides/ai-identity/mcp-proxy#troubleshooting) guides.
## Harden Tool Access with Inbound Authorization Policies
The AI Identity Gateway Orchestrator evaluates [OPA inbound authorization policies](/guides/security/policies#ai-identity-gateway-opa-authorization) on every MCP tool call before it reaches the upstream service. While token minting policies (below) govern whether a token is issued at all, inbound authorization policies govern what an agent can do with that token -- controlling which tools are accessible, under what conditions, and for which callers.
This is the primary mechanism for enforcing least-privilege access at the tool level. Policies can inspect the tool name, tool arguments, HTTP headers (including the JWT), source IP, and any other field in the [MCP app input schema](/guides/security/policies#mcp-app-input-schema).
### Example: Separate Read and Write Access to Sensitive Data
The following policy allows agents with `hr:read` scope to query employee data, but requires `hr:admin` scope to create or update records. This prevents AI agents from modifying sensitive HR data unless explicitly authorized with elevated permissions:
```yaml maverics.yaml theme={null}
apps:
- name: hr-api
type: mcpBridge
authorization:
inbound:
type: opa
opa:
name: hr-read-write-separation
rego: |
package orchestrator
default result["allowed"] := false
# Decode the bearer token's claims. Undefined when the header is
# absent or is not a JWT, so the rules below fail and deny.
jwt_payload := jwt.parse_bearer(input.request.http.headers.Authorization)
# Read-only tools require hr:read scope.
result["allowed"] if {
input.request.mcp.tool.params.name in ["listEmployees", "getEmployee"]
contains(jwt_payload.scope, "hr:read")
}
# Write tools require hr:admin scope.
result["allowed"] if {
input.request.mcp.tool.params.name in ["createEmployee", "updateEmployee"]
contains(jwt_payload.scope, "hr:admin")
}
result["internal_message"] := sprintf("denied %s for client %s", [
input.request.mcp.tool.params.name,
jwt_payload.client_id,
]) if {
not result.allowed
}
result["external_message"] := "insufficient permissions for this operation" if {
not result.allowed
}
```
See the [Authorization Policies guide](/guides/security/policies#ai-identity-gateway-opa-authorization) for the full input schema, output schema, and additional examples.
## Harden Token Issuance with Token Minting Policies
The Auth Provider Orchestrator supports [OPA token minting policies](/guides/security/policies#configure-opa-token-minting-policies-oidc-provider-only-optional) that evaluate every token request before issuance. These policies add a governance layer on top of OAuth client registration -- even after a user authenticates successfully, the Orchestrator can deny or constrain the token based on client identity, grant type, requested scopes, or environmental conditions.
This is especially valuable when using **public clients**. Because public clients authenticate with only a client ID and PKCE (no secret), any application that knows the client ID can initiate an authorization flow. Token minting policies let you enforce additional constraints at the point of token issuance to compensate -- for example, restricting which networks can mint tokens for a given client.
**Public client** is an OAuth term describing how the client authenticates (no
secret, PKCE only) -- it does not mean the Gateway is publicly accessible. A
public client can connect to a Gateway on a private network (e.g., Claude Code
or Claude Desktop via mcp-remote connecting to an internal Gateway). Similarly,
a publicly accessible Gateway can use confidential clients. The client type and
deployment model are independent choices.
### Example: Restrict a Private Gateway to Corporate Networks
The following policy ensures that the public client `claude-public` can only mint tokens when the request originates from the corporate network. This is useful when the Gateway is on a private network and you want to ensure tokens are only issued to users connecting from known internal ranges:
```yaml maverics.yaml theme={null}
apps:
- name: claude-public
type: oidc
clientID: claude-public
public: true
grantTypes:
- authorization_code
- refresh_token
authorization:
tokenMinting:
accessToken:
policies:
- name: restrict-public-client-by-network
rego: |
package orchestrator
default result := {"allowed": true}
# Only allow the public client to mint tokens from the
# corporate network.
result := {"allowed": false, "internal_message": "public client not allowed from this network"} {
input.request.oauth.client_id == "claude-public"
not net.cidr_contains("10.0.0.0/8", input.source.ip)
}
redirectURLs:
# claude.ai and Claude Desktop web connectors (routed through Anthropic)
- https://claude.ai/api/mcp/auth_callback
- https://claude.com/api/mcp/auth_callback
# Claude Code -- fixed port via --callback-port (connects directly from user's machine)
- http://localhost:29352/callback
# Claude Desktop via mcp-remote -- note /oauth/callback path differs from Claude Code
- http://localhost:3334/oauth/callback
accessToken:
type: jwt
lifetimeSeconds: 3600
refreshToken:
allowOfflineAccess: true
lifetimeSeconds: 86400
authentication:
idps:
- upstream-idp
claimsMapping:
email: upstream-idp.email
name: upstream-idp.name
sub: upstream-idp.sub
```
This policy denies token issuance for `claude-public` unless the request originates from the `10.0.0.0/8` CIDR range. Replace the CIDR with your organization's internal network range. You can combine multiple `net.cidr_contains` checks to allow several network ranges.
Source IP checks are a useful defense-in-depth measure but should not be your
only security control. Client IPs can be obscured by proxies, VPNs, or NAT,
and the `input.source.ip` value reflects the immediate connection to the
Orchestrator, which may be a load balancer or reverse proxy rather than the
end user's machine. Use IP restrictions alongside other controls -- such as
user authentication, PKCE, and scoped token lifetimes -- rather than relying
on them in isolation.
### Example: Restrict a Public Gateway to Anthropic's IP Ranges
When the Gateway is publicly accessible and Claude connects via claude.ai or Claude Desktop web connectors, traffic arrives from [Anthropic's published outbound IP ranges](https://platform.claude.com/docs/en/api/ip-addresses). The following policy restricts token issuance to requests originating from these ranges:
```
package orchestrator
default result := {"allowed": true}
# Only allow token minting from Anthropic's outbound IP ranges.
# See https://platform.claude.com/docs/en/api/ip-addresses
# for the current ranges.
result := {"allowed": false, "internal_message": "request not from Anthropic IP range"} {
not anthropic_ip
}
anthropic_ip {
# Anthropic outbound IPv4
net.cidr_contains("160.79.104.0/21", input.source.ip)
}
anthropic_ip {
# Anthropic outbound IPv6
net.cidr_contains("2607:6bc0::/48", input.source.ip)
}
```
If you also support Claude Code or Claude Desktop via mcp-remote (which connect directly from users' machines), combine the Anthropic ranges with your corporate network ranges:
```
package orchestrator
anthropic_ip {
# Anthropic outbound IPv4
net.cidr_contains("160.79.104.0/21", input.source.ip)
}
anthropic_ip {
# Anthropic outbound IPv6
net.cidr_contains("2607:6bc0::/48", input.source.ip)
}
corporate_ip {
net.cidr_contains("10.0.0.0/8", input.source.ip)
}
result := {"allowed": false, "internal_message": "request not from allowed network"} {
not anthropic_ip
not corporate_ip
}
```
Token minting policies can inspect any field in the token request, including `input.request.oauth.client_id`, `input.request.oauth.scope`, `input.request.oauth.audience`, `input.request.oauth.grant_type`, and `input.source.ip`. See the [token minting policy reference](/guides/security/policies#configure-opa-token-minting-policies-oidc-provider-only-optional) for the full input schema.
### IP Allowlisting for Public Deployments
When the AI Identity Gateway and Auth Provider Orchestrator are publicly accessible, you can restrict inbound traffic to known IP ranges as an additional layer of protection. Understanding the traffic flow is important for applying restrictions at the right layer:
* **User's browser → Auth Provider** -- During the OAuth authorization step, the user's browser connects directly to the Auth Provider Orchestrator's authorize endpoint. This traffic comes from the user's IP, not Anthropic's.
* **Anthropic's backend → Auth Provider** -- Token exchange and token refresh requests are made server-side by Anthropic's infrastructure. This traffic comes from [Anthropic's published outbound IP ranges](https://platform.claude.com/docs/en/api/ip-addresses).
* **Anthropic's backend → Gateway** -- MCP tool calls are routed through Anthropic's infrastructure. This traffic also comes from Anthropic's outbound IP ranges.
This means IP restrictions apply differently depending on the component:
* **Gateway infrastructure-level allowlisting** -- The Gateway can be locked down to [Anthropic's outbound IP ranges](https://platform.claude.com/docs/en/api/ip-addresses) (`160.79.104.0/21` for IPv4, `2607:6bc0::/48` for IPv6) since only Anthropic's backend connects to it for web connectors. Use your cloud provider's firewall, security groups, WAF, or reverse proxy.
* **Auth Provider infrastructure-level allowlisting** -- The Auth Provider cannot be restricted to Anthropic's IPs alone because the user's browser must reach the authorize endpoint during the OAuth flow. However, it does not need to be open to the entire internet -- organizations can restrict access to Anthropic's outbound IP ranges **plus** their own users' networks using VPNs, corporate IP allowlists, device management policies, or conditional access controls. The key requirement is that both Anthropic's infrastructure and the user's device can reach the Auth Provider.
* **Auth Provider token minting policies** -- OPA token minting policies evaluate at the token endpoint, where requests come from Anthropic's backend (for web connectors) or the user's machine (for Claude Code / mcp-remote). Use the examples above to restrict by source IP at this layer.
* **Gateway inbound authorization policies** -- Use OPA policies on the AI Identity Gateway to restrict tool invocations by source IP. This controls who can call tools even with a valid token.
Anthropic publishes stable outbound IP addresses for MCP tool calls from
claude.ai and Claude Desktop. See [Anthropic IP Addresses](https://platform.claude.com/docs/en/api/ip-addresses)
for the current ranges. These addresses will not change without notice.
For Claude Code and Claude Desktop via mcp-remote, traffic originates from
the user's machine rather than Anthropic's infrastructure. Whether
infrastructure-level IP allowlisting is practical for these clients depends
on your network topology and trust domains -- organizations with well-defined
corporate IP ranges can allowlist those ranges alongside token minting and
Gateway authorization policies.
## Troubleshooting
The redirect URI Claude sends does not match what is configured in the OIDC
app's `redirectURLs`.
**Resolution:**
1. Check the Auth Provider Orchestrator logs for the exact `redirect_uri`
value Claude is sending.
2. Add that exact URI (including scheme, host, port, and path) to the OIDC
app's `redirectURLs` array.
3. For **claude.ai and Claude Desktop**, ensure both `https://claude.ai/api/mcp/auth_callback`
and `https://claude.com/api/mcp/auth_callback` are in the redirect URLs list.
4. For **Claude Code**, ensure you passed `--callback-port` when adding the MCP
server, and that `http://localhost:{PORT}/callback` with that port is in the
redirect URLs list. Without `--callback-port`, Claude Code picks a random port
that will not match any pre-registered URL.
5. For **Claude Desktop via mcp-remote**, ensure `http://localhost:{PORT}/oauth/callback`
is in the redirect URLs list. Note the `/oauth/callback` path -- this differs
from Claude Code's `/callback` path. The default port is `3334`.
If Claude connects and authenticates but sees no tools:
* Verify that MCP Bridge or MCP Proxy apps are configured and running on the
AI Identity Gateway Orchestrator.
* Check that the agent's token has the required scopes for tool discovery.
* Review the AI Identity Gateway Orchestrator logs for errors during tool
registration or upstream connection failures.
* Confirm that inbound OPA policies do not block tool listing.
If Claude does not prompt you to authenticate when connecting to the Gateway:
* Verify that `mcpProvider.authorization.oauth.enabled` is `true` on the AI
Identity Gateway Orchestrator.
* Check that the Gateway's `/.well-known/oauth-protected-resource` endpoint
is reachable and returns valid metadata.
* Ensure the Auth Provider Orchestrator's well-known endpoint is listed in the
Gateway's `mcpProvider.authorization.oauth.servers` configuration.
* For Claude Desktop, confirm you restarted the application after editing the
configuration file.
If Claude's session stops working after the access token expires:
* Verify that the OIDC app's `grantTypes` includes `refresh_token`.
* Check that `refreshToken.allowOfflineAccess` is `true` in the OIDC app
configuration.
* Confirm the refresh token has not expired (check `refreshToken.lifetimeSeconds`).
* If using a confidential client, ensure the client secret has not been
rotated or revoked since the session was established.
When a user disconnects a connector in claude.ai or Claude Desktop, Anthropic
removes the tokens from its systems but does **not** revoke them at the identity
provider. Access and refresh tokens on the Auth Provider Orchestrator remain
valid until they expire, and session cookies are not cleared.
**Resolution:**
* Set short `accessToken.lifetimeSeconds` values (e.g., 300--900 seconds) to
limit the window of validity after disconnection.
* Set `refreshToken.lifetimeSeconds` to bound how long a refresh token can
extend a session.
* If immediate revocation is required, revoke the user's session directly on
the Auth Provider Orchestrator or upstream identity provider.
If `mcp-remote` fails with `UNABLE_TO_VERIFY_LEAF_CERTIFICATE` or similar
TLS errors, the Gateway's certificate is not trusted by Node.js. This is
common with self-signed certificates, internal CAs, or VPN-intercepted
connections.
**Resolution (recommended):** Point `NODE_EXTRA_CA_CERTS` to your
organization's CA certificate file so Node.js trusts the Gateway's
certificate chain:
```json claude_desktop_config.json theme={null}
{
"mcpServers": {
"ai-identity-gateway": {
"command": "npx",
"args": ["mcp-remote", "https://your-gateway.example.com/mcp"],
"env": {
"NODE_EXTRA_CA_CERTS": "/path/to/your-ca-bundle.pem"
}
}
}
}
```
**Resolution (development only):** For local development with self-signed
certificates, you can disable TLS verification entirely. Do **not** use
this in production.
```json claude_desktop_config.json theme={null}
{
"mcpServers": {
"ai-identity-gateway": {
"command": "npx",
"args": ["mcp-remote", "https://your-gateway.example.com/mcp"],
"env": {
"NODE_TLS_REJECT_UNAUTHORIZED": "0"
}
}
}
}
```
Setting `NODE_TLS_REJECT_UNAUTHORIZED=0` disables all TLS certificate
verification, making the connection vulnerable to man-in-the-middle
attacks. Use `NODE_EXTRA_CA_CERTS` with your organization's CA
certificate for non-development environments.
## Related Pages
Set up the Auth Provider Orchestrator and understand agent identity concepts
Make REST APIs available to Claude as MCP tools via MCP Bridge
Add identity governance to existing MCP servers via MCP Proxy
Full configuration reference for OAuth client registration
### Anthropic Documentation
Critical reference covering connector architecture, traffic routing, OAuth requirements, token limits, timeouts, and privacy details
Claude Code docs covering MCP transports, OAuth options, and callback port configuration
How to add remote MCP servers as connectors on claude.ai, including plan requirements
Developer guide for building OAuth-protected MCP servers that work with Claude
How to package local MCP servers as desktop extensions (.mcpb) for enterprise distribution
MCP protocol docs for configuring MCP servers in Claude Desktop
# Expose APIs to Agents
Source: https://docs.strata.io/guides/ai-identity/mcp-bridge
Make your existing REST APIs available to AI agents as discoverable MCP tools -- with full identity verification and authorization on every call.
## How It Works
MCP Bridge enables AI agents to access your existing REST APIs as MCP tools -- without modifying either the agents or the APIs. The Model Context Protocol (MCP) is an open standard that provides a structured way for AI agents to discover and invoke tools. MCP Bridge brings this capability to your existing REST APIs by translating between the two protocols automatically.
The Maverics Orchestrator sits between the AI agent and your REST APIs, acting as a translator. When an agent makes an MCP tool request, the Orchestrator converts it into the corresponding REST API call. When the REST API responds, the Orchestrator translates the response back into MCP format. This means your REST APIs become discoverable, invocable tools for AI agents -- without any changes to your existing API code.
But translation alone is not enough. Every tool invocation also passes through the Orchestrator's identity and authorization layer. Here is what happens when an agent requests a tool:
1. **Authenticates the agent** -- When the agent first connects, the AI Identity Gateway Orchestrator returns protected resource metadata (per RFC 9470) that tells the agent which authorization server(s) to authenticate against. The agent authenticates with the Auth Provider Orchestrator (or your external IdP) and obtains a token, then presents it to the gateway for validation.
2. **Resolves the user context** -- AI agents typically act on behalf of a human user. The Orchestrator identifies which user delegated authority to the agent, so authorization decisions reflect the user's actual permissions -- not just the agent's.
3. **Evaluates authorization policies** -- The Orchestrator checks whether the agent (acting on behalf of the user) is permitted to invoke the requested tool. Policies can restrict access based on the agent's scopes, the user's group memberships, the specific tool being invoked, or any combination of these factors.
4. **Translates and forwards** -- The Orchestrator exchanges the agent's token for a short-lived, narrowly scoped token specific to the tool being invoked, then converts the MCP tool call into the corresponding REST API request (mapping parameters, headers, and body content) and forwards it to your backend service with this fresh token.
5. **Returns the response** -- The REST API response is translated back into MCP format and returned to the agent, along with any identity context the agent needs for subsequent calls.
```mermaid theme={null}
flowchart LR
Agent["AI Agent"] --> Gateway["MCP Bridge (AI Identity Gateway Orchestrator)"]
Gateway --> AuthServer["Auth Provider (Orchestrator / OIDC Provider)"]
Gateway --> API1["REST API 1"]
Gateway --> API2["REST API 2"]
```
**MCP Bridge vs MCP Proxy:** MCP Bridge translates REST APIs into MCP tools --
choose it when you want to expose existing REST APIs to AI agents via MCP. MCP Proxy proxies existing MCP server connections with identity injection -- choose
it when you already have MCP servers running.
See the [AI overview](/guides/ai-identity/overview) for a side-by-side
comparison of both approaches.
## Prerequisites
* **A running Maverics Orchestrator** -- If you have not installed the Orchestrator yet, follow the [Quick Start guide](/guides/getting-started/quick-start) first. The Orchestrator is a small, lightweight runtime that deploys almost anywhere.
* **An identity provider configured as an identity connector** -- The Orchestrator needs an [Identity Fabric](/reference/orchestrator/identity-fabric) to authenticate agents. If you have not connected an identity provider yet, the Quick Start guide covers this step.
* **One or more REST APIs you want to expose as MCP tools** -- These are the backend APIs that AI agents will access. The APIs must use OAuth for authentication (MCP Bridge performs token exchange to call them on behalf of agents) and must be under your organization's control.
* **An OpenAPI spec for your REST API** -- MCP Bridge uses the OpenAPI specification to generate MCP tool definitions from your API endpoints.
* **An AI agent that supports the Model Context Protocol (MCP)** -- The agent connects to MCP Bridge as its MCP server, discovering and invoking tools through the standard MCP protocol.
## Configure MCP Bridge
The MCP Provider is the Orchestrator's entry point for AI agent connections. It handles MCP transport (how agents connect), agent authentication (verifying agent identity via OAuth), and tool routing (directing tool calls to the correct app).
Configure the MCP Provider with transport settings and OAuth-based agent authentication. The MCP Provider supports both SSE (Server-Sent Events) and Streamable HTTP transports.
**Console UI documentation is coming soon.** This section will walk you
through configuring this component using the Maverics Console's visual
interface, including step-by-step screenshots and field descriptions.
Define the MCP Provider and the OIDC connector that authenticates agents. The `mcpProvider.authorization.oauth` section configures how agent tokens are validated.
```yaml maverics.yaml theme={null}
connectors:
# Points to the Auth Provider Orchestrator (the separate OIDC Provider deployment)
- name: auth-provider
type: oidc
oidcWellKnownURL: https://your-auth-server.example.com/.well-known/openid-configuration
oauthClientID: ai-identity-gateway
oauthClientSecret:
oauthLoginRedirect:
urls:
- https://your-gateway.example.com/oidc-callback
oauthLogoutRedirect:
urls:
- https://your-gateway.example.com/logout
mcpProvider:
enabled: true
transports:
sse:
enabled: true
path: "/mcp/sse"
messagePath: "/mcp/message"
keepAlive:
enabled: true
interval: 30s
stream:
enabled: true
path: "/mcp"
session:
enabled: true
headerName: "Mcp-Session-Id"
allowClientTermination: true
timeout: 1h
authorization:
oauth:
enabled: true
metadataPath: /.well-known/oauth-protected-resource
servers:
- wellKnownEndpoint: https://your-auth-server.example.com/.well-known/oauth-authorization-server
refreshInterval: 24h
tokenValidation:
expectedAudiences:
- https://your-gateway.example.com/
method: jwt
jwt:
clockSkew: 15s
```
The MCP Provider enables both SSE and Streamable HTTP transports so agents can connect using whichever method they support. The `authorization.oauth` section configures JWT-based token validation -- the Orchestrator fetches the Auth Provider Orchestrator's signing keys from the well-known endpoint and validates agent tokens against them.
For the full set of AI Identity Gateway mode options, see the
[AI Identity Gateway reference](/reference/modes/ai-identity-gateway).
Register your REST API as an MCP Bridge app. The Orchestrator reads your API's OpenAPI specification and automatically generates MCP tool definitions for each endpoint. Agents discover these tools through the standard MCP protocol.
**Console UI documentation is coming soon.** This section will walk you
through configuring this component using the Maverics Console's visual
interface, including step-by-step screenshots and field descriptions.
Define an MCP Bridge app in the `apps` section. The `openapi.spec.uri` points to your API's OpenAPI specification, and `openapi.baseURL` points to the actual REST API server.
```yaml maverics.yaml theme={null}
apps:
- name: my-api-bridge
type: mcpBridge
mode: openapi
toolNamespace:
disabled: false
name: my_api_
openapi:
spec:
uri: https://your-api.example.com/openapi.yaml
baseURL: https://your-api.example.com/api/v1
```
The `toolNamespace.name` prefix is added to all tool names generated from this API. For example, if your API has a `listUsers` endpoint, agents will see it as `my_api_listUsers`. This prevents naming collisions when you have multiple MCP Bridge apps exposing tools from different APIs.
The `openapi.spec.uri` can be an HTTP URL or a local file path (`file:///path/to/spec.yaml`). The `openapi.baseURL` is the base URL where the Orchestrator sends the translated REST API requests.
Authorization is critical for MCP apps. Every MCP app requires both **inbound** authorization (OPA policy that decides whether a tool call is allowed) and **outbound** authorization (how the Orchestrator authenticates to the upstream REST API on behalf of the agent).
**Console UI documentation is coming soon.** This section will walk you
through configuring this component using the Maverics Console's visual
interface, including step-by-step screenshots and field descriptions.
The outbound authorization is where the Orchestrator's per-tool token exchange happens. Instead of forwarding the agent's original token to your REST API, the Orchestrator mints a fresh, short-lived token for each tool invocation. Each token carries only the scopes needed for that specific tool and expires in seconds.
Add the `authorization` block to your MCP Bridge app. The `inbound` section defines the OPA policy, and the `outbound` section configures token exchange for the upstream REST API.
```yaml maverics.yaml theme={null}
apps:
- name: my-api-bridge
type: mcpBridge
mode: openapi
toolNamespace:
disabled: false
name: my_api_
openapi:
spec:
uri: https://your-api.example.com/openapi.yaml
baseURL: https://your-api.example.com/api/v1
authorization:
inbound:
opa:
name: my-api-bridge-inbound-authz
rego: |
package orchestrator
default result["allowed"] := false
result["allowed"] := true {
input.request.mcp.tool.params.name == "listUsers"
}
result["allowed"] := true {
input.request.mcp.tool.params.name == "getUser"
}
outbound:
type: tokenExchange
tokenExchange:
type: delegation
idp: auth-provider
audience: https://your-api.example.com/
tools:
- name: listUsers
ttl: 5s
scopes:
- name: user:List
- name: getUser
ttl: 5s
scopes:
- name: user:Get
- name: createUser
ttl: 5s
scopes:
- name: user:Create
```
**Inbound authorization (OPA):** The Rego policy evaluates every tool invocation against the OPA input schema. The `input.request.mcp.tool.params.name` field contains the MCP tool name, and `input.request.mcp.tool.params.arguments` contains the tool arguments. You can also access `input.request.http.headers` (including the inbound access token), `input.request.http.method`, and `input.source.ip` for richer policy decisions. See the [Authorization Policies guide](/guides/security/policies#opa-authorization-ai-identity-gateway) for the full input schema and example policies.
**Outbound authorization (token exchange):** The Orchestrator exchanges the agent's token for a delegation token scoped to the target REST API. Each tool can have its own `scopes` (the permissions included in the delegated token) and `ttl` (how long the delegated token is valid). The `idp` references the connector used for the token exchange.
This means when an agent calls `listUsers`, the Orchestrator mints a token with only `user:List` scope that expires in 5 seconds. When the same agent calls `createUser` a moment later, a completely different token is minted with only `user:Create` scope. No single token ever carries more permissions than a single tool needs, and no token lives longer than it takes to complete the call.
For unprotected upstream APIs that do not require authentication, use `type: unprotected` instead of `type: tokenExchange`.
See [MCP Bridge Reference](/reference/orchestrator/applications/mcp-bridge) for all available fields.
Start with a deny-by-default policy and explicitly grant access to specific
tools. This is safer than starting with allow-all and trying to restrict
later -- it ensures agents only access what you intentionally permit.
Test the complete flow by connecting an AI agent to MCP Bridge and invoking a registered tool. This verifies that authentication, authorization, and REST API translation all work correctly end-to-end.
Connect your AI agent to the Orchestrator's MCP endpoint. The agent should be able to:
1. **Discover tools** -- The agent's MCP client lists available tools and sees the REST APIs you registered
2. **Authenticate** -- The agent presents its OAuth credentials and receives a valid session
3. **Invoke a tool** -- The agent calls a tool, and the Orchestrator translates it to the REST API call
4. **Receive a response** -- The REST API response is returned to the agent in MCP format
Check the Orchestrator logs to confirm that each step completed successfully. The logs show authentication events, policy evaluations, API translations, and any errors that occurred.
**Success!** Your REST APIs are now accessible as MCP tools through the
Orchestrator. AI agents authenticate with their credentials, authorization
policies control which tools each agent can access, and every tool
invocation is logged for audit and compliance.
## Troubleshooting
If the agent connects to MCP Bridge but sees no tools, check the following:
* Verify that REST APIs are correctly registered as MCP tools in the Bridge
configuration. Each API endpoint needs a valid URL, method, and tool name.
* Check that the agent has the required scopes to discover tools. Some
configurations restrict tool listing based on the agent's permissions.
* Look at the Orchestrator logs for errors during tool registration. If an
API endpoint is unreachable during startup, the tool may not be registered.
* Confirm that authorization policies do not block tool listing. A policy
that denies all access will also prevent tool discovery.
Agent authentication failures typically have one of these causes:
* The agent's OAuth client credentials (client ID and secret) are incorrect.
Double-check them against your identity provider's application registration.
* The identity provider is not reachable from the Orchestrator. Test
connectivity to your IdP's token endpoint.
* The agent's client registration has expired or been revoked in the identity
provider.
* The Orchestrator's identity connector is misconfigured. Check that the
connector's issuer URL and client configuration match your IdP.
Check the Orchestrator logs for specific authentication error details -- the
logs include the identity provider's error response, which usually identifies
the exact issue.
MCP Bridge translates MCP tool invocations to REST API calls and translates
the responses back. When the underlying REST API returns an error, the
Orchestrator passes it through as an MCP error response.
To isolate the issue:
* Call the REST API directly (bypassing MCP Bridge) to confirm it works on
its own. This tells you whether the issue is in the translation or the API.
* Check the Orchestrator logs for the full REST request and response. The
logs show how MCP Bridge mapped tool parameters to API parameters.
* Verify that parameter mappings are correct -- a common issue is mapping an
MCP tool parameter to the wrong REST query parameter or header.
* If the REST API requires authentication, ensure the outbound authorization
is configured with the correct token exchange settings and scopes.
## What's Next
Learn about agent identity concepts and set up the Auth Provider for token exchange
Detailed configuration reference for all MCP Bridge settings and options
# Protect MCP Servers
Source: https://docs.strata.io/guides/ai-identity/mcp-proxy
Add identity governance to your existing MCP servers -- authenticate every agent, authorize every tool call, and audit every action, without modifying your MCP servers.
## How It Works
MCP Proxy is for when you already have MCP servers running but they lack identity awareness. Maybe you built MCP servers that expose tools for your AI agents, but those servers do not know who is calling them or whether the caller is authorized. MCP Proxy solves this by adding an identity-aware layer between your agents and your existing MCP servers -- without modifying either side.
The Model Context Protocol (MCP) is an open standard for AI agent-to-tool communication. When you have MCP servers already deployed, they speak MCP natively -- agents connect, discover tools, and invoke them. The problem is that vanilla MCP does not include identity. Any agent that can reach your MCP server can invoke any tool. MCP Proxy fixes this gap.
The Maverics Orchestrator acts as a transparent proxy between agents and your MCP servers. Agents connect to the Orchestrator (thinking it is the MCP server), and the Orchestrator forwards their requests to your actual MCP servers after applying identity and authorization. Here is the flow:
1. **Agent connects** -- The AI agent connects to the Orchestrator's MCP endpoint, treating it as a standard MCP server.
2. **Authentication** -- The AI Identity Gateway Orchestrator returns protected resource metadata (per RFC 9470) that tells the agent which authorization server(s) to authenticate against. The agent authenticates with the Auth Provider Orchestrator and obtains a token, which the gateway validates before allowing the connection to proceed.
3. **Identity injection** -- For every tool invocation, the Orchestrator injects identity context into the request before forwarding it to the upstream MCP server. This context includes the agent's identity, the delegating user's identity, and any relevant claims or attributes.
4. **Authorization** -- The Orchestrator evaluates authorization policies to determine whether this agent, acting on behalf of this user, is allowed to invoke this specific tool.
5. **Transparent forwarding** -- The Orchestrator exchanges the agent's token for a short-lived, narrowly scoped token specific to the tool being invoked, then forwards the authorized request to the upstream MCP server with this fresh token and identity context attached. The MCP server receives the request as if the agent connected directly -- but now with identity information it can use.
6. **Response passthrough** -- The MCP server's response flows back through the Orchestrator to the agent, with audit logging capturing the complete interaction.
```mermaid theme={null}
flowchart LR
Agent["AI Agent"] --> Gateway["MCP Proxy (AI Identity Gateway Orchestrator)"]
Gateway --> AuthServer["Auth Provider (Orchestrator / OIDC Provider)"]
Gateway --> MCP1["MCP Server 1"]
Gateway --> MCP2["MCP Server 2"]
```
**MCP Proxy vs MCP Bridge:** MCP Proxy proxies existing MCP server connections
with identity injection -- choose it when you already have MCP servers running.
MCP Bridge translates REST APIs into MCP tools -- choose it when you have REST
APIs, not MCP servers.
See the [AI overview](/guides/ai-identity/overview) for a side-by-side
comparison of both approaches.
## Prerequisites
* **A running Maverics Orchestrator** -- If you have not installed the Orchestrator yet, follow the [Quick Start guide](/guides/getting-started/quick-start) first. The Orchestrator is a small, lightweight runtime that deploys almost anywhere.
* **An identity provider configured as an identity connector** -- The Orchestrator needs an [Identity Fabric](/reference/orchestrator/identity-fabric) to authenticate agents and resolve user context.
* **One or more existing MCP servers** -- These are the upstream MCP servers that your AI agents will access through the proxy. They must be reachable from the Orchestrator over the network.
* **An AI agent that supports the Model Context Protocol (MCP)** -- The agent connects to the Orchestrator's MCP endpoint (not directly to your MCP servers).
## Configure MCP Proxy
The MCP Provider is the Orchestrator's entry point for AI agent connections -- the same component used by MCP Bridge. It handles MCP transport, agent authentication via OAuth, and routes tool calls to the correct MCP Proxy app.
**Console UI documentation is coming soon.** This section will walk you
through configuring this component using the Maverics Console's visual
interface, including step-by-step screenshots and field descriptions.
Define the MCP Provider and the OIDC connector for agent authentication. This configuration is identical to the MCP Bridge setup -- the MCP Provider serves both Bridge and Proxy apps.
```yaml maverics.yaml theme={null}
connectors:
# Points to the Auth Provider Orchestrator (the separate OIDC Provider deployment)
- name: auth-provider
type: oidc
oidcWellKnownURL: https://your-auth-server.example.com/.well-known/openid-configuration
oauthClientID: ai-identity-gateway
oauthClientSecret:
oauthLoginRedirect:
urls:
- https://your-gateway.example.com/oidc-callback
oauthLogoutRedirect:
urls:
- https://your-gateway.example.com/logout
mcpProvider:
enabled: true
transports:
sse:
enabled: true
path: "/mcp/sse"
messagePath: "/mcp/message"
keepAlive:
enabled: true
interval: 30s
stream:
enabled: true
path: "/mcp"
session:
enabled: true
headerName: "Mcp-Session-Id"
allowClientTermination: true
timeout: 1h
authorization:
oauth:
enabled: true
metadataPath: /.well-known/oauth-protected-resource
servers:
- wellKnownEndpoint: https://your-auth-server.example.com/.well-known/oauth-authorization-server
refreshInterval: 24h
tokenValidation:
expectedAudiences:
- https://your-gateway.example.com/
method: jwt
jwt:
clockSkew: 15s
```
The MCP Provider configuration is shared across all MCP apps (both Bridge and Proxy). Agents authenticate once at the MCP Provider level (via the Auth Provider Orchestrator) and can then invoke tools from any registered MCP app.
Register your upstream MCP server as an MCP Proxy app. The Orchestrator proxies MCP protocol natively -- it receives MCP requests from agents and forwards them to your upstream MCP server over the Streamable HTTP transport.
**Console UI documentation is coming soon.** This section will walk you
through configuring this component using the Maverics Console's visual
interface, including step-by-step screenshots and field descriptions.
Define an MCP Proxy app in the `apps` section. The `upstream` configuration points to your existing MCP server, and `toolNamespace` prefixes tool names to avoid collisions.
```yaml maverics.yaml theme={null}
apps:
- name: my-mcp-server-proxy
type: mcpProxy
toolNamespace:
disabled: false
name: my_server_
upstream:
transport: stream
stream:
url: http://mcp-server.example.com:8080/mcp
connection:
dialTimeout: 10s
keepAlive:
interval: 15s
pool:
maxIdleConns: 100
maxIdleConnsPerHost: 100
```
The `upstream.stream.url` points to your MCP server's Streamable HTTP endpoint. The `toolNamespace.name` prefix is added to all tools from this upstream server -- for example, `my_server_listItems`. This prevents naming collisions when you proxy multiple MCP servers.
The `connection` settings control how the Orchestrator maintains its connection pool to the upstream MCP server, including dial timeouts and keep-alive intervals.
If your MCP servers are behind a firewall or VPN, make sure the Orchestrator
has network access to them. The Orchestrator needs to reach each upstream
server to discover its tools and forward requests.
Like MCP Bridge, every MCP Proxy app requires both **inbound** authorization (OPA policy) and **outbound** authorization (how the Orchestrator authenticates to the upstream MCP server on behalf of the agent). This is the same authorization pattern used across all MCP apps.
**Console UI documentation is coming soon.** This section will walk you
through configuring this component using the Maverics Console's visual
interface, including step-by-step screenshots and field descriptions.
The outbound authorization is where the Orchestrator's per-tool token exchange happens. Instead of forwarding the agent's original token to your MCP server, the Orchestrator mints a fresh, short-lived token for each tool invocation -- scoped to exactly the permissions that tool needs, with a TTL measured in seconds.
Add the `authorization` block to your MCP Proxy app. The `inbound` section defines the OPA policy, and the `outbound` section configures token exchange (or marks the upstream as unprotected).
```yaml maverics.yaml theme={null}
apps:
- name: my-mcp-server-proxy
type: mcpProxy
toolNamespace:
disabled: false
name: my_server_
upstream:
transport: stream
stream:
url: http://mcp-server.example.com:8080/mcp
connection:
dialTimeout: 10s
keepAlive:
interval: 15s
pool:
maxIdleConns: 100
maxIdleConnsPerHost: 100
authorization:
inbound:
opa:
name: my-mcp-server-inbound-authz
rego: |
package orchestrator
default result["allowed"] := false
result["allowed"] := true {
input.request.mcp.tool.params.name == "listItems"
}
result["allowed"] := true {
input.request.mcp.tool.params.name == "getItem"
}
outbound:
type: tokenExchange
tokenExchange:
type: delegation
idp: auth-provider
audience: https://mcp-server.example.com/
tools:
- name: listItems
ttl: 5s
scopes:
- name: item:List
- name: getItem
ttl: 5s
scopes:
- name: item:Get
- name: createItem
ttl: 5s
scopes:
- name: item:Create
- name: updateItem
ttl: 5s
scopes:
- name: item:Update
```
**Inbound authorization (OPA):** The Rego policy controls which tool calls are allowed. The OPA input schema provides `input.request.mcp.tool.params.name` (the tool name), `input.request.mcp.tool.params.arguments` (the tool arguments), `input.request.http.headers` (including the inbound access token), and `input.source.ip` (the client IP). See the [Authorization Policies guide](/guides/security/policies#opa-authorization-ai-identity-gateway) for the full input schema and example policies.
**Outbound authorization (token exchange):** Each tool gets its own scopes and TTL for the delegated token. The `type: delegation` means the exchanged token preserves both the agent's and the delegating user's identity.
This means when an agent calls `listItems`, the Orchestrator mints a token with only `item:List` scope that expires in 5 seconds. When the same agent calls `createItem` next, a completely different token is minted with only `item:Create` scope. Every tool invocation gets a fresh, minimal-privilege token -- nothing is reused or over-scoped.
If your upstream MCP server does not require authentication, use `type: unprotected`:
```yaml theme={null}
authorization:
inbound:
opa:
name: my-mcp-server-inbound-authz
file: /etc/maverics/policies/my-mcp-server-inbound-authz.rego
outbound:
type: unprotected
```
See [MCP Proxy Reference](/reference/orchestrator/applications/mcp-proxy) for all available fields.
If your upstream MCP servers are also accessible directly (not just through
the proxy), agents could bypass the identity layer by connecting to the MCP
server directly. Restrict network access so that MCP servers only accept
connections from the Orchestrator.
Test the complete flow by connecting an AI agent to MCP Proxy and verifying that identity context is correctly injected into upstream requests.
Connect your agent to the Orchestrator's MCP endpoint and invoke a tool. Then check:
1. **Agent authentication** -- The Orchestrator logs show the agent was authenticated successfully
2. **Tool discovery** -- The agent sees tools from all registered upstream MCP servers
3. **Identity injection** -- The upstream MCP server received the request with identity context attached (check the MCP server's logs or add a debug tool that echoes received metadata)
4. **Authorization enforcement** -- Try invoking a tool the agent should not have access to and confirm the request is denied
**Success!** Your existing MCP servers are now protected by the Orchestrator's
identity layer. Agents authenticate before accessing tools, identity context
is injected into every request, and authorization policies control which
tools each agent can use.
## Troubleshooting
If the Orchestrator cannot reach your upstream MCP servers, agents will see
connection timeout errors. Check the following:
* Verify that the upstream MCP server is running and listening on the
configured endpoint.
* Test network connectivity from the Orchestrator to the MCP server. If the
server is behind a firewall, ensure the Orchestrator's IP is allowed.
* Check the transport protocol configuration -- ensure the MCP server and
the Orchestrator are using compatible transport protocols.
* Look at the Orchestrator logs for specific timeout or connection error
details.
If your MCP server is receiving requests but without identity context, the
outbound authorization configuration may be incorrect:
* Verify the outbound type is set to `tokenExchange` (not `unprotected`) if
you need identity context forwarded.
* Check that the token exchange `idp` references a valid connector and that
the `audience` matches what the upstream server expects.
* If using per-tool scopes, verify the tool names in the `tools` array match
the actual tool names from the upstream MCP server.
* Enable debug logging in the Orchestrator to see the full token exchange
flow and identify where identity context is lost.
Authentication failures for MCP Proxy follow the same patterns as MCP Bridge:
* Verify the agent's OAuth credentials (client ID and secret) are correct.
* Confirm the identity provider is reachable from the Orchestrator.
* Check that the agent's client registration has not expired or been revoked.
* Review the Orchestrator logs for the identity provider's error response.
See the [AI Identity overview](/guides/ai-identity/overview) for more
detail on agent credential management and common authentication issues.
## What's Next
Learn about agent identity concepts and set up the Auth Provider for token exchange
Detailed configuration reference for all MCP Proxy settings and options
# Overview
Source: https://docs.strata.io/guides/ai-identity/overview
Secure AI agent access to your APIs and MCP tools with identity, authentication, and authorization on every call. The Maverics Orchestrator lets you control which agents can access which tools, trace every action back to the human user who authorized it, and audit everything -- so AI agents operate with the same identity governance as your human users.
The Orchestrator provides two approaches for securing AI agent access through the **Model Context Protocol (MCP)**, an open standard that lets AI agents discover and invoke tools in a structured, protocol-driven way. Each approach adds identity, authentication, and authorization to MCP connections in a different way, depending on your architecture and what you already have in place.
Whether you have existing REST APIs you want to open up to AI agents or existing MCP servers that need identity awareness -- there is an approach that fits your situation.
## Choose Your Approach
| Approach | When to Use | How It Works |
| ------------------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Expose APIs to Agents** | You have existing REST APIs you want AI agents to access | Translates REST APIs into MCP tools automatically -- agents discover and invoke tools via MCP while the Orchestrator handles the REST translation behind the scenes |
| **Protect MCP Servers** | You have existing MCP servers that need identity | Proxies MCP connections with identity injection -- the Orchestrator sits between agents and your MCP servers, adding authentication and authorization to every tool invocation |
Not sure which approach to start with? If you have REST APIs today and want to
expose them to AI agents, start with **MCP Bridge**. If you already have MCP
servers running, start with **MCP Proxy**.
## Agent Identity Concepts
AI agents are not humans -- but they still need identity. When an AI agent accesses a tool, reads data, or performs an action on behalf of a user, something needs to answer these questions: Who is this agent? Who authorized it to act? What is it allowed to do? And what did it actually do?
Agent identity addresses this by adding three capabilities that traditional service accounts lack:
* **Delegation chains** -- Every agent action traces back to the human user who authorized it. When Agent X accesses a tool, the system knows that Alice delegated authority to Agent X and that Alice's permissions (not just the agent's) determine what the agent can do. This is implemented through OAuth 2.0 token exchange, which supports two modes. **Delegation** (default) produces a token with an `act` claim that identifies both the user and the agent acting on their behalf, giving downstream services full visibility for auditability. **Impersonation** produces a token that fully assumes the user's identity, with no trace of agent involvement -- use this when downstream services do not support the actor claim pattern. See the [MCP Bridge](/reference/orchestrator/applications/mcp-bridge#token-exchange) and [MCP Proxy](/reference/orchestrator/applications/mcp-proxy#token-exchange) references for configuration details.
* **Dynamic scopes** -- Agent permissions can change based on context. An agent might have broad scopes for one task and narrow scopes for another, depending on what the delegating user authorized. Scopes are named permissions (like `read:orders`, `write:invoices`, or `admin:users`) that your identity provider issues in the agent's token.
* **Action-level audit** -- Every tool invocation is logged with the full identity context: which agent, which user, which tool, what parameters, and what result. This gives you a complete audit trail that satisfies compliance requirements and enables forensic analysis when something goes wrong.
The Maverics Orchestrator works with your existing identity provider to manage agent identity. You register agents in your identity provider (just like you register applications), configure their scopes and permissions, and the Orchestrator enforces those permissions at runtime -- whether you are using [MCP Bridge](/guides/ai-identity/mcp-bridge) or [MCP Proxy](/guides/ai-identity/mcp-proxy) mode.
## How Token Security Works
The AI Identity Gateway involves two orchestrator deployments working together:
* **Auth Provider Orchestrator** -- A separate orchestrator deployment running as an OIDC Provider (authorization server). It handles agent authentication, token issuance, and token exchange (minting short-lived, scoped delegation tokens for each tool invocation).
* **AI Identity Gateway Orchestrator** -- Runs the MCP Provider with MCP Bridge and/or MCP Proxy apps. It handles MCP transport, tool routing, inbound authorization (OPA policies), and upstream forwarding.
These can be the same orchestrator instance for simpler deployments, but are typically separate deployments in production.
Every tool invocation gets its own token. When an agent calls a tool, the AI Identity Gateway Orchestrator does not reuse the agent's existing token or forward it to the upstream service. Instead, it requests a token exchange from the Auth Provider Orchestrator -- trading the agent's token for a brand-new token specific to that single tool call. Each token carries only the scopes that tool needs (like `employee:List` for listing employees) and expires in seconds (typically a `ttl` of `5s`). A different tool call a moment later gets a completely different token with different scopes.
```mermaid theme={null}
sequenceDiagram
participant Agent as AI Agent
participant Gateway as AI Identity Gateway (Orchestrator)
participant AuthServer as Auth Provider (Orchestrator / OIDC Provider)
participant API as Tool / API
Agent->>Gateway: Connect to MCP endpoint
Gateway-->>Agent: 401 + /.well-known/oauth-protected-resource
Agent->>Gateway: GET /.well-known/oauth-protected-resource
Gateway-->>Agent: Protected resource metadata (lists authorization servers)
Agent->>AuthServer: OAuth authorization flow
AuthServer-->>Agent: Access token
Agent->>Gateway: Invoke tool (with access token)
Gateway->>Gateway: Validate token + evaluate OPA policies
Gateway->>AuthServer: Token exchange: mint scoped token ttl: 5s, scopes: [employee:List]
AuthServer-->>Gateway: Short-lived delegation token
Gateway->>API: Forward request with delegation token
API-->>Gateway: Response
Gateway-->>Agent: Tool result
```
## MCP Spec OAuth Discovery (RFC 9470)
When an agent first connects to the AI Identity Gateway, it goes through a standards-based OAuth discovery flow:
1. The agent connects to the AI Identity Gateway Orchestrator's MCP endpoint.
2. The gateway returns a `401` along with a pointer to its protected resource metadata endpoint.
3. The gateway exposes `/.well-known/oauth-protected-resource` (per RFC 9470), which returns protected resource metadata including the list of authorization server(s) the agent can authenticate against.
4. The agent reads the metadata, authenticates against the Auth Provider Orchestrator (one of the listed authorization servers), and obtains a token.
5. The agent returns to the gateway with a valid token. The gateway validates the token and proceeds with tool discovery and invocation.
This flow means agents do not need to be pre-configured with authorization server URLs -- they discover them dynamically from the gateway's protected resource metadata.
Traditional approaches give agents broad, long-lived tokens that accumulate permissions. The Orchestrator takes the opposite approach: every tool invocation gets a fresh, minimal-privilege token that expires in seconds. No single token ever carries more permissions than a single tool needs, and no token lives longer than it takes to complete the call.
## Set Up the Auth Provider
The OIDC Provider you configure here is the Orchestrator's own token minting infrastructure. It does not just validate tokens from an external provider -- it issues short-lived, narrowly scoped tokens for each tool invocation. You configure it with token exchange grant types so it can mint delegation tokens that carry both the agent's identity and the delegating user's identity.
**Console UI documentation is coming soon.** This section will walk you
through configuring this component using the Maverics Console's visual
interface, including step-by-step screenshots and field descriptions.
This configuration is for the **Auth Provider Orchestrator** deployment -- the separate orchestrator instance that runs the OIDC Provider. It is not the same deployment as the AI Identity Gateway Orchestrator that runs the MCP Provider.
Configure the `oidcProvider` and register the AI Identity Gateway as an OIDC application with token exchange grants and custom scopes for MCP tools.
```yaml maverics.yaml theme={null}
connectors:
- name: upstream-idp
type: oidc
oidcWellKnownURL: https://your-idp.example.com/.well-known/openid-configuration
oauthClientID: orchestrator-client
oauthClientSecret:
oauthLoginRedirect:
urls:
- https://your-auth-server.example.com/oidc-callback
oauthLogoutRedirect:
urls:
- https://your-auth-server.example.com/logout
disablePKCE: false
scopes: openid profile email
oidcProvider:
correlateSession: true
discovery:
issuer: https://your-auth-server.example.com
endpoints:
wellKnown: https://your-auth-server.example.com/.well-known/oauth-authorization-server
jwks: https://your-auth-server.example.com/oauth2/jwks
auth: https://your-auth-server.example.com/oauth2/auth
token: https://your-auth-server.example.com/oauth2/token
userinfo: https://your-auth-server.example.com/oauth2/userinfo
introspect: https://your-auth-server.example.com/oauth2/introspect
jwks:
- algorithm: RSA256
publicKey:
privateKey:
```
The OIDC Provider issues tokens that the AI Identity Gateway validates when agents connect. The `jwks` section defines the signing keys used to sign tokens -- the gateway fetches the public key from the `jwks` endpoint to verify token signatures.
Treat agent credentials with the same care as user passwords. Store the
client secret in a [secret provider](/reference/orchestrator/configuration/secret-providers)
\-- never in source code, configuration files, or environment variables that
might be logged or exposed.
Register the AI Identity Gateway as an OIDC application that can perform token exchange. This client uses the `urn:ietf:params:oauth:grant-type:token-exchange` grant type to exchange a user's token for a delegation token scoped to specific downstream APIs.
**Console UI documentation is coming soon.** This section will walk you
through configuring this component using the Maverics Console's visual
interface, including step-by-step screenshots and field descriptions.
Define the gateway client in the `apps` section with `grantTypes` that include both `client_credentials` and `token-exchange`. Configure `customScopes` for the MCP tools the gateway will broker access to.
```yaml maverics.yaml theme={null}
apps:
- name: ai-identity-gateway
type: oidc
clientID: ai-identity-gateway
credentials:
secrets:
-
grantTypes:
- client_credentials
- urn:ietf:params:oauth:grant-type:token-exchange
accessToken:
type: jwt
allowedAudiences:
- https://your-api.example.com/
- https://mcp-server.example.com/
customScopes:
scopes:
- name: user:List
- name: user:Get
- name: user:Create
- name: user:Update
- name: item:List
- name: item:Get
- name: item:Create
claimsMapping:
email: upstream-idp.email
name: upstream-idp.name
sub: upstream-idp.sub
```
The `grantTypes` array enables both `client_credentials` (for machine-to-machine auth) and `urn:ietf:params:oauth:grant-type:token-exchange` (RFC 8693 token exchange for delegation). The `allowedAudiences` list restricts which downstream services the gateway can request tokens for. The `customScopes` define the per-tool permissions that can be included in exchanged tokens.
Administrators can also configure token minting policies on the OIDC Provider app (`authorization.tokenMinting.accessToken.policies`) to apply OPA-based governance over which tokens get issued during exchange. This provides a second control point beyond inbound OPA policies -- inbound policies control which tool calls are allowed, while token minting policies control which tokens are issued. See the [OIDC Provider reference](/reference/modes/oidc-provider) for configuration details.
### Per-Tool Token Exchange
Each tool in the `tools` array gets its own `ttl` and `scopes`, and each tool invocation triggers a separate token exchange operation. This is not a single token with all scopes -- every tool call gets its own freshly minted token.
For example, when an agent calls `listEmployees`, the Orchestrator mints a token with only `employee:List` scope, valid for 5 seconds. When the same agent calls `createEmployee` a moment later, the Orchestrator performs a completely separate token exchange, minting a different token with only `employee:Create` scope, also valid for 5 seconds. The first token has already expired by the time the second call completes.
This means no token ever accumulates permissions across tools, and no token outlives its purpose. The `ttl` and `scopes` fields in the YAML above are not just configuration -- they define the security boundary for each individual tool invocation.
Document your scope naming convention and share it with your team. Consistent
scope names (like always using the `action:resource` pattern) make policies
easier to write, review, and audit.
## Guides
Make your existing REST APIs available to AI agents as discoverable MCP tools with full identity and authorization
Add identity governance to your existing MCP servers -- authenticate every agent and authorize every tool call
## Troubleshooting
If an agent cannot authenticate with its client credentials, check the
following:
* Verify the client ID and client secret are correct. Client secrets are
often only shown once when created -- if you have lost the secret, generate
a new one in your identity provider.
* Check that the agent's application registration is active and has not
been disabled or deleted in the identity provider.
* Confirm the grant type is set to "client\_credentials" in the agent's
application registration.
* Verify that the token endpoint URL in the Orchestrator's identity
connector matches your identity provider's actual token endpoint.
* If the agent's credentials have an expiration date, check whether they
have expired.
If the Orchestrator cannot resolve the delegation chain (the agent
authenticates but the user context is missing):
* Verify that the delegated token includes the `act` (actor) claim or
whatever custom claim your identity provider uses for delegation.
* Check that the token exchange was performed correctly -- the original
user token must be exchanged for a delegated agent token, not simply
passed through.
* Verify that the gateway client's `grantTypes` includes
`urn:ietf:params:oauth:grant-type:token-exchange`.
* If your identity provider does not support the standard OAuth 2.0 token
exchange, check the Orchestrator's identity connector documentation for
provider-specific delegation configuration.
* Enable debug logging in the Orchestrator to see the full token contents
and identify which claims are present or missing.
If the token exchange succeeds but the downstream service rejects the
exchanged token:
* Verify the `allowedAudiences` in the gateway client includes the audience
value used in the MCP app's `outbound.tokenExchange.audience`.
* Check that the downstream service's expected audience matches the
`audience` value in the token exchange configuration.
* Review the exchanged token's claims (using a JWT debugger) to confirm
the `aud` claim contains the expected value.
## Related Pages
Detailed configuration reference for all AI Identity Gateway modes and settings
TLS, secrets management, authorization policies, and compliance guides
SSO, OIDC, SAML federation, and identity provider migration guides
# OWASP MCP Top 10
Source: https://docs.strata.io/guides/ai-identity/owasp-mcp-top-10
The [OWASP MCP Top 10](https://owasp.org/www-project-mcp-top-10/) identifies the most critical security risks in Model Context Protocol deployments. As AI agents interact with enterprise systems through MCP, new attack surfaces emerge -- from token mismanagement and privilege escalation to shadow servers and context injection.
The Maverics Orchestrator in [AI Identity Gateway](/reference/modes/ai-identity-gateway) mode addresses several of these risks directly. Using a second Orchestrator as an [Auth Provider](/guides/ai-identity/overview#set-up-the-auth-provider) (OIDC Provider) with per-tool token exchange, it provides identity, authorization, and audit controls for every MCP interaction. This page maps each OWASP MCP risk to the specific capabilities that mitigate it -- and is transparent about where complementary controls are needed.
**Disclaimer:** This page is provided for informational purposes only and does
not constitute a guarantee of security, compliance, or complete risk mitigation.
The mappings described here reflect general architectural capabilities and may
not apply to every deployment topology or configuration. Security outcomes depend
on proper configuration, organizational governance, and complementary controls.
Customers are responsible for evaluating their own security posture, conducting
independent assessments, and implementing appropriate controls for their specific
environment. Strata Identity makes no warranties regarding the completeness or
accuracy of these mappings.
The AI Identity Gateway operates at the **identity and authorization layer** --
authentication, token management, policy enforcement, telemetry, and auditing. Some OWASP MCP
risks target the **AI model layer** (prompt injection, intent manipulation, context
memory). For those risks, the gateway limits the blast radius and enables detection,
but prevention requires complementary controls at the model and application layers.
## Coverage Summary
| OWASP Risk | Coverage | How the AI Identity Gateway Addresses It |
| ------------------------------------------------------- | ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [**MCP01**](#mcp01) -- Token Mismanagement | Directly addresses | Upstream services never see long-lived or over-scoped tokens. Per-tool token exchange mints short-lived, scoped tokens with customizable TTLs (e.g., 5s). The agent's original token is never forwarded to upstream services. |
| [**MCP02**](#mcp02) -- Privilege Escalation | Reduces attack surface | Per-tool scopes and short-lived tokens prevent runtime scope accumulation. OPA policies and token minting policies enforce configured boundaries. Configuration-level scope creep (admins gradually broadening permissions) requires organizational governance. |
| [**MCP03**](#mcp03) -- Tool Poisoning | Reduces attack surface | The gateway only serves tools from OpenAPI specs and MCP servers that your organization explicitly registers -- no public registries or auto-discovery. OPA policies can validate tool arguments before they reach upstream services. Tool namespacing mitigates shadowing. |
| [**MCP04**](#mcp04) -- Supply Chain Attacks | Reduces attack surface | The Orchestrator is a single binary with no plugin marketplace or dependency resolution. Upstream servers and APIs are explicitly registered in configuration. Complementary controls needed for SBOM and dependency scanning of your own services. |
| [**MCP05**](#mcp05) -- Command Injection | Directly addresses (gateway layer) | The gateway forwards structured protocol messages (MCP or REST) to upstream services, never executes commands or code. OPA policies can inspect and reject malicious tool argument values before they reach upstream services. |
| [**MCP06**](#mcp06) -- Intent Flow Subversion | Limits blast radius | Even if an agent is subverted, OPA policies constrain which tools it can invoke and what arguments it can pass. Delegation tokens enforce both the agent's and the delegating user's permissions on upstream services. Auditing enables detection. Prevention requires AI model-layer controls. |
| [**MCP07**](#mcp07) -- Insufficient Auth | Directly addresses | Upstream services are protected by multi-layer auth: OAuth 2.0 agent authentication, OPA policies on every tool call, per-tool token exchange with scoped delegation tokens, and token minting policies. This is the core problem the gateway was built to solve. |
| [**MCP08**](#mcp08) -- Lack of Audit | Directly addresses | Every tool call to an upstream service is logged with agent identity, user identity, tool name, parameters, and outcome. Structured JSON for SIEM. Downstream analysis and tamper protection depend on SIEM configuration. |
| [**MCP09**](#mcp09) -- Shadow MCP Servers | Directly addresses (gateway layer) | Agents access upstream services only through the centralized gateway. Upstream servers are explicitly registered. Network isolation prevents agents from bypassing the gateway. Discovering rogue servers in the org requires separate tooling. |
| [**MCP10**](#mcp10) -- Context Injection & Over-Sharing | Reduces attack surface | Upstream services are protected from cross-context access -- each tool invocation gets its own scoped token, and sessions are isolated per agent. Model-layer context memory isolation requires complementary controls. |
## Risk Details
**OWASP risk:** Tokens and credentials serve as the primary means of authentication and authorization in MCP systems. Developers frequently embed secrets improperly, creating "contextual secret leakage" where protocols themselves become unintentional credential repositories. Long-lived sessions and context persistence compound the problem. Attackers retrieve tokens through prompt injection, log scraping, or context poisoning -- leading to complete infrastructure compromise, lateral movement across integrated services, and data exfiltration.
**Coverage: Directly addresses**
The Orchestrator's [per-tool token exchange](/guides/ai-identity/overview#how-token-security-works) protects upstream services by ensuring they never receive long-lived or over-scoped tokens:
* **Per-tool token exchange** -- Every tool invocation triggers a fresh token exchange. The gateway mints a new delegation token with only the scopes that tool needs and a customizable TTL (e.g., `5s`). A different tool call a moment later gets a completely different token with different scopes.
* **No token forwarding** -- The gateway never passes the agent's original token to upstream services. Every upstream call uses a freshly minted, minimally scoped delegation token. The agent's primary token never reaches the backend.
* **Inbound delegation support** -- Agents can optionally perform a token exchange before connecting to the gateway, producing a token with the user as the subject and the agent as the actor (`act` claim). Regardless of whether this inbound exchange happens, the gateway always performs its own outbound token exchange for each tool call.
The protection profile varies depending on your deployment topology. When the upstream service is another AI agent, short TTLs and scoped tokens are especially critical -- a compromised downstream agent with a long-lived, broadly scoped token could leverage that access far more aggressively than a traditional API consumer would. When the upstream is a REST API, the same token constraints protect against token reuse and lateral movement, but the attack vectors differ. The gateway's per-tool token exchange addresses both scenarios by ensuring that no upstream service -- agent or API -- ever receives more access than a single tool invocation requires.
**OWASP risk:** Scope creep occurs when narrowly scoped permissions granted to an MCP agent expand over time -- intentionally for convenience or accidentally through configuration drift -- until the agent holds broad or administrative privileges. This enables unauthorized code modifications, unreviewed deployments, full environment control through service account impersonation, and regulatory violations. The risk is amplified by autonomous agent execution paths that compound incremental permission increases.
**Coverage: Reduces attack surface**
The Orchestrator prevents runtime scope accumulation, but configuration-level scope creep -- where admins gradually broaden permissions over time -- is an organizational governance problem the gateway cannot solve on its own. What the gateway does is make scope boundaries explicit, auditable, and enforceable at runtime:
1. **Per-tool scopes** -- Each tool has an explicit, declarative scopes list. Scopes are defined in configuration, not accumulated at runtime. A `listUsers` tool gets `user:List`; a `createUser` tool gets `user:Create`. Adding a new scope requires a deliberate configuration change, which flows through your change management process.
2. **Automatic token expiry** -- Every minted token has a TTL measured in seconds. Permissions cannot accumulate over time because each token is destroyed before the next one is issued. There is no long-lived session where scopes could grow.
3. **OPA inbound policies** -- Rego policies evaluate every tool invocation with a [deny-by-default stance](/guides/ai-identity/mcp-bridge#configure-authorization) before the request reaches any upstream service. Policy authors have access to tool name, argument names and values, HTTP headers (including the inbound access token, which can be parsed for identity claims), and source IP. The identity claims available in the token depend on the inbound flow -- an agent that performed token exchange presents a token with the user as subject and agent as actor, while an autonomous agent presents its own identity token. Policy authors can write arbitrarily granular validation logic against any of this context. For example, a policy can allow `createUser` only when the `role` argument is not `admin`, or restrict `deleteItem` to specific token subjects. For elevated operations, OPA policies will soon support human-in-the-loop approval, requiring explicit human authorization before the action proceeds. An agent cannot invoke a tool that the policy does not explicitly permit.
4. **Token minting policies** -- The Auth Provider Orchestrator can apply [OPA-based governance](/guides/ai-identity/overview#set-up-the-auth-provider) over which tokens are issued during exchange. This is a second, independent control point -- even if an inbound policy allows a tool call, the Auth Provider can refuse to mint the token if the requested scopes violate minting policy.
**OWASP attack scenarios and how the gateway responds:**
* **Accidental escalation** (temporary `repo:write` expands to permanent broad access): Scopes are defined declaratively and require a deliberate configuration change to modify, not an ad-hoc runtime grant.
* **Credential harvesting + escalation** (long-lived token found in logs, used to grant additional scopes): Delegation tokens minted for upstream calls expire in seconds and cannot be used to request additional scopes. The agent's own access token should also be configured with an appropriately short TTL on the Auth Provider. The token exchange flow is one-directional -- delegation tokens are minted by the Auth Provider for specific tools, not requested or influenced by the agent.
* **Automated policy bypass** (attacker updates agent manifest to add admin privileges): The Auth Provider defines the universe of allowed scopes. A tool cannot request a scope that is not registered in the Auth Provider.
**Complementary controls needed:** The gateway enforces whatever scopes
and policies are configured, but does not prevent those configurations
from becoming overly permissive over time. OWASP recommends automated
scope expiry, periodic entitlement reviews, and separation of duties
for configuration changes. These are organizational governance practices
that complement the gateway's runtime enforcement.
See the [MCP Bridge authorization](/guides/ai-identity/mcp-bridge#configure-authorization)
and [MCP Proxy authorization](/guides/ai-identity/mcp-proxy#configure-authorization)
guides for full configuration details.
**OWASP risk:** Tool poisoning occurs when an adversary compromises the tools, plugins, or their schemas that an AI model depends on. Techniques include rug pulls (malicious updates to trusted tools), schema poisoning (corrupting interface definitions so legitimate agents execute unintended destructive operations), and tool shadowing (introducing fake or duplicate tools). Impact includes data compromise, privilege escalation, policy circumvention, and audit trail corruption -- because logs show valid actions per contract despite the contract being malicious.
**Coverage: Reduces attack surface**
The Orchestrator prevents tool poisoning through architectural controls that keep tool definitions under organizational control:
* **Explicitly registered upstream services** -- Both app types require explicit registration of upstream services. [MCP Bridge](/guides/ai-identity/mcp-bridge#define-the-mcp-bridge-app) dynamically generates tools from OpenAPI specifications you provide. [MCP Proxy](/guides/ai-identity/mcp-proxy#define-the-mcp-proxy-app) proxies tool calls to upstream MCP servers registered by URL. In both cases, tools come from sources your organization controls -- there is no auto-discovery from public registries, third-party marketplaces, or community repositories. Rogue tools cannot enter the catalog because the system only serves tools from explicitly registered upstreams.
* **Tool namespacing** -- Tool names are prefixed with a configurable namespace (e.g., `my_api_listUsers`). This mitigates tool shadowing by making the source of each tool identifiable -- if two tools share a name, the namespace disambiguates them. Agents see which registered upstream each tool comes from.
* **OPA argument-level validation** -- Inbound OPA policies inspect tool arguments before any request reaches an upstream service. Policy authors can validate argument names, check argument values against expected patterns, reject unexpected parameters, and enforce business rules -- catching anomalous behavior that might indicate a poisoned tool definition before it affects upstream resources.
**Complementary controls needed:** The Orchestrator does not implement
cryptographic schema signing (JWS/COSE/PKI), content-addressable hash
verification of tool definitions, or provenance metadata tracking (author,
timestamp, approver) on schemas -- all recommended by OWASP for this risk.
If your threat model includes sophisticated supply chain attackers who could
compromise your internal OpenAPI specs or MCP server configurations, implement
schema signing and integrity verification in your CI/CD pipeline as a
complementary control.
**OWASP risk:** MCP ecosystems depend on open-source packages, connectors, and model-side plug-ins that may contain malicious or vulnerable components. Attackers target MCP server libraries, third-party plugins, dependency updates, and build pipelines. Compromised dependencies can call unsafe APIs, exfiltrate context data, insert rogue schemas, tamper with tool execution, or silently escalate privileges. These components often appear legitimate and can operate undetected for extended periods.
**Coverage: Reduces attack surface**
The Orchestrator's deployment model eliminates several attack vectors that make MCP supply chain attacks possible:
* **No runtime plugin ecosystem** -- Unlike MCP frameworks that rely on user-installed plugins, connectors, or community extensions, the Orchestrator does not have a runtime extension mechanism where customers pull packages from public registries. This eliminates the dependency confusion, typosquatting, and registry compromise vectors that OWASP highlights for the gateway layer specifically.
* **Explicit upstream registration** -- All upstream services are explicitly registered. MCP Proxy connects to upstream MCP servers you configure. MCP Bridge reads OpenAPI specifications from URIs you provide. In neither case does the system auto-discover or auto-install tools from public repositories.
* **Deliberate configuration changes** -- Tool definitions, authorization policies, and server registrations are defined declaratively. Changes are auditable through your existing change management process.
**Complementary controls needed:** The gateway adds one component to
the deployment (the Orchestrator binary itself), but does not reduce
supply chain risk for upstream MCP servers, REST APIs, or the AI agents
connecting to it. Each of those systems has its own dependencies,
build pipelines, and attack surface. It is the customer's responsibility
to ensure that upstream services, agents, and the Orchestrator deployment
all follow standard supply chain security practices -- SBOM management,
dependency scanning, version pinning, signed builds, and vendor security
assessments.
**OWASP risk:** AI agents construct and execute system commands, shell scripts, API calls, or code snippets using untrusted input without proper validation or sanitization. The attack surface is unique because the agent interprets natural language instructions and translates them into executable operations. Techniques include prompt-driven execution, dynamic command construction through string concatenation, tool-mediated execution via MCP tools wrapping system calls, and chained execution using shell operators.
**Coverage: Directly addresses (gateway layer)**
The gateway protects upstream services from command injection by validating and constraining every tool invocation before it is forwarded:
* **Protocol-level gateway, not a command executor** -- The Orchestrator forwards structured protocol messages to upstream services in both app types. MCP Proxy forwards MCP protocol messages to upstream MCP servers. MCP Bridge translates MCP tool calls into structured REST API requests (HTTP method, URL, headers, body) mapped through the OpenAPI spec. In neither case does the Orchestrator execute shell commands, scripts, or arbitrary code. There is no string concatenation or template injection in the forwarding path.
* **OPA argument-level validation** -- Inbound OPA policies inspect every tool invocation before it reaches an upstream service. Policy authors have access to tool argument names and values, the tool name, HTTP headers, and source IP. Policies can reject arguments containing shell metacharacters, SQL injection patterns, path traversal sequences, or any other suspicious content. Because Rego is a full policy language, policy authors can write validation logic as granular as their upstream services require -- allowlisting specific argument values, enforcing type constraints, or matching against regex patterns.
* **Per-tool token scoping** -- Even if a malicious argument passes OPA validation and reaches an upstream service, the delegation token limits the blast radius to the scopes configured for that specific tool. The upstream service cannot be used to access resources beyond the tool's configured scope.
**Upstream service security is outside gateway scope.** The Orchestrator
validates and constrains at the gateway layer, but cannot prevent an
upstream MCP server or REST API from being vulnerable to injection in its
own implementation. If your upstream tools wrap shell commands, SQL queries,
or code execution, those tools must implement their own input sanitization,
parameterized execution, and sandboxing as recommended by OWASP.
**OWASP risk:** Intent flow subversion occurs when malicious instructions embedded within retrieved context cause an MCP-enabled agent to deviate from the user's original goal. Unlike direct prompt injection, this happens "in-flow" -- the agent retrieves resources containing hidden directives that override intended objectives. Impact includes goal hijacking (the agent pursues an entirely different objective), unauthorized autonomous actions (deleting repositories, modifying cloud configurations), and stealthy persistence (meta-instructions in long-lived contexts alter behavior across multiple sessions).
**Coverage: Limits blast radius**
Intent flow subversion is fundamentally an **AI model-layer problem** -- the attack targets how the model interprets context, not how identity or authorization is enforced. The AI Identity Gateway cannot prevent a model from being manipulated by malicious context. However, it protects upstream services by ensuring that even a subverted agent cannot exceed its authorized boundaries:
* **OPA policies as a containment boundary** -- Even if an agent's intent is hijacked, every tool invocation must pass OPA policy evaluation before reaching any upstream service. Policy authors can constrain not just which tools are allowed, but what argument values are permitted. If the OWASP attack scenario describes an agent being tricked into calling `delete_branch` on a production repository, the OPA policy can deny that tool entirely, restrict it to specific branches, or block it based on the argument values. For high-impact operations, OPA policies will soon support human-in-the-loop approval, requiring explicit human authorization before the request proceeds to the upstream service. The policy enforces the boundary regardless of what the agent's manipulated intent says.
* **Delegation tokens enforce both agent and user permissions** -- For user-delegated agents, the delegation token carries the user as the subject and the agent as the actor (`act` claim). Upstream services receive tokens that reflect both sets of permissions -- the user's actual entitlements and the agent's configured scopes. An agent acting on behalf of a read-only user cannot perform write operations on upstream services even if its intent is subverted. For autonomous agents operating without a delegating user, the token carries only the agent's own registered scopes, and OPA policies enforce boundaries based on agent identity alone. In both cases, an agent without the required scopes is blocked regardless of its intent.
* **Short-lived, per-invocation tokens** -- Delegation tokens are minted by the gateway and sent directly to upstream services -- the agent never sees or handles them. Each token is scoped to a single tool with a customizable TTL (e.g., 5s). Even if a delegation token is intercepted in transit, it expires almost immediately and cannot be used for a different tool or service.
* **Auditing enables detection** -- Action-level logging captures every tool invocation with full identity context. Unusual patterns -- unexpected tools being called, anomalous invocation frequency, suspicious parameters -- are visible in the audit trail for security teams to detect and respond to.
**Complementary controls needed:** The gateway provides damage limitation,
not prevention. To address intent flow subversion at its source, implement
AI model-layer controls: intent alignment validation, guardrail models that
review agent plans independently of potentially poisoned context, context
sanitization that treats all retrieved MCP resources as untrusted data
(not instructions), and drift detection that pauses sessions when agent
behavior deviates from the original objective. See
[OWASP MCP06](https://owasp.org/www-project-mcp-top-10/2025/MCP06-2025%E2%80%93Intent-Flow-Subversion)
for detailed model-layer mitigation guidance.
**OWASP risk:** MCP servers, tools, or agents fail to properly verify identities or enforce access controls during interactions. Manifestations include missing API validation, hardcoded secrets, static credentials, insecure token issuance without expiry or scoping, client-side-only authorization, and unverified caller metadata. Since MCP ecosystems involve multiple agents, users, and services exchanging data and executing actions, weak identity validation exposes critical attack paths: unauthorized access to sensitive operations, privilege escalation through token reuse, agent impersonation, and complete service compromise through chained malicious actions.
**Coverage: Directly addresses -- this is the core problem the gateway was built to solve**
The Orchestrator protects upstream services through multiple independent layers of authentication and authorization, addressing every vulnerability indicator OWASP lists:
1. **Agent authentication (OAuth 2.0 inbound)** -- Every agent must authenticate before accessing any upstream tools or services. The gateway validates agent tokens using JWT verification or token introspection against the [Auth Provider Orchestrator](/guides/ai-identity/overview#set-up-the-auth-provider). Unauthenticated agents receive a `401` and are directed to the authorization server via [RFC 9470 protected resource metadata](/guides/ai-identity/overview#mcp-spec-oauth-discovery-rfc-9470). There is no anonymous or guest access to upstream resources.
2. **Inbound authorization (OPA policies)** -- After authentication, every tool invocation is evaluated against Rego policies with a deny-by-default stance before reaching any upstream service. Policy authors can write granular rules based on tool name, tool argument names and values, HTTP headers (including the inbound token's identity claims), and client IP. Authorization is enforced server-side on the gateway -- never client-side.
3. **Outbound authorization (per-tool token exchange)** -- The Orchestrator performs [per-tool token exchange](/guides/ai-identity/overview#how-token-security-works) with the Auth Provider, minting a scoped delegation token for each upstream call. Each token is bound to a specific tool, carries only the scopes that tool needs, expires in seconds, and includes both agent and user identity. Tokens are not reusable across agents, tools, or sessions.
4. **Token minting policies** -- The Auth Provider Orchestrator can apply OPA-based governance during token exchange. This is an independent control point -- even if an inbound policy allows a tool call, the Auth Provider can refuse to mint the token.
5. **Centralized identity management** -- The Auth Provider Orchestrator integrates with your organizational IdP (Microsoft Entra ID, Okta, Auth0, or any OIDC provider) via [Identity Fabric connectors](/reference/orchestrator/identity-fabric). Agent identities are managed through your existing IAM infrastructure, not through separate, disconnected credential stores.
6. **Per-agent identity** -- Each agent authenticates with its own credentials. Credentials are not shared across agents. The Auth Provider defines the permitted scopes per agent registration.
**OWASP attack scenarios and how the gateway responds:**
* **Token replay** (intercepted token reused for admin operations): Delegation tokens expire quickly (with configurable TTLs, typically seconds), are scoped to a single tool, and are bound to a specific audience. A replayed token is expired, wrong-scoped, and wrong-audience.
* **Cross-environment escalation** (test and production share auth scopes): The Auth Provider can restrict which downstream services each gateway client can request tokens for. Test and production gateways use separate client registrations with separate audience restrictions.
* **Spoofed agent registration** (malicious service registers as legitimate agent): Agent registration happens in the Auth Provider's OIDC Provider configuration or upstream IdP, both under administrative control. There is no self-service or unprotected enrollment endpoint.
* **Inherited privileged credentials** (agents inherit credentials through shared context): The gateway never forwards the inbound agent's token to upstream services. Each upstream call receives a freshly minted delegation token with only the scopes configured for that specific tool. If the upstream service is another agent, it receives a scoped token -- not the calling agent's credentials. Agent-to-agent credential sharing that happens outside the gateway (through shared context or direct communication) is outside gateway scope.
**OWASP risk:** MCP systems orchestrate complex, autonomous workflows with minimal human intervention. When auditing mechanisms fail, organizations cannot track agent actions, access patterns, or decision logic. Consequences include inability to perform root-cause analysis, regulatory violations (GDPR, PCI DSS, ISO 27001), extended breach dwell time, behavioral drift going undetected, and inability to demonstrate proper data governance.
**Coverage: Directly addresses**
The Orchestrator generates comprehensive, structured audit data for every interaction with upstream services:
* **Full identity context per event** -- The Orchestrator can log all MCP requests and responses, capturing agent identity, delegating user identity, tool name, tool parameters, response content, and session ID. This creates a complete audit trail that traces every action back to both the agent and the human who authorized it. Policy authors can also add custom log messages via OPA policies for additional context.
* **Structured JSON logging** -- Logs are output in structured JSON format for direct SIEM ingestion. Session IDs correlate events across a user's session for complete interaction reconstruction.
* **Authorization decision logging** -- Every OPA policy evaluation is logged: which policies were evaluated, what input data they received, and whether access was allowed or denied. Failed authorization attempts are captured alongside successful ones.
* **Token exchange logging** -- Token exchange events are logged: which tokens were minted, for which tools, with which scopes, and with what TTL. This provides visibility into the delegation chain for every upstream call.
* **Access logging** -- HTTP-level access logging records every inbound request with method, path, status code, and timing.
**OWASP attack scenarios and how the gateway responds:**
* **Silent exfiltration** (agent exports data through legitimate tool calls without detection): Every tool call is logged with full parameters. Unusual data access patterns (large result sets, unexpected tools, high frequency) are visible in the audit trail for SIEM-based alerting.
* **Insider manipulation** (developer disables telemetry during testing): The Orchestrator's logging is configured at the infrastructure level, not controlled by individual agents or users. An agent cannot disable logging for its own sessions.
* **Prompt injection data theft** (malicious instruction causes credential retrieval): The audit trail shows the exact tool invocations, parameters, and outcomes -- enabling forensic reconstruction of what data was accessed and where it was sent.
See the [Compliance and Audit guide](/guides/security/compliance) for SIEM integration setup and the [Telemetry reference](/reference/orchestrator/telemetry) for all logging configuration.
**Downstream responsibilities:** The Orchestrator generates the audit data.
Tamper-evident storage (append-only, HMAC integrity), retention policy
enforcement, PII redaction, ML-based anomaly detection, and real-time
alerting are responsibilities of your SIEM/XDR platform (Splunk, ELK,
Sentinel, Datadog, etc.).
**OWASP risk:** Shadow MCP servers are unapproved or unsupervised MCP deployments that operate outside formal security governance. Like Shadow IT, these rogue nodes are spun up for experimentation or convenience, using default credentials, permissive configurations, or unsecured APIs. They create unmonitored attack surface, expose sensitive data processing capabilities, introduce compliance violations, and complicate incident response because untracked servers are invisible during containment and forensics.
**Coverage: Directly addresses (gateway layer)**
The Orchestrator's gateway architecture ensures agents only reach approved, governed upstream services:
* **Single entry point** -- Agents connect to the AI Identity Gateway Orchestrator, not directly to MCP servers. The gateway is the only MCP endpoint configured in agent configurations. All tool discovery and invocation flows through the gateway's authentication and authorization layers. An agent configured to use the gateway cannot reach an unregistered MCP server through the gateway.
* **Explicit server registration** -- Upstream MCP servers must be explicitly registered in the gateway. The gateway does not auto-discover, auto-register, or dynamically connect to MCP servers. Shadow servers cannot inject themselves into the tool catalog.
* **Network isolation** -- The [recommended deployment pattern](/guides/ai-identity/mcp-proxy#configure-authorization) restricts network access so that MCP servers only accept connections from the Orchestrator. Agents that attempt to bypass the gateway and connect to MCP servers directly are blocked at the network level. This turns the gateway into a mandatory checkpoint.
* **Centralized governance** -- All authentication, authorization, and audit policies are configured on the Orchestrator. Shadow servers that bypass the gateway operate without any identity governance, making them detectable through their absence from audit logs -- and through network monitoring for MCP traffic patterns outside the gateway's known endpoints.
**Complementary controls needed:** The gateway prevents managed agents from
accessing shadow servers, but does not discover shadow servers in your
network. OWASP recommends network discovery scanning (Nmap, CSPM, EASM),
passive network sensors for MCP traffic patterns, mandatory registration
governance before deployment, CI/CD pipeline gates blocking unregistered
instances, and developer education on shadow MCP risks. These are
organizational governance controls outside the scope of the gateway.
**OWASP risk:** In MCP-based systems, context acts as the working memory for agents -- storing prompts, retrieved documents, intermediate reasoning, and interaction history. When this shared context lacks proper isolation or governance, sensitive information from one task, user, or agent may be exposed to another. The risk combines context injection (malicious content embedded in shared memory) with over-sharing (reusing context across systems that should be isolated). Impact includes cross-agent and cross-user information disclosure, regulatory violations, exposure of trade secrets, and persistent behavioral contamination.
**Coverage: Reduces attack surface**
The Orchestrator protects upstream services from cross-context access through token-level and session-level isolation:
* **Per-tool token scoping** -- The gateway mints a separate delegation token for each tool invocation and sends it directly to the upstream service -- the agent never sees or handles these tokens. Each token carries only the scopes that specific tool needs. An upstream service receiving a `user:List` token cannot use it to access a different service expecting `order:List`. This prevents cross-tool data access at the authorization layer.
* **Short TTLs limit exposure** -- Delegation tokens expire in seconds. Even if a token is intercepted between the gateway and an upstream service, it cannot be reused in a different context or against a different service because it has already expired and is scoped to a single tool.
* **Delegation vs impersonation controls** -- The Orchestrator supports [two token exchange modes](/reference/modes/ai-identity-gateway#delegation-vs-impersonation). Delegation (default) produces tokens with an `act` claim that preserves full identity context -- downstream services see both agent and user identity. Impersonation produces tokens that assume the user's identity without exposing the agent's identity. Organizations choose the mode that matches their data-sharing requirements.
* **Session isolation** -- At the MCP transport layer, sessions are isolated per agent connection. One agent's session context -- including discovered tools, session state, and MCP session ID -- is not shared with other agents connecting to the same gateway. This is transport-level isolation; model-level context isolation (the core OWASP concern) is addressed in the complementary controls below.
**Complementary controls needed:** The gateway prevents **token-based**
cross-context access but does not control the **AI model's context memory**.
OWASP recommends ephemeral contexts with automatic deletion post-task,
per-user/per-agent namespace isolation in vector stores, data classification
tagging (Public/Internal/Confidential/Restricted), TTL enforcement on
context memory with automated purging, PII redaction before context storage,
and injection filtering that detects instruction-like persistence attempts.
These are AI model-layer and data pipeline controls outside the scope of
the identity gateway.
## Related Pages
Set up the Auth Provider and AI Identity Gateway with per-tool token exchange
Configure audit logging, TLS, secret management, and SIEM integration
Define OPA-based access control policies for fine-grained authorization
Complete configuration reference for MCP Provider settings, transports, and OAuth
# Scale the AI Identity Gateway for Production
Source: https://docs.strata.io/guides/ai-identity/scale-for-production
By the end of this guide, you will have a production-scaled AI Identity Gateway deployment with horizontally scaled Auth Provider and Gateway Orchestrators, load-balanced MCP traffic, optimized token exchange, and observability tuned for AI agent workloads.
The AI Identity Gateway has a [two-deployment architecture](/reference/modes/ai-identity-gateway#two-deployment-architecture): an **Auth Provider Orchestrator** (OIDC Provider) that issues and exchanges tokens, and an **AI Identity Gateway Orchestrator** (MCP Provider) that handles agent connections and tool routing. Scaling for production means scaling both deployments independently, because they have different load profiles and different infrastructure requirements.
Both the Auth Provider and AI Identity Gateway are the same Orchestrator software with different configurations. You do not need to install or manage separate products -- just deploy the same Orchestrator image with the appropriate configuration for each tier.
AI agent traffic patterns differ from human user traffic. Agents make rapid, bursty tool invocations -- a single agent session can trigger dozens of token exchanges in seconds. This guide addresses the scaling challenges specific to these patterns.
## Prerequisites
* **A working AI Identity Gateway deployment** -- You should have the Auth Provider Orchestrator and AI Identity Gateway Orchestrator configured and working in development. See the [AI Identity overview](/guides/ai-identity/overview) for setup.
* **Familiarity with production deployment basics** -- This guide builds on the [Deploy to Production](/guides/operations/deploy) and [Scale for Production](/guides/operations/scale) guides. Read those first if you have not deployed the Orchestrator to production before.
* **A load balancer with cookie and header-based session affinity** -- The Auth Provider requires cookie-based affinity (on the `maverics_session` cookie). The AI Identity Gateway requires header-based affinity (on the `Mcp-Session-Id` header). See [Configure load balancing for MCP traffic](#configure-load-balancing-for-mcp-traffic) for examples.
* **A Redis instance** -- Required for the Auth Provider Orchestrator (OIDC Provider) in multi-node deployments.
* **An observability stack** -- Prometheus, Grafana, or equivalent for metrics and dashboards. See the [Monitor guide](/guides/operations/monitor) for setup.
## Scale the AI Identity Gateway
The Auth Provider Orchestrator is a standard Maverics Orchestrator configured with an `oidcProvider` block. It runs as an OIDC Provider and handles agent authentication, token issuance, and per-tool token exchange. In an AI Identity Gateway deployment, every tool invocation triggers a token exchange request to this service.
Scale the Auth Provider horizontally with Redis caching and sticky sessions, following the same pattern as any [OIDC Provider scaling](/guides/operations/scale):
* **Redis cache is required** for multi-node OIDC Provider deployments. Authorization codes, token state, and provider data must be accessible from any instance.
* **Sticky sessions** ensure each agent's OAuth flow completes on the same instance.
Go to **Deployments** in the sidebar and select the deployment that runs your Auth Provider Orchestrator.
Under **Orchestrator Settings**, scroll to **Redis Caches** and click **Add**. Fill in the Redis connection, TLS, and encryption settings, then click **Add**.
Under **OIDC Provider**, click **Edit OIDC Provider**. Select the Redis cache you created from the **Redis Cache** dropdown and click **Save**.
Under **Session and Cookie**, click **Edit Session and Cookie**. Adjust the cache size, lifetime, and idle timeout for your expected agent volume, then click **Save**.
Configure the Auth Provider Orchestrator with Redis caching and production session settings:
```yaml maverics.yaml theme={null}
# Auth Provider Orchestrator configuration
http:
address: "{{ env.MAVERICS_HTTP_ADDRESS }}"
tls: default
tls:
default:
certFile: "{{ env.TLS_CERT_PATH }}"
keyFile: "{{ env.TLS_KEY_PATH }}"
minVersion: 1.2
caches:
- name: auth-redis
type: redis
redis:
addresses:
- "{{ env.REDIS_ADDRESS }}"
password:
tls: default
encryption:
keys:
current:
hashing:
keys:
disabled: false
session:
cookie:
name: maverics_session
domain: .example.com
lifetime:
maxTimeout: 12h
idleTimeout: 30m
store:
type: local
local:
capacity: 100000
oidcProvider:
cache: auth-redis
correlateSession: true
discovery:
issuer: https://auth.example.com
endpoints:
wellKnown: https://auth.example.com/.well-known/oauth-authorization-server
jwks: https://auth.example.com/oauth2/jwks
auth: https://auth.example.com/oauth2/auth
token: https://auth.example.com/oauth2/token
userinfo: https://auth.example.com/oauth2/userinfo
introspect: https://auth.example.com/oauth2/introspect
jwks:
- algorithm: RSA256
publicKey:
privateKey:
```
The `capacity: 100000` on the local session store accommodates the higher session volume from AI agents. Adjust this based on your expected concurrent user count.
See [Redis Cache Reference](/reference/orchestrator/caches/redis) for Redis clustering and encryption options.
The Auth Provider is the token-minting bottleneck. If agents experience slow tool invocations, check Auth Provider latency first -- every tool call requires a round-trip token exchange to this service.
The AI Identity Gateway Orchestrator is the same Maverics Orchestrator software, configured with an `mcpProvider` block instead of an `oidcProvider` block. It runs the MCP Provider with your MCP Bridge and MCP Proxy apps, handling inbound agent connections, tool discovery, OPA policy evaluation, and upstream forwarding. Unlike the Auth Provider, the Gateway Orchestrator does not use an external state store.
Go to **Deployments** in the sidebar and select the deployment that runs your AI Identity Gateway Orchestrator.
Under **Orchestrator Settings**, scroll to **MCP Provider** and click **Edit MCP Provider**. Enable the provider, configure the **Stream Endpoint**, **Session** settings (header name, timeout), and **OAuth 2.0 Authorization Settings**, then click **Save**.
Configure the AI Identity Gateway Orchestrator for production:
```yaml maverics.yaml theme={null}
# AI Identity Gateway Orchestrator configuration
http:
address: "{{ env.MAVERICS_HTTP_ADDRESS }}"
tls: default
tls:
default:
certFile: "{{ env.TLS_CERT_PATH }}"
keyFile: "{{ env.TLS_KEY_PATH }}"
minVersion: 1.2
mcpProvider:
enabled: true
transports:
stream:
enabled: true
path: /mcp
session:
enabled: true
headerName: Mcp-Session-Id
timeout: 1h
authorization:
oauth:
enabled: true
metadataPath: /.well-known/oauth-protected-resource
servers:
- wellKnownEndpoint: https://auth.example.com/.well-known/oauth-authorization-server
refreshInterval: 5m
tokenValidation:
expectedAudiences:
- https://gateway.example.com/
method: jwt
```
Key scaling considerations for the Gateway Orchestrator:
* **No Redis needed** -- The AI Identity Gateway uses token-based state tied to the upstream OAuth authorization server. Each request is independently validated.
* **MCP session affinity** -- While the Gateway is stateless for
authorization, MCP sessions (tracked via the `Mcp-Session-Id` header) maintain tool discovery state in the process memory of the instance that minted them. Configure your load balancer to pin each session to the instance that minted it; otherwise follow-up requests may land on an instance that does not recognize the session ID. See [Configure load balancing for MCP traffic](#configure-load-balancing-for-mcp-traffic) for tested LB configurations.
* **OAuth metadata refresh** -- The `refreshInterval: "5m"` ensures the Gateway periodically refreshes the Auth Provider's JWKS and metadata. In high-availability deployments, this prevents stale signing key issues during key rotation.
* **Scaling ratio** -- The Auth Provider and Gateway have different load profiles. The Auth Provider handles CPU-intensive cryptographic operations (JWT signing) per request, while the Gateway handles all inbound MCP traffic (tool discovery, OPA evaluation, upstream forwarding). Monitor both and scale each independently based on observed load.
MCP traffic uses Streamable HTTP, which is HTTP-based but has specific load balancer requirements. You need separate load balancers (or separate listener rules) for the Auth Provider and the Gateway, since they serve different roles and may scale independently.
**Auth Provider load balancer:**
* Cookie-based sticky sessions on the Orchestrator's session cookie which has a default name of `maverics_session` (same as any OIDC Provider -- see [Scale for Production](/guides/operations/scale#configure-load-balancing))
* Health check on `/status`
**AI Identity Gateway load balancer:**
* Session affinity on the `Mcp-Session-Id` header for Streamable HTTP connections
* Extended timeouts for long-lived MCP sessions (at least 1 hour to match the default `session.timeout`)
* Health check on `/status`
```nginx theme={null}
# Auth Provider upstream
upstream auth_provider {
server 10.0.1.10:9443;
server 10.0.1.11:9443;
sticky cookie maverics_session;
}
# AI Identity Gateway upstream
upstream ai_gateway {
server 10.0.2.10:9443;
server 10.0.2.11:9443;
server 10.0.2.12:9443;
# Route based on the Mcp-Session-Id header for session affinity
sticky route $http_mcp_session_id;
}
server {
listen 443 ssl;
server_name auth.example.com;
location / {
proxy_pass https://auth_provider;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
server {
listen 443 ssl;
server_name gateway.example.com;
# Extended timeouts for long-lived MCP sessions
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
location / {
proxy_pass https://ai_gateway;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
location /status {
proxy_pass https://ai_gateway/status;
}
}
```
This example uses [Envoy Gateway](https://gateway.envoyproxy.io), an open source Kubernetes Gateway API implementation.
The Auth Provider uses cookie-based session affinity (standard `BackendTrafficPolicy`). The AI Identity Gateway needs Envoy's [envelope-mode stateful session filter](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/http/stateful_session/envelope/v3/envelope.proto), which Envoy Gateway does not yet expose through `BackendTrafficPolicy.SessionPersistence` -- it must be enabled via [`EnvoyPatchPolicy`](https://gateway.envoyproxy.io/docs/tasks/extensibility/envoy-patch-policy/).
The envelope stateful session extension was added in **Envoy v1.35.0** ([envoyproxy/envoy#39004](https://github.com/envoyproxy/envoy/pull/39004)) and shipped with the default Envoy data-plane image in **Envoy Gateway v1.5.0+**. Earlier versions silently reject the patch. See the [Envoy Gateway compatibility matrix](https://gateway.envoyproxy.io/news/releases/matrix/).
`EnvoyPatchPolicy` is also disabled by default and must be turned on in the EnvoyGateway config. With the official [Helm chart](https://gateway.envoyproxy.io/docs/install/install-helm/) set `config.envoyGateway.extensionApis.enableEnvoyPatchPolicy=true` at install or upgrade time.
```yaml theme={null}
# Auth Provider -- cookie-based affinity on maverics_session
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: auth-provider
namespace: maverics
spec:
parentRefs:
- name: maverics
hostnames:
- auth.example.com
rules:
- backendRefs:
- name: auth-provider
port: 9443
---
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
metadata:
name: auth-provider-affinity
namespace: maverics
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: auth-provider
loadBalancer:
type: ConsistentHash
consistentHash:
type: Cookie
cookie:
name: maverics_session
---
# AI Identity Gateway -- HTTPRoute (LB affinity is set up via EnvoyPatchPolicy below)
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: ai-gateway
namespace: maverics
spec:
parentRefs:
- name: maverics
hostnames:
- gateway.example.com
rules:
- backendRefs:
- name: ai-gateway
port: 9443
---
# AI Identity Gateway -- session affinity via envelope-mode stateful_session.
#
# Envoy rewrites the Mcp-Session-Id response header to embed the chosen
# upstream instance's address alongside the original session ID. On subsequent
# requests, Envoy decodes the address back out and routes to that instance,
# restoring the original session ID before forwarding upstream. Transparent
# to MCP clients (the session ID is treated as opaque per the MCP spec)
# and to the AI Identity Gateway (it never sees the encoded form).
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyPatchPolicy
metadata:
name: ai-gateway-envelope-session
namespace: maverics
spec:
targetRef:
group: gateway.networking.k8s.io
kind: Gateway
name: maverics
type: JSONPatch
jsonPatches:
- type: type.googleapis.com/envoy.config.listener.v3.Listener
# Envoy Gateway names listeners //.
# Update this to match your Gateway. The listener name is also visible
# in the data-plane Envoy's /listeners admin endpoint.
name: maverics/maverics/https
operation:
op: add
path: /default_filter_chain/filters/0/typed_config/http_filters/0
value:
name: envoy.filters.http.stateful_session
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.stateful_session.v3.StatefulSession
session_state:
name: envoy.http.stateful_session.envelope
typed_config:
"@type": type.googleapis.com/envoy.extensions.http.stateful_session.envelope.v3.EnvelopeSessionState
header:
name: Mcp-Session-Id
```
**Why not just `BackendTrafficPolicy.SessionPersistence`?** Envoy Gateway exposes `Cookie` and `Header` modes there, but neither fits the MCP protocol:
* **Cookie mode** writes a `Set-Cookie` that the LB reads on subsequent requests. MCP clients typically do not use cookies, so the cookie is dropped and affinity is lost.
* **Header mode** writes the chosen upstream's address into a configured response header. If you point it at `Mcp-Session-Id`, the value collides with the session ID the AI Identity Gateway already wrote; if you point it at a sibling header, MCP clients do not know to roundtrip it.
The envelope mode rewrites the existing `Mcp-Session-Id` *value* to embed both the upstream address and the original session ID, which is the only approach that is transparent to MCP clients while preserving the protocol semantics.
This example uses the [HAProxy Kubernetes Ingress Controller](https://www.haproxy.com/documentation/kubernetes-ingress/), the official open source Ingress Controller from HAProxy Technologies.
The Auth Provider uses cookie-based session affinity (the standard [`haproxy.org/cookie-persistence`](https://www.haproxy.com/documentation/kubernetes-ingress/community/configuration-reference/ingress/#cookie-persistence) annotation). The AI Identity Gateway uses HAProxy's [stick-table](https://www.haproxy.com/documentation/haproxy-configuration-tutorials/load-balancing/sticky-sessions/) mechanism, which learns the ` → ` mapping from the upstream's `Mcp-Session-Id` response header and routes subsequent requests with the same header back to the recorded instance. The Ingress Controller does not expose stick-table-on-header as a first-class annotation, so we inject the directives via the controller's escape hatch: [`haproxy.org/backend-config-snippet`](https://www.haproxy.com/documentation/kubernetes-ingress/community/configuration-reference/ingress/#backend-config-snippet).
Install the controller via the official [Helm chart](https://github.com/haproxytech/helm-charts/tree/main/kubernetes-ingress):
```bash theme={null}
helm repo add haproxytech https://haproxytech.github.io/helm-charts
helm install haproxy-kic haproxytech/kubernetes-ingress \
-n haproxy-controller --create-namespace
```
The `backend-config-snippet` annotation passes raw HAProxy directives directly into the rendered backend section, so syntax is validated by HAProxy at reload time -- not by the controller. Malformed snippets cause HAProxy to fail to reload; check the controller pod logs after applying.
```yaml theme={null}
# Auth Provider -- cookie-based affinity on maverics_session
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: auth-provider
namespace: maverics
annotations:
haproxy.org/cookie-persistence: maverics_session
spec:
ingressClassName: haproxy
rules:
- host: auth.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: auth-provider
port:
number: 9443
---
# AI Identity Gateway -- session affinity via stick-table on Mcp-Session-Id.
#
# HAProxy maintains an in-memory stick-table keyed by the Mcp-Session-Id
# value. The `stick store-response` directive records ->
# when an upstream responds with the header (i.e. on `initialize`).
# The `stick on` directive looks up that mapping on subsequent requests
# and routes to the recorded instance -- transparent to MCP clients (they
# roundtrip the protocol-mandated Mcp-Session-Id header by spec).
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ai-gateway
namespace: maverics
annotations:
haproxy.org/load-balance: roundrobin
haproxy.org/backend-config-snippet: |
stick-table type string len 128 size 100k expire 1h
stick on req.hdr(Mcp-Session-Id)
stick store-response res.hdr(Mcp-Session-Id)
# Extended timeouts for long-lived MCP sessions
haproxy.org/timeout-client: 1h
haproxy.org/timeout-server: 1h
spec:
ingressClassName: haproxy
rules:
- host: gateway.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: ai-gateway
port:
number: 9443
```
**Why not `haproxy.org/cookie-persistence` for the AI Identity Gateway too?** The annotation works perfectly for the Auth Provider's browser-based OAuth flow, but cookie-based affinity does not work for typical MCP clients. MCP clients only roundtrip the protocol-mandated `Mcp-Session-Id` header, so the LB has to key affinity off that header rather than off a cookie it sets itself.
The stick-table state lives in HAProxy's process memory. For multi-replica HAProxy deployments, configure HAProxy [`peers`](https://docs.haproxy.org/dev/configuration.html#3.5) to replicate stick-tables across replicas; otherwise each replica builds its own table independently and traffic must remain pinned to a specific HAProxy replica (typically via L4 source-IP affinity at the upstream LB).
Per-tool token exchange is one of the core security mechanism of the AI Identity Gateway -- every tool invocation triggers a token exchange round-trip to the Auth Provider. At scale, this becomes the primary latency and throughput bottleneck.
Optimize token exchange performance:
1. **Minimize network latency between Gateway and Auth Provider** -- Deploy them in the same region and availability zones. Each tool invocation adds one round-trip to the Auth Provider, so every millisecond of network latency is multiplied by the number of tool calls.
2. **Scale the Auth Provider ahead of demand** -- The Auth Provider handles cryptographic operations (JWT signing) for every token exchange. Monitor CPU utilization on Auth Provider instances and scale horizontally before saturation. When deploying on platforms like Kubernetes, autoscaling rules can be configured based on the CPU utilization (see the Orchestrator [Helm Chart](https://github.com/strata-io/helm-charts/blob/main/charts/orchestrator/values.yaml#L93C3-L93C33) for an example).
3. **Set appropriate token TTLs** -- Short TTLs (e.g., `5s`) are the default and provide the strongest security. If your tool invocations involve slow upstream APIs, increase the TTL to avoid tokens expiring mid-request. Balance security requirements against your upstream response times.
Go to **Applications** in the sidebar and select your MCP Bridge or MCP Proxy application.
Under **Application Identity**, click **Edit**. In the **Outbound Request Authorization** section, set **Authorization Type** to **Token Exchange**, choose the **Exchange Type** and **OIDC Identity Provider**, and set the **Audience**.
Under **Tool Configurations**, click **Add Tool Configuration**. Enter the **Tool Name** (exact match or regex pattern), set a **Token Lifetime (TTL)**, and add any required **OAuth Scopes**. Repeat for each tool or tool pattern.
Configure per-tool token exchange with appropriate TTLs in your MCP Bridge or MCP Proxy app:
```yaml maverics.yaml theme={null}
# On the AI Identity Gateway Orchestrator
apps:
- name: employee-api
type: mcpBridge
mode: openapi
openapi:
spec:
uri: https://api.example.com/openapi.json
baseURL: https://api.example.com
authorization:
outbound:
type: tokenExchange
tokenExchange:
type: delegation
# Connector pointing to the Auth Provider's OIDC well-known
idp: auth-provider
audience: https://api.example.com/
tools:
- name: listEmployees
ttl: 10s
scopes:
- name: employee:List
- name: getEmployee
ttl: 10s
scopes:
- name: employee:Get
- name: createEmployee
ttl: 30s
scopes:
- name: employee:Create
```
Write operations (`createEmployee`) use a longer TTL because the upstream API may take longer to process mutations. Read operations use shorter TTLs because they complete quickly and benefit from tighter token lifetimes.
AI agent traffic generates different load patterns than human user traffic. Agents make rapid, bursty requests -- a single agent session can trigger dozens of tool invocations in seconds. Monitor both the Auth Provider and Gateway deployments to detect bottlenecks early.
Key host-level metrics to monitor on both deployments:
| Metric | Why It Matters |
| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| CPU utilization | Token exchange (Auth Provider) and policy evaluation (Gateway) are CPU-intensive. Scale horizontally when utilization exceeds 70%. |
| Memory usage | High memory on the Auth Provider may indicate Redis connection pooling issues. High memory on the Gateway may indicate excessive concurrent MCP sessions. |
| Network throughput | Every tool invocation generates a round-trip between Gateway and Auth Provider. Monitor for saturation, especially if they are in different availability zones. |
| Request rate and error rate | Use your load balancer's metrics to track inbound request volume and 5xx error rates for each deployment independently. |
| Load balancer health check failures | Indicates an Orchestrator instance is unhealthy or unreachable. Configure alerts so failed instances are investigated promptly. |
| Open file descriptors | The Gateway maintains concurrent connections: inbound from agents, outbound to the Auth Provider for token exchange, and outbound to upstream APIs. While connections are reused across requests, each concurrent agent session consumes file descriptors across all three. Ensure the OS `ulimit -n` is set high enough and monitor usage to avoid connection failures. |
See the [Monitor guide](/guides/operations/monitor) for setting up OpenTelemetry metrics and traces, and [Telemetry Reference](/reference/orchestrator/telemetry) for all configuration options.
AI Identity Gateway-specific metrics -- including token exchange latency, MCP session counts, and tool invocation rates -- are planned for a future Orchestrator release. Today, use host-level and load balancer metrics to monitor your deployment.
With both deployments scaled, load balancers configured, and observability in place, verify that the entire system works end-to-end under load.
```bash theme={null}
# Verify Auth Provider instances are healthy
curl -s https://auth.example.com/status | jq .
# Verify AI Identity Gateway instances are healthy
curl -s https://gateway.example.com/status | jq .
# Verify OAuth discovery works through the load balancer
curl -s https://gateway.example.com/.well-known/oauth-protected-resource | jq .
```
Test the full agent flow:
1. **Connect an agent to the Gateway** through the load balancer -- verify OAuth discovery returns the Auth Provider's metadata
2. **Authenticate the agent** against the Auth Provider -- verify token issuance succeeds
3. **Discover tools** -- verify the agent receives the full tool catalog
4. **Invoke a tool** -- verify the tool call succeeds end-to-end (agent → Gateway → token exchange → Auth Provider → upstream API)
5. **Check audit logs** -- verify the tool invocation is logged with both agent and user identity
6. **Simulate a Gateway instance failure** -- stop one Gateway instance and verify the agent's next request is routed to a healthy instance
7. **Simulate an Auth Provider instance failure** -- stop one Auth Provider instance and verify token exchange still succeeds via remaining instances
**Success!** Your AI Identity Gateway is scaled for production. The Auth
Provider handles token exchange with Redis-backed state, the Gateway handles
MCP traffic seamlessly, load balancers route traffic with appropriate session
affinity, and observability captures AI-specific metrics for monitoring and
alerting. Remember, both tiers are running the same Orchestrator software --
upgrades and patches apply uniformly to both deployments.
## Architecture Overview
The following diagram shows the scaled two-deployment architecture with load balancers, multiple instances, and the flow of MCP traffic:
```mermaid theme={null}
flowchart LR
subgraph Users["User-Delegated Agents"]
U1[Agent 1]
U2[Agent N]
end
subgraph Autonomous["Autonomous Agents"]
A1[Agent 1]
A2[Agent N]
end
subgraph ALB["Auth Provider Load Balancer"]
ALB1[Cookie-based sticky sessions]
end
subgraph Auth["Auth Provider (OIDC Provider)"]
AP1[Auth 1]
AP2[Auth 2]
AP3[Auth N]
end
subgraph GLB["Gateway Load Balancer"]
GLB1[MCP session affinity Extended timeouts]
end
subgraph Gateway["AI Identity Gateway (MCP Provider)"]
G1[Gateway 1]
G2[Gateway 2]
G3[Gateway N]
end
Redis[(Redis)]
APIs[Upstream APIs / MCP Servers]
U1 & U2 -->|Authentication| ALB1
A1 & A2 -->|Authentication| ALB1
ALB1 --> AP1 & AP2 & AP3
AP1 & AP2 & AP3 --> Redis
U1 & U2 -->|MCP Tool Calls| GLB1
A1 & A2 -->|MCP Tool Calls| GLB1
GLB1 --> G1 & G2 & G3
G1 & G2 & G3 -->|Token Exchange| ALB1
G1 & G2 & G3 -->|Tool Invocation| APIs
```
## Troubleshooting
High token exchange latency usually means the Auth Provider is the
bottleneck:
* **Check Auth Provider CPU** -- Token exchange involves JWT signing, which is CPU-intensive. If CPU utilization is above 70%, add more Auth Provider instances.
* **Check Redis latency** -- The Auth Provider reads/writes token state in Redis. High Redis latency propagates to every token exchange. Monitor Redis response times and consider upgrading to a larger Redis instance or a Redis cluster.
* **Check network latency** -- If the Gateway and Auth Provider are in different availability zones or regions, every tool invocation pays the cross-zone round-trip cost. Co-locate them in the same zone.
Premature session disconnections are usually caused by load balancer
timeouts:
* **Check load balancer idle timeout** -- MCP sessions can be idle between tool invocations. If the load balancer's idle timeout is shorter than the MCP session timeout, the connection drops. Set the load balancer idle timeout to at least match `mcpProvider.transports.stream.session.timeout` (default 1 hour).
* **Check proxy timeouts** -- NGINX `proxy_read_timeout` and `proxy_send_timeout` must accommodate long-lived MCP sessions. Set both to at least 3600 seconds.
If agents lose their tool catalog after a Gateway scaling event (new
instances added or removed):
* **Check session affinity** -- If the load balancer is not pinning each MCP
session to the instance that minted it, agents may be routed to a Gateway instance that does not have their session context. See [Configure load balancing for MCP traffic](#configure-load-balancing-for-mcp-traffic) for tested LB configurations; in particular, generic consistent-hashing on the `Mcp-Session-Id` header does not deliver affinity (the instance that minted the session and the instance the hash selects are uncorrelated), and cookie-based affinity does not work for MCP clients that do not use cookies.
* **Check connection draining** -- When a Gateway instance is removed, in-progress MCP sessions should drain gracefully. Configure connection draining (deregistration delay) on your load balancer to allow active sessions to complete.
* **Agent reconnection** -- Well-behaved MCP agents should reconnect and re-discover tools when a session is lost. If your agents do not handle reconnection, consider increasing the connection draining timeout.
Slow OPA policy evaluation adds latency to every tool invocation:
* **Review policy complexity** -- Complex Rego policies with external data lookups or deep object traversals take longer to evaluate. Simplify policies where possible.
* **Check policy data size** -- Large policy data sets (loaded via `data` imports) increase evaluation time. Keep policy data minimal and load only what each policy needs.
* **Monitor Gateway CPU** -- OPA evaluation is CPU-bound. If Gateway CPU is high and most of the time is in policy evaluation, scale the Gateway horizontally.
## Related Pages
Set up the AI Identity Gateway from scratch with Auth Provider and Gateway configuration
Full configuration reference for MCP Provider settings, transports, and OAuth authorization
General Orchestrator scaling guide with load balancer examples for all modes
Set up OpenTelemetry observability with metrics, traces, and structured logging
# Choosing an Orchestrator Mode
Source: https://docs.strata.io/guides/authentication/choosing-a-mode
The Maverics Orchestrator operates in five modes, each designed for a different protocol and deployment pattern. Choosing the right mode depends on what protocol your application speaks, whether you can modify the application, and what identity operations you need. Most deployments use one or two modes; some use three or more simultaneously.
This guide helps you compare all five modes side-by-side so you can pick the right one without reading each mode page individually. If you already know which mode you need, jump to the mode-specific guides linked at the bottom of this page.
All five modes share the same Orchestrator binary, configuration framework, and Service Extension SDK. The difference is in how identity is delivered to your applications -- tokens, assertions, HTTP headers, LDAP entries, or OAuth-scoped MCP context.
## Decision Matrix
The following table compares all five modes across the criteria that matter most when choosing a deployment pattern.
| Criteria | OIDC Provider | SAML Provider | HTTP Proxy | LDAP Provider | AI Identity Gateway |
| ----------------------------- | ------------------------------------------------------------------- | ------------------------------------------------------------------- | ---------------------------------------------------------------------------- | ----------------------------------------------------------------------- | ---------------------------------------------------------------- |
| **Protocol** | OpenID Connect | SAML 2.0 | HTTP | LDAP | MCP (Model Context Protocol) |
| **Best for** | Modern apps that consume OIDC tokens natively | Enterprise SAML apps with rigid federation requirements | Legacy apps where you cannot modify authentication code | LDAP-dependent apps that need a virtual directory | AI agents that invoke tools on behalf of users |
| **App modification required** | Yes -- app must be an OIDC client (relying party) | Yes -- app must be configured as a SAML SP | No -- the Orchestrator proxies traffic transparently | No -- the app connects to the Orchestrator as if it were an LDAP server | Yes -- the AI agent must be an MCP/OAuth client |
| **Identity delivery** | JWT or opaque tokens (ID token, access token, refresh token) | Signed SAML assertions with mapped attributes | HTTP headers injected into upstream requests (e.g., `SM_USER`) | LDAP entries returned via bind and search operations | OAuth access tokens with MCP tool-scoped context |
| **Authorization model** | Per-app declarative rules or OPA policies | Per-app declarative rules | Location-based policies (different rules per URL path) | Service Extension-driven (custom Go logic) | OPA policies evaluated per-tool invocation |
| **Session management** | Cookie-based sessions with configurable lifetime | Cookie-based sessions with configurable lifetime | Cookie-based sessions with configurable lifetime | Per-connection LDAP bind state | Token-based (OAuth token lifetime) |
| **Service Extensions** | Optional hooks for custom claims, authentication, and authorization | Optional hooks for custom claims, authentication, and authorization | Optional hooks for request/response modification, headers, and authorization | Required for all core operations (bind, search, credential lookup) | Optional (OPA policies are the primary authorization mechanism) |
| **Can combine with** | SAML Provider, HTTP Proxy | OIDC Provider, HTTP Proxy | OIDC Provider, SAML Provider, LDAP Provider | HTTP Proxy | Standalone (runs alongside other modes on the same Orchestrator) |
## Decision Flowchart
Use this decision tree to identify the right mode for your application. Start at question 1 and follow the path that matches your situation.
1. **Does your application support OpenID Connect natively?**
If yes, use [OIDC Provider](/reference/modes/oidc-provider). OIDC is the modern standard for authentication -- if your app supports it, this is the most straightforward mode. (Your IdP does not need to support OIDC -- the Orchestrator can translate from any upstream protocol.)
2. **Does your application only support SAML 2.0?**
If yes, use [SAML Provider](/reference/modes/saml-provider). Many enterprise apps (Salesforce, ServiceNow, Workday) require SAML assertions for federated SSO.
3. **Can you NOT modify the application's authentication code at all?**
If yes, use [HTTP Proxy](/reference/modes/http-proxy). The Orchestrator sits in front of the app as a reverse proxy, handling authentication and injecting identity headers without any changes to the application.
4. **Does your application require LDAP directory lookups for authentication or user data?**
If yes, use [LDAP Provider](/reference/modes/ldap-provider). The Orchestrator presents a virtual LDAP directory backed by modern cloud identity providers. This mode is often paired with HTTP Proxy for comprehensive legacy stack modernization.
5. **Are you securing AI agent-to-tool communication via MCP?**
If yes, use [AI Identity Gateway](/reference/modes/ai-identity-gateway). This mode adds identity, authorization, and audit to Model Context Protocol connections between AI agents and enterprise tools.
## Protocol Translation
The Orchestrator's mode determines what protocol your **application** speaks. The Identity Fabric connector determines what protocol your **identity provider** speaks. These are completely independent.
This means you do not need to match your IdP's protocol to your application's protocol. For example:
* An application that only speaks SAML can authenticate against an OIDC-only IdP (using SAML Provider mode with an OIDC connector)
* An application that only speaks OIDC can authenticate against a SAML-only IdP (using OIDC Provider mode with a SAML connector)
* An application behind HTTP Proxy can authenticate against an LDAP directory or any OIDC/SAML provider
The Orchestrator handles all protocol translation transparently. When choosing a mode, focus on what protocol your **application** requires -- the IdP side is handled by the connector, which can speak any supported protocol.
## Connector Compatibility
Every Orchestrator mode works with every Identity Fabric connector -- the Orchestrator handles protocol translation between your identity provider and your application. However, some connectors are more commonly used with certain modes. The table below shows the typical pairings and notes for each combination.
| Connector | OIDC Provider | SAML Provider | HTTP Proxy | LDAP Provider | AI Identity Gateway |
| ---------------------------------------------------------------------------- | :-----------: | :-----------: | :--------: | :---------------------: | :-----------------: |
| [Microsoft Entra ID](/reference/orchestrator/identity-fabric/azure-ad) | Common | Common | Common | Common | Common |
| [Okta](/reference/orchestrator/identity-fabric/okta) | Common | Common | Common | Common | Common |
| [PingFederate](/reference/orchestrator/identity-fabric/pingone) | Common | Common | Common | Possible | Possible |
| [Auth0](/reference/orchestrator/identity-fabric/auth0) | Common | Common | Common | Possible | Common |
| [ADFS](/reference/orchestrator/identity-fabric/adfs) | Common | Common | Common | Possible | Possible |
| [Amazon Cognito](/reference/orchestrator/identity-fabric/cognito) | Common | Possible | Possible | Possible | Common |
| [Generic OIDC](/reference/orchestrator/identity-fabric/custom-oidc) | Common | Common | Common | Possible | Common |
| [Google Workspace](/reference/orchestrator/identity-fabric/google-workspace) | Common | Common | Common | Possible | Common |
| [Generic SAML](/reference/orchestrator/identity-fabric/custom-saml) | Common | Common | Common | Rare | Rare |
| [LDAP](/reference/orchestrator/identity-fabric/ldap) | Possible | Possible | Common | Common (as attr source) | Rare |
| [Active Directory](/reference/orchestrator/identity-fabric/activedirectory) | Possible | Possible | Common | Common (as attr source) | Rare |
| [Continuity](/reference/orchestrator/identity-fabric/continuity) | Common | Common | Common | Possible | Possible |
**Common** = frequently used pairing. **Possible** = works but less typical. **Rare** = technically possible but uncommon. All connectors work with all modes -- the Orchestrator handles protocol translation. Continuity connectors aggregate multiple IdPs for failover and are mode-agnostic.
For a complete walkthrough on setting up Identity Continuity with automatic failover, see the [Identity Continuity guide](/guides/identity-continuity/overview).
## Common Combinations
Modes can run simultaneously on the same Orchestrator instance. Here are the most common combinations and when to use them.
### OIDC Provider + HTTP Proxy
Use this combination when your organization has both modern and legacy applications. Modern apps consume OIDC tokens directly from the Orchestrator's OIDC Provider. Legacy apps that cannot be modified receive identity through HTTP headers injected by the proxy. Both share the same upstream identity providers and session infrastructure.
### HTTP Proxy + LDAP Provider
Use this combination for full legacy stack modernization. Many legacy applications depend on both header-based authentication (for the web tier) and LDAP directory lookups (for user data and group membership). Running both modes on the same Orchestrator provides a complete identity bridge -- the proxy handles HTTP traffic while the virtual directory handles LDAP queries, both sourcing identity from modern cloud providers.
### OIDC Provider + SAML Provider
Use this combination to bridge modern and enterprise authentication protocols. The Orchestrator acts as both an OIDC authorization server and a SAML identity provider simultaneously. This enables protocol translation -- upstream OIDC identity providers can feed downstream SAML service providers, or vice versa -- making IdP migration possible without changing application configurations on either side.
## Deployment Topologies
The Common Combinations section above describes modes running together on a single Orchestrator instance. In production, organizations typically deploy multiple separate Orchestrator instances, each named and configured for a specific role. The Console manages all deployments from a single pane of glass. The patterns below are common starting points -- many permutations are possible depending on your organization's needs.
### Auth Provider
A centralized deployment running OIDC Provider and SAML Provider modes together. This deployment acts as the organization's identity broker -- modern apps connect via OIDC, enterprise apps connect via SAML, and both share the same upstream identity providers and session infrastructure. This is the most common starting point for organizations adopting the Orchestrator.
### AI Identity Gateway
A standalone deployment running only AI Identity Gateway mode. It secures MCP connections between AI agents and enterprise tools, enforcing identity, authorization, and audit on every tool invocation. Typically deployed alongside (but separate from) the Auth Provider so that AI identity workflows are isolated from traditional authentication traffic.
### HTTP Proxy
HTTP Proxy deployments follow two common patterns depending on the environment.
**Centralized proxy** -- A single HTTP Proxy deployment fronting multiple legacy applications. This is simpler to manage and works well when applications share similar authentication patterns and header requirements.
**Per-application proxy** -- A dedicated HTTP Proxy deployment for each legacy application. This provides isolation -- each app gets its own configuration, policies, and scaling. Use this pattern when applications have different authentication requirements or when teams manage their own infrastructure.
### LDAP Provider
LDAP Provider deployments also follow two common patterns.
**Centralized** -- A single LDAP Provider deployment serving multiple LDAP-consuming applications across the network. This minimizes the number of deployments to manage and works well when applications share similar directory schemas.
**Co-located** -- An LDAP Provider deployed on the same server (or in the same pod) as the LDAP-consuming application. This keeps LDAP traffic local -- the application connects to localhost rather than sending LDAP queries across the network. Use this pattern in security-sensitive environments or for applications with high LDAP query volume.
## Mode-Specific Guides
Configure the Orchestrator as an OIDC Provider for modern single sign-on
Federate enterprise SAML applications through the Orchestrator
Protect legacy applications with reverse proxy authentication and header injection
Migrate between identity providers with zero downtime
Set up automatic IdP failover with health monitoring and simulation testing
## Mode Reference Pages
Complete OIDC Provider configuration reference
Complete SAML Provider configuration reference
Complete HTTP Proxy configuration reference
Complete LDAP Provider configuration reference
Complete AI Identity Gateway configuration reference
Shared app fields, authorization rules, and all 5 app types
# How Authentication Works
Source: https://docs.strata.io/guides/authentication/how-auth-works
The Maverics Orchestrator handles authentication across five modes, each serving a different protocol: OIDC, SAML, HTTP, LDAP, and MCP. Although each mode speaks a different wire protocol, the three core modes -- OIDC Provider, SAML Provider, and HTTP Proxy -- follow a common authentication pipeline: intercept the request, authenticate the user against an upstream identity provider, enrich the user's attributes, establish a cookie-based session, and deliver identity to the application in the format it expects. LDAP Provider and AI Identity Gateway follow a similar pattern but handle authentication state differently: LDAP Provider uses per-connection bind state rather than cookie-based sessions, and AI Identity Gateway uses OAuth token-based state management.
This page explains how that pipeline works so you can understand the system holistically before diving into mode-specific configuration. By the end, you will know which steps are shared across the core modes, where LDAP Provider and AI Identity Gateway diverge, and how sessions and Service Extensions fit into the authentication lifecycle.
Understanding the shared pipeline also makes it easier to run multiple modes simultaneously. Many deployments combine HTTP Proxy with LDAP Provider for legacy stacks, or run OIDC Provider alongside SAML Provider for mixed application portfolios. Because OIDC Provider, SAML Provider, and HTTP Proxy share the same session and attribute enrichment infrastructure, users authenticated in one of these modes carry their identity context across the system. LDAP Provider uses per-connection bind state and does not participate in the shared session infrastructure. AI Identity Gateway uses token-based state management tied to the upstream OAuth authorization server.
## The Authentication Pipeline
OIDC Provider, SAML Provider, and HTTP Proxy follow the same six-step pipeline, with steps 2 through 4 shared across these three modes. LDAP Provider and AI Identity Gateway follow a similar pattern but differ in how they handle authentication (step 2) and session state (step 4). Steps 1 and 5 differ by mode across all five modes.
1. **Request arrives** -- A protocol-specific trigger starts the flow. For OIDC, this is an authorization request to the `/oauth2/auth` endpoint. For SAML, it is an `AuthnRequest` from a service provider. For HTTP Proxy, it is any HTTP request matching a route pattern. For LDAP, it is a bind operation on the LDAP port. For AI Identity Gateway, it is an MCP connection with an OAuth token.
2. **Upstream IdP authentication** -- The Orchestrator routes the user to a configured upstream identity provider (Microsoft Entra ID, Okta, PingFederate, or any OIDC/SAML/LDAP connector) for authentication. If multiple IdPs are configured, the Orchestrator tries them in order -- if the primary IdP is unavailable, authentication falls back to the next provider seamlessly. The [Continuity connector](/guides/identity-continuity/overview) enables health-check-driven failover without application changes.
3. **Attribute enrichment** -- After authentication succeeds, attribute providers load additional claims about the user from directories, databases, and APIs. This enrichment step aggregates identity data from multiple sources into a single profile, regardless of which IdP authenticated the user.
4. **Session establishment** -- For OIDC Provider, SAML Provider, and HTTP Proxy, the Orchestrator creates a server-side session containing the authentication state, tokens, and enriched attributes. An opaque session cookie is returned to the client. All sensitive data stays server-side -- the cookie is just an identifier. LDAP Provider maintains per-connection bind state instead of creating a cookie-based session. AI Identity Gateway relies on the upstream OAuth token lifecycle rather than Orchestrator-managed sessions. See the [Sessions documentation](/reference/orchestrator/sessions) for configuration details.
5. **Identity delivery** -- The Orchestrator delivers the authenticated identity in the format the application expects. For OIDC, this means issuing ID tokens, access tokens, and optional refresh tokens. For SAML, it means generating a signed assertion. For HTTP Proxy, it means injecting identity headers into the upstream request. For LDAP, it means returning translated directory entries. For AI Identity Gateway, it means propagating identity context through tool invocations.
6. **Ongoing operations** -- After the initial authentication, the Orchestrator manages the ongoing lifecycle: token refresh for OIDC, session expiry and re-authentication for cookie-based modes, and audit logging of identity events.
Steps 2 through 4 -- upstream authentication, attribute enrichment, and session establishment -- are shared across OIDC Provider, SAML Provider, and HTTP Proxy. If you configure a connector or attribute provider once, these modes can use it. LDAP Provider uses Service Extensions for authentication (step 2) and per-connection bind state instead of cookie-based sessions (step 4). AI Identity Gateway validates OAuth tokens (step 2) and uses token-based state (step 4). Step 3 (attribute enrichment) is available across all modes.
## Per-Mode Authentication Flows
Each mode implements the shared pipeline with protocol-specific behavior at the entry and delivery points. The following sections summarize how authentication works in each mode without duplicating the full reference documentation.
### OIDC Provider
The OIDC Provider mode configures the Orchestrator as an OpenID Connect authorization server, issuing standards-compliant tokens to applications that support OIDC natively.
1. The application redirects the user to the Orchestrator's authorization endpoint (`/oauth2/auth`) with standard OIDC parameters (client ID, redirect URI, scopes).
2. The Orchestrator authenticates the user against the configured upstream IdP. The upstream IdP can use any protocol -- the Orchestrator handles protocol translation between OIDC, SAML, and LDAP.
3. After authentication and attribute enrichment, the Orchestrator generates OIDC tokens -- an ID token, an access token, and optionally a refresh token -- with claims mapped from the authenticated identity.
4. The application receives the tokens at its redirect URI and uses them for session establishment and authorization decisions.
5. The Orchestrator serves the JWKS endpoint for token verification, handles token introspection and revocation, and manages refresh token flows.
The OIDC Provider supports both JWT and opaque access tokens, DPoP sender-bound tokens for proof-of-possession, and seamless key rotation via the JWKS array. Like all modes, the OIDC Provider can authenticate against upstream IdPs using any supported connector protocol -- OIDC, SAML, or LDAP. See the [OIDC Provider reference](/reference/modes/oidc-provider) for full configuration.
### SAML Provider
The SAML Provider mode configures the Orchestrator as a SAML 2.0 identity provider, generating signed assertions for enterprise applications that require SAML federation.
1. A SAML service provider sends an `AuthnRequest` to the Orchestrator's SSO endpoint (SP-initiated flow), or a user navigates to an IdP-initiated login URL.
2. The Orchestrator authenticates the user against the upstream IdP. The upstream IdP can use any protocol -- the Orchestrator handles protocol translation between OIDC, SAML, and LDAP.
3. After attribute enrichment, the Orchestrator generates a signed SAML assertion containing the NameID and mapped attributes.
4. The SAML response is POSTed to the service provider's assertion consumer service URL. The SP validates the signature and establishes a session.
The SAML Provider translates between protocols -- an upstream OIDC identity provider can feed a downstream SAML service provider, making IdP migration possible without changing SP configurations. See the [SAML Provider reference](/reference/modes/saml-provider) for full configuration.
### HTTP Proxy
The HTTP Proxy mode deploys the Orchestrator as an identity-aware reverse proxy, injecting authentication headers into upstream requests without requiring any changes to the application.
1. The Orchestrator intercepts HTTP requests matching configured route patterns (hostname/path combinations) before they reach the upstream application.
2. If the user does not have a valid session, the Orchestrator redirects them to the configured IdP for authentication. After authentication, a session cookie is established.
3. The Orchestrator evaluates location-based authorization rules against the user's attributes.
4. For authorized requests, the Orchestrator injects identity headers (e.g., `SM_USER`, `X-Remote-User`) into the upstream request using template syntax that maps claims from connectors.
5. The request is forwarded to the upstream backend with the injected headers. The application uses these headers for its own identity decisions.
HTTP Proxy supports location-based policies -- different URL paths within the same application can have different authentication and authorization requirements. See the [HTTP Proxy reference](/reference/modes/http-proxy) for full configuration.
### LDAP Provider
The LDAP Provider mode configures the Orchestrator as a virtual LDAP directory, presenting a standard LDAP interface to applications while sourcing identity data from modern cloud identity providers.
1. An LDAP-dependent application connects to the Orchestrator's LDAP endpoint (`ldap://` or `ldaps://`) and sends a bind request with a DN and password.
2. A Service Extension validates the credentials against a cloud identity provider -- typically by translating the LDAP bind into an authentication request against the upstream IdP.
3. After successful authentication, the application sends LDAP search requests. A search Service Extension translates these into queries against upstream identity sources and returns matching entries in LDAP format.
4. The Service Extension maps cloud IdP attributes (e.g., Microsoft Entra ID user properties) into the LDAP attribute names the application expects (e.g., `cn`, `sAMAccountName`, `memberOf`).
Every LDAP Provider integration requires Service Extensions for its core operations. The `authenticateSE` handles bind operations, and the `searchSE` handles search queries. Unlike other modes that can use declarative configuration alone, the LDAP Provider relies on Go-based Service Extension code. See the [LDAP Provider reference](/reference/modes/ldap-provider) for full configuration.
### AI Identity Gateway
The AI Identity Gateway mode extends the Orchestrator into AI agent-to-tool communication, adding identity, authorization, and audit to Model Context Protocol (MCP) connections.
1. An AI agent connects to the Orchestrator's MCP endpoint via SSE or Streamable HTTP transport and presents an OAuth access token.
2. The Orchestrator validates the agent's token against the configured OAuth authorization server. The token identifies both the agent and the delegating user.
3. The agent discovers available tools -- generated from OpenAPI specs (MCP Bridge) or discovered from upstream MCP servers (MCP Proxy).
4. When the agent invokes a tool, the Orchestrator evaluates OPA policies on the inbound request, performs token exchange to obtain a scoped delegation token, and forwards the request to the upstream service.
The AI Identity Gateway propagates both agent identity and delegated user identity through the entire tool chain, enabling least-privilege access per tool and full audit trails. See the [AI Identity Gateway reference](/reference/modes/ai-identity-gateway) for full configuration.
## Sessions and Authentication
After authentication succeeds in OIDC Provider, SAML Provider, or HTTP Proxy mode, the Orchestrator creates a server-side session that persists the user's authentication state. This session is the bridge between the initial authentication event and subsequent requests -- it eliminates the need for re-authentication on every request. LDAP Provider and AI Identity Gateway manage authentication state differently: LDAP Provider maintains per-connection bind state (see the [LDAP Provider reference](/reference/modes/ldap-provider)), and AI Identity Gateway relies on the OAuth token lifecycle (see the [AI Identity Gateway reference](/reference/modes/ai-identity-gateway)).
The session stores authentication state, tokens from upstream identity providers, and enriched attributes from attribute providers. All of this data stays server-side. The client receives only an opaque session cookie (the `maverics_session` cookie by default) that identifies the session. Because the cookie carries no sensitive data, session hijacking risks are limited to cookie theft, which is mitigated by the Orchestrator's secure cookie defaults (`HttpOnly`, `Secure`, `SameSite`).
On subsequent requests, the Orchestrator checks whether the session cookie maps to a valid, unexpired session. If it does, the user is considered authenticated and the request proceeds without re-authentication. If the session has expired or the cookie is missing, the user is redirected through the full authentication flow.
Session lifetime is controlled by two settings: a maximum lifetime (total time since authentication, default 12 hours) and an optional idle timeout (time since last activity, disabled by default). Both can be evaluated dynamically using Service Extensions, enabling context-aware timeout policies -- for example, shorter timeouts for contractors and longer timeouts for employees.
For multi-node deployments, each Orchestrator instance maintains its own local session store. To ensure users consistently reach the instance that holds their session, configure cookie-based sticky sessions (session affinity) on your load balancer using the `maverics_session` cookie.
For complete session configuration including cookie settings, lifetime controls, and store options, see the [Sessions reference](/reference/orchestrator/sessions).
## Service Extensions in the Auth Lifecycle
Service Extensions are Go-based hook functions that customize the Orchestrator's behavior at key points in the authentication and authorization lifecycle. The following hooks are most relevant to authentication:
* **`isAuthenticatedSE`** -- Runs a custom check to determine whether the user is already authenticated. Available on OIDC, SAML, and HTTP Proxy apps. Must be paired with `authenticateSE`.
* **`authenticateSE`** -- Implements custom authentication logic when standard IdP connector authentication is insufficient. Required for LDAP Provider mode. Must be paired with `isAuthenticatedSE` on OIDC, SAML, and HTTP Proxy apps.
* **`isAuthorizedSE`** -- Runs custom authorization logic after authentication succeeds. Available on all app types that support authorization rules.
* **`buildClaimsSE`** -- Constructs custom claims for SAML assertions, replacing the declarative `claimsMapping` when more complex logic is needed.
* **`buildIDTokenClaimsSE` / `buildAccessTokenClaimsSE`** -- Customize the claims included in OIDC ID tokens and access tokens, respectively.
* **`loadAttrsSE`** -- Loads custom attributes from external sources after authentication, supplementing or replacing the declarative `attrProviders` configuration.
These hooks provide escape hatches when standard configuration is insufficient. For the full list of 22 hook points and their function signatures, see the [Service Extensions reference](/reference/orchestrator/service-extensions).
## Related Pages
Configure the Orchestrator as an OpenID Connect authorization server
Configure the Orchestrator as a SAML 2.0 identity provider for federation
Protect applications with reverse proxy mode and header injection
Virtualize LDAP directories for legacy applications
Secure AI agent-to-tool communication with identity and authorization
Session stores, cookie configuration, and lifetime controls
Custom Go hooks for authentication, authorization, and claims building
Authorization rules, OPA policies, and access control patterns
# Add SSO to Web Apps
Source: https://docs.strata.io/guides/authentication/http-proxy-auth
By the end of this guide, you will have a Maverics Orchestrator deployed as an identity-aware reverse proxy -- authenticating users through your identity provider and injecting identity headers into requests to your backend application, with no application code changes required.
## What Is HTTP Proxy Mode?
HTTP Proxy authentication places the Maverics Orchestrator between your users and your backend application as a reverse proxy. The Orchestrator intercepts every request, checks whether the user is authenticated, redirects unauthenticated users to your identity provider, and then injects identity information as HTTP headers into the upstream request. Your backend application reads these headers to identify the user -- no changes to the application code or configuration are required.
This pattern is especially useful for legacy applications, COTS (commercial off-the-shelf) products, and any application that supports header-based authentication (e.g., SiteMinder-style `SM_USER` headers, `REMOTE_USER`, or custom identity headers).
## Prerequisites
* **A running Maverics Orchestrator** -- If you have not installed the Orchestrator yet, follow the [Quick Start guide](/guides/getting-started/quick-start) or see the [installation reference](/reference/orchestrator/installation).
* **An identity provider account** -- You need credentials for an identity provider that supports OIDC, such as [Microsoft Entra ID](/reference/orchestrator/identity-fabric/azure-ad), [Okta](/reference/orchestrator/identity-fabric/okta), or [Auth0](/reference/orchestrator/identity-fabric/auth0). See the full list of [Identity Fabric](/reference/orchestrator/identity-fabric).
* **A target web application** -- A web application accessible via HTTP/HTTPS that you want to protect with modern authentication. The application should accept identity information via HTTP headers.
## Configure HTTP Proxy Mode
In the Maverics Console, all configuration lives within a **Deployment** -- a managed Orchestrator instance with its own configuration, storage provider, and signing keys. Before you can create identity connectors and applications, you need a Deployment to hold them.
1. Log in to the [Maverics Console](https://maverics.strata.io).
2. Navigate to **Deployments** in the sidebar and click **Create**.
3. Enter a name for your deployment (e.g., `HTTP Proxy Auth`).
4. Select a deployment provider. The Console supports several options:
* **AWS S3**, **Azure Blob Storage**, or **Google Cloud Storage** -- customer-managed cloud storage for production.
* **GitHub** or **GitLab** -- deploy bundles to a Git repository.
* **Download Only** -- manual bundle download for air-gapped environments.
See [Publishing Deployment Configs overview](/reference/console/config-publishing#deployment-providers) for provider setup details.
5. Click **Create**.
Your new deployment opens automatically. You can now configure identity connectors and applications within it.
When using direct configuration, no deployment setup is needed -- configuration is defined directly in the `maverics.yaml` file and delivered to the Orchestrator via the `-config` flag or `MAVERICS_CONFIG` environment variable. See [Installation](/reference/orchestrator/installation) for details on configuration delivery options.
An identity provider (IdP) is the service that manages your user accounts and handles login -- think Microsoft Entra ID (now Microsoft Entra ID), Okta, or Google Workspace. Connecting the Orchestrator to your IdP tells it where to send users when they need to authenticate.
The Orchestrator uses [Identity Fabric](/reference/orchestrator/identity-fabric) connectors to communicate with your IdP. This guide demonstrates an OIDC connector, but the connector protocol is independent of the Orchestrator's mode -- even though the Orchestrator is running in HTTP Proxy mode, the IdP connector can use OIDC, SAML, or LDAP. The Orchestrator handles the protocol translation between your IdP and your application.
You will need your IdP's client ID, client secret, and discovery URL (the well-known endpoint). These credentials allow the Orchestrator to establish a trust relationship with your provider.
1. Navigate to **Identity Fabric** in the sidebar and click **Create**.
2. Select your identity provider from the list. Choose a provider-specific option (such as **Okta (OIDC)**, **Microsoft Entra ID (OIDC)**, or **Auth0 (OIDC)**) or select **Generic OIDC Configuration** for any OIDC-compliant provider. SAML and LDAP connector options are also available -- this guide demonstrates the OIDC connector path, but any connector type is valid here.
3. Fill in the connector form:
| Field | Required | Description |
| ---------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------- |
| Name | Yes | A friendly name for your identity provider (e.g., `my-idp`). |
| OIDC Well Known URL | Yes | Your IdP's OIDC discovery endpoint (e.g., `https://your-idp.example.com/.well-known/openid-configuration`). |
| OAuth Client ID | Yes | The client ID from the application you registered in your IdP for Maverics. |
| Client Authentication Method | Yes | Select **OAuth Client Secret** (default) or **OAuth JWT Client Authentication**. |
| OAuth Client Secret | Yes | The client secret from your IdP. For production, use a [secret provider](/reference/orchestrator/configuration/secret-providers). |
| Redirect URLs | Yes | The callback URL where your IdP redirects after authentication (e.g., `https://your-orchestrator.example.com/oidc-callback`). |
| Scopes | No | Space-separated OIDC scopes (e.g., `openid profile email`). |
The **PKCE** toggle is enabled by default. Disable it only if your IdP does not support Proof Key for Code Exchange.
4. Click **Save**.
Define an OIDC connector in the `connectors` section of your `maverics.yaml` file. This example uses Microsoft Entra ID, but any OIDC-compatible IdP works the same way.
```yaml maverics.yaml theme={null}
connectors:
- name: azure
type: azure
oidcWellKnownURL: https://login.microsoftonline.com/{tenant-id}/v2.0/.well-known/openid-configuration
oauthClientID: your-client-id
oauthClientSecret:
scopes: openid profile email
```
Replace `{tenant-id}` with your Microsoft Entra ID tenant ID. The `oauthClientSecret` uses the `` secret reference syntax -- the Orchestrator retrieves this value at runtime from your [secret provider](/reference/orchestrator/configuration/secret-providers) rather than reading a plaintext value from the config file.
Not sure which connector to use? The [Identity Fabric overview](/reference/orchestrator/identity-fabric) includes a comparison table mapping each connector to its supported protocols and use cases.
**Protocol translation:** This guide shows an OIDC connector, but the Orchestrator can connect to your IdP using any supported protocol -- OIDC, SAML, or LDAP. The Orchestrator's mode (HTTP Proxy) determines how your *application* receives identity (via headers). The connector determines what protocol your *IdP* speaks. These are independent -- you can connect a SAML-only or LDAP-only IdP and the Orchestrator will translate identity attributes into HTTP headers for your application. See the [Identity Fabric overview](/reference/orchestrator/identity-fabric) for all connector types.
Next, create a proxy application entry that tells the Orchestrator which hostname to listen on and where to forward requests.
1. Navigate to **Applications** in the sidebar and click **Create**.
2. Select **Proxy-based**.
3. Fill in the application form:
| Field | Required | Description |
| -------------- | -------- | ---------------------------------------------------------------------------------------------- |
| Name | Yes | A friendly name for your application (e.g., `my-legacy-app`). |
| Upstream URL | Yes | The backend URL the Orchestrator forwards requests to (e.g., `https://backend.internal:8080`). |
| Route Patterns | Yes | Hostname/path patterns the Orchestrator intercepts (e.g., `myapp.example.com`). |
Advanced fields such as TLS profile and **Preserve Host** (which forwards the original `Host` header to the upstream) are available but not required for basic setup.
4. Click **Save**.
Define a proxy application in the `apps` section. The `upstream` URL is where the Orchestrator forwards authenticated requests. The `routePatterns` define which hostnames and paths the Orchestrator intercepts.
```yaml maverics.yaml theme={null}
apps:
- name: my-legacy-app
type: proxy
upstream: https://backend.internal:8080
routePatterns:
- "myapp.example.com"
```
The `upstream` must be reachable from the Orchestrator's network. The `routePatterns` entry tells the Orchestrator to intercept all HTTP requests for `myapp.example.com` and proxy them to `https://backend.internal:8080`.
Now bind the identity connector to the proxy application by adding an authentication policy. The policy defines which paths require authentication and which IdP handles it.
In the Console, authentication policies are configured on the proxy application itself, within its access control policies.
1. Open your proxy application. In the **Resources** card, click **Edit**, click **Add Resource**, select the connector you created in Step 2, and click **Save**. A connector must be added as a resource before it can be used as an authentication source.
2. Find the **Access Control** card and click **Edit**, then click **Policy** to add an access control policy and set its **Location** to the path you want to protect (e.g., `/`).
3. From the **Select an authentication source** dropdown, select your identity provider -- the connector you added.
4. For **Authorization method**, choose **Allow all access** to permit any authenticated user (you can add rules later).
5. Click **Save**.
In the Console, an application's authentication, headers, and policies are configured together on the application. In YAML, these are separate sections within the application configuration block.
Add a `policies` section to your proxy application. The `location` defines the URL path to protect, `authentication.idps` references the connector name from Step 2, and `authorization.allowAll` permits all authenticated users.
```yaml maverics.yaml theme={null}
apps:
- name: my-legacy-app
type: proxy
upstream: https://backend.internal:8080
routePatterns:
- "myapp.example.com"
policies:
- location: "/"
authentication:
idps: ["azure"]
authorization:
allowAll: true
```
The `idps` array references the connector `name` from Step 2 (`azure`). Setting `location: "/"` protects all paths under the root. Setting `allowAll: true` authorizes every authenticated user -- you can add fine-grained authorization rules later.
This is where the Orchestrator translates identity into something your application understands. Add headers to inject user attributes from the identity provider into HTTP requests sent to your backend.
Header injection is configured within the proxy application's access control policy.
1. Open the application you configured in the previous step, find the **Access Control** card, and click **Edit**.
2. In your policy, find the **Headers** section.
3. Add header mappings:
| Field | Description |
| ----------------- | -------------------------------------------------------------------------------- |
| Header Name | The HTTP header name sent to the upstream (e.g., `SM_USER`, `REMOTE_USER`). |
| Identity Source | Select the identity provider connector to pull the attribute from. |
| Attribute Mapping | The attribute from the IdP to use as the header value (e.g., `email`, `groups`). |
4. Click **Header** to add additional rows for each header your application expects.
5. Click **Save**.
Add a `headers` section to your proxy application. Each entry specifies a header name and a value using the `{{ connector.attribute }}` template syntax.
```yaml maverics.yaml theme={null}
apps:
- name: my-legacy-app
type: proxy
upstream: https://backend.internal:8080
routePatterns:
- "myapp.example.com"
headers:
- name: SM_USER
value: "{{ azure.email }}"
- name: X-Remote-Groups
value: "{{ azure.groups }}"
policies:
- location: "/"
authentication:
idps: ["azure"]
authorization:
allowAll: true
```
The template syntax `{{ azure.email }}` pulls the `email` claim from the `azure` connector. The prefix before the dot must match the connector `name` from Step 2. Common header patterns include:
| Header Name | Purpose | Example Value |
| ----------------- | -------------------------------- | -------------------------------- |
| `SM_USER` | SiteMinder-style user identifier | `{{ azure.email }}` |
| `REMOTE_USER` | Standard remote user header | `{{ azure.preferred_username }}` |
| `X-Remote-User` | Custom user identifier | `{{ azure.email }}` |
| `X-Remote-Groups` | Group memberships | `{{ azure.groups }}` |
| `X-Remote-Name` | Display name | `{{ azure.name }}` |
After configuring your deployment, identity connector, application, and headers in the Console, you need to publish the configuration so the Orchestrator receives it and applies your changes.
1. At the bottom of the deployment Settings page, click **Publish Preview** in the sticky footer bar.
2. In the Deployment Manager dialog, review the configuration diff to verify your changes.
3. Optionally add a revision note describing what changed (e.g., "Initial HTTP Proxy auth setup").
4. Click **Publish** to deploy the configuration bundle to your storage provider.
5. The Orchestrator detects the new bundle on its next poll cycle and applies the configuration automatically.
See [Publishing Deployment Configs overview](/reference/console/config-publishing) for details on the publishing lifecycle, revision history, and bundle verification.
When using direct configuration, configuration is delivered directly to the Orchestrator via the `-config` flag or `MAVERICS_CONFIG` environment variable. No publishing step is needed -- restart the Orchestrator to apply configuration changes.
With the identity provider connected, proxy application defined, authentication policy applied, and headers configured, you are ready to test the complete authentication flow.
Start (or restart) the Orchestrator to pick up your configuration and verify it is healthy:
```bash theme={null}
maverics -config /etc/maverics/config.yaml
curl -s https://localhost:9443/status | jq .
```
A healthy response confirms the Orchestrator is running:
```json theme={null}
{
"status": "up"
}
```
Now walk through the authentication flow:
1. **Visit the proxy URL** -- Open `https://myapp.example.com` in a browser. You should be redirected to your identity provider's login page.
2. **Authenticate** -- Log in with valid credentials at the IdP.
3. **Verify redirect** -- After authentication, you should land on your backend application with full access.
4. **Verify headers** -- Check that your backend application receives the injected identity headers. If your application has a debug or profile page that displays HTTP headers, verify `SM_USER` and `X-Remote-Groups` contain the expected values.
5. **Check logs** -- Review the Orchestrator logs for authentication events confirming the flow completed successfully.
**Success!** Your Maverics Orchestrator is acting as an identity-aware reverse
proxy -- authenticating users through your identity provider and injecting
identity headers into requests to your backend application. Users experience
seamless authentication without any changes to your application code.
## Adding Authorization Rules
Once authentication is working, you can add path-specific authorization to restrict access based on user attributes like group membership.
```yaml theme={null}
policies:
- location: "/admin"
authentication:
idps: ["azure"]
authorization:
rules:
- and:
- contains: ["{{ azure.groups }}", "app-admins"]
- location: "/"
authentication:
idps: ["azure"]
authorization:
allowAll: true
```
In this example, the `/admin` path requires the user to be a member of the `app-admins` group, while all other paths are accessible to any authenticated user. Policies are evaluated in order -- more specific paths should be listed first.
For the full set of authorization operators and rule composition, see the [Security and Policies guide](/guides/security/policies) and the [Authorization reference](/reference/orchestrator/authorization).
## Troubleshooting
This usually means the Orchestrator authenticated the user successfully but
cannot reach the upstream application. Verify that the `upstream` URL is correct
and that the backend is running and accessible from the Orchestrator's network.
Check for firewall rules, DNS resolution, or TLS certificate issues between the
Orchestrator and the backend.
Verify that the `headers` section is defined at the application level (not inside
a policy). Check that the connector name in the template syntax matches the
`name` field of your connector exactly (e.g., `{{ azure.email }}` requires a
connector named `azure`). Review the Orchestrator logs for template evaluation
errors.
Ensure the `policies` section has a `location` that matches the request path.
If `location` is set to a specific path like `/app`, requests to `/` will not
trigger authentication. Use `location: "/"` to protect all paths. Also verify
that `routePatterns` matches the hostname the user is accessing.
## Related Pages
Complete configuration reference for HTTP Proxy mode -- route patterns, upstreams, headers, and policies
Authorization rules, operators, and policy composition for fine-grained access control
All supported identity providers and connector configuration
Session storage options and cookie configuration for proxy authentication
# Migrate Between Identity Providers
Source: https://docs.strata.io/guides/authentication/idp-migration
By the end of this guide, you will have a Maverics deployment that seamlessly routes authentication between your old and new identity providers -- migrating users with zero downtime and no application changes.
## Why Migrate Identity Providers?
Identity provider migration is one of the most common -- and most stressful -- projects in enterprise IAM. Organizations outgrow their current IdP, acquire companies running different providers, consolidate after mergers, or switch to a provider with better pricing or features. Whatever the reason, the migration usually affects every user and every application in the organization.
The traditional approach is painful: reconfigure every application to trust the new IdP, migrate all user accounts, coordinate a cutover date, and hope nothing breaks. With the Maverics Orchestrator, migration becomes gradual and reversible. The Orchestrator sits between your applications and both identity providers, routing authentication to whichever IdP is appropriate for each user -- so you can migrate users in batches, roll back instantly if something goes wrong, and keep every application running throughout the process.
## Prerequisites
* **A running Maverics Orchestrator** -- If you have not installed the Orchestrator yet, follow the [Quick Start guide](/guides/getting-started/quick-start) or see the [installation reference](/reference/orchestrator/installation).
* **Source identity provider connector configured** -- Your Orchestrator should already be connected to your current (source) IdP. The [SSO with OIDC guide](/guides/authentication/sso-with-oidc) covers connector setup.
* **Target identity provider account** -- You need credentials and access to the new IdP you are migrating to (for example, moving from [ADFS](/reference/orchestrator/identity-fabric/adfs) to [Microsoft Entra ID](/reference/orchestrator/identity-fabric/azure-ad), or from [Okta](/reference/orchestrator/identity-fabric/okta) to [Auth0](/reference/orchestrator/identity-fabric/auth0)).
## Configure the Migration
The first step is connecting the Orchestrator to both your source (current) and target (new) identity providers. Each provider gets its own [Identity Fabric](/reference/orchestrator/identity-fabric) with independent credentials and configuration.
If you already have a connector configured for your source IdP (from your existing Maverics deployment), you only need to add the new target connector. The Orchestrator can maintain active connections to both providers simultaneously -- users authenticating against either provider will have a seamless experience.
**Console UI documentation is coming soon.** This section will walk you
through configuring this component using the Maverics Console's visual
interface, including step-by-step screenshots and field descriptions.
Define both connectors in the `connectors` section of your `maverics.yaml` file. Each connector has its own credentials and discovery endpoint.
```yaml maverics.yaml theme={null}
connectors:
- name: source-idp
type: oidc
oidcWellKnownURL: https://source-idp.example.com/.well-known/openid-configuration
oauthClientID: orchestrator-source-client
oauthClientSecret:
oauthLoginRedirect:
urls:
- https://your-orchestrator.example.com/oidc-callback
oauthLogoutRedirect:
urls:
- https://your-orchestrator.example.com/logout
scopes: openid profile email
- name: target-idp
type: oidc
oidcWellKnownURL: https://target-idp.example.com/.well-known/openid-configuration
oauthClientID: orchestrator-target-client
oauthClientSecret:
oauthLoginRedirect:
urls:
- https://your-orchestrator.example.com/oidc-callback
oauthLogoutRedirect:
urls:
- https://your-orchestrator.example.com/logout
scopes: openid profile email
```
Both connectors can use the same redirect URLs -- the Orchestrator routes callbacks to the correct connector based on the session state. Name your connectors clearly (e.g., `source-idp` and `target-idp`) to avoid confusion during migration.
Name your connectors clearly to distinguish between source and target -- for example, `okta-source` and `azure-ad-target`. Clear naming prevents configuration mistakes during migration when you are referencing connectors in policies.
The [Continuity connector](/reference/orchestrator/identity-fabric/continuity) is what makes zero-downtime migration possible. It acts as a smart router between your two identity providers -- directing each authentication request to the right IdP based on your migration policies.
The Continuity connector wraps both of your IdP connectors and adds failover logic. If a user has already been migrated to the new IdP, their authentication is routed there. If they have not been migrated yet, authentication goes to the source IdP. If either provider is temporarily unavailable, the Continuity connector can fail over to the other -- keeping authentication working even during provider outages.
Think of it as a load balancer for identity -- but instead of distributing traffic for performance, it routes authentication based on migration state and availability.
**Console UI documentation is coming soon.** This section will walk you
through configuring this component using the Maverics Console's visual
interface, including step-by-step screenshots and field descriptions.
Add a Continuity connector that references both IdP connectors. The `failover.idps` array lists connectors in priority order -- the first entry is tried first, and subsequent entries serve as fallbacks.
```yaml maverics.yaml theme={null}
connectors:
- name: source-idp
type: oidc
oidcWellKnownURL: https://source-idp.example.com/.well-known/openid-configuration
oauthClientID: orchestrator-source-client
oauthClientSecret:
oauthLoginRedirect:
urls:
- https://your-orchestrator.example.com/oidc-callback
oauthLogoutRedirect:
urls:
- https://your-orchestrator.example.com/logout
scopes: openid profile email
- name: target-idp
type: oidc
oidcWellKnownURL: https://target-idp.example.com/.well-known/openid-configuration
oauthClientID: orchestrator-target-client
oauthClientSecret:
oauthLoginRedirect:
urls:
- https://your-orchestrator.example.com/oidc-callback
oauthLogoutRedirect:
urls:
- https://your-orchestrator.example.com/logout
scopes: openid profile email
- name: migration-connector
type: continuity
strategy: failover
failover:
idps:
- target-idp
- source-idp
attributes:
- name: email
mapping:
target-idp: email
source-idp: email
- name: name
mapping:
target-idp: name
source-idp: name
```
The Continuity connector lists `target-idp` first so the Orchestrator tries the new provider first. If the target IdP is unavailable or the user has not been migrated, it falls back to `source-idp`.
The `attributes` section normalizes attribute names across providers. Even if both IdPs use the same attribute names, explicitly mapping them ensures consistent behavior regardless of which IdP handles the authentication.
See [Continuity Connector Reference](/reference/orchestrator/identity-fabric/continuity) for all available fields.
Update your application configurations to use the Continuity connector instead of pointing directly at a single IdP. This is the key change that enables failover -- your applications reference the Continuity connector, and the connector handles routing to the appropriate IdP.
**Console UI documentation is coming soon.** This section will walk you
through configuring this component using the Maverics Console's visual
interface, including step-by-step screenshots and field descriptions.
Update the `authentication.idps` array in your application definitions to reference the Continuity connector name instead of a specific IdP connector.
```yaml maverics.yaml theme={null}
apps:
- name: my-web-app
type: oidc
clientID: my-web-app
credentials:
secrets:
-
redirectURLs:
- https://your-app.example.com/callback
authentication:
idps:
- migration-connector
accessToken:
type: jwt
claimsMapping:
email: migration-connector.email
name: migration-connector.name
```
The `authentication.idps` now references `migration-connector` (the Continuity connector) instead of a specific IdP. The `claimsMapping` also references the Continuity connector's normalized attribute names -- not the individual IdP connectors. This ensures your application receives consistent claims regardless of which IdP authenticated the user.
Always start with a small group or low percentage and monitor before
expanding. IdP migrations affect every user's ability to log in -- a
cautious rollout lets you catch configuration issues before they impact
the entire organization.
With both connectors active and the Continuity connector routing authentication, the Orchestrator begins routing authentication according to your failover configuration. Monitor the migration to ensure users are authenticating successfully against the target IdP.
Key things to watch during migration:
* **Authentication success rates** -- Compare success rates between source and target IdPs. A drop in the target IdP's success rate may indicate configuration issues.
* **User complaints** -- Users who experience login problems are likely hitting the target IdP with misconfigured attributes or missing accounts.
* **Session behavior** -- Verify that sessions created by the target IdP work correctly with all your applications.
As confidence grows, you can adjust the Continuity connector's failover order. When all users are successfully authenticating against the new provider, remove the source connector from the `failover.idps` list. Eventually, you can remove the Continuity connector entirely and point applications directly at the target IdP.
```bash theme={null}
# Check Orchestrator health and connector status during migration
curl -s https://localhost:9443/status | jq .
```
**Success!** Your Maverics Orchestrator is seamlessly routing authentication
between both identity providers. Users are being migrated gradually with
zero downtime -- and your applications required no changes at all. When the
migration is complete, remove the Continuity connector and source IdP
configuration to clean up.
## Troubleshooting
Check your Continuity connector's `failover.idps` order to verify the routing
logic is correct. The first connector in the list is always tried first. If
a user who should be on the new IdP is still authenticating against the
source, the target IdP may be rejecting the user (causing failover to the
source). Use the Orchestrator logs to trace which connector handled a specific
authentication request -- the logs show the connector name and the failover
path that was followed. Also verify that the user's account exists in the
target IdP with the correct attributes.
If a user has an active session from the source IdP and then gets routed
to the target IdP on their next login, they may see unexpected behavior --
such as being asked to re-authenticate or losing session data. This happens
when session identifiers differ between the two providers. Configure the
Orchestrator to invalidate existing sessions when a user's IdP routing
changes, or set session timeouts short enough that users naturally cycle
through during the migration window. See the
[Sessions reference](/reference/orchestrator/sessions) for
session management options.
The Orchestrator supports instant rollback -- update your Continuity
connector's `failover.idps` order to list the source IdP first. Because the
Orchestrator re-reads configuration changes, the updated failover order takes
effect on the next authentication request. After rolling back, investigate the
issue, fix the target IdP configuration, and resume the gradual rollout by
restoring the target IdP to first position.
## Related Pages
Return to the Authentication guides hub for SSO, SAML, and other authentication workflows
Supported identity providers and connector configuration for Microsoft Entra ID, Okta, Auth0, and more
Complete configuration reference for the Continuity connector -- failover, routing, and migration settings
# Modernize LDAP Authentication
Source: https://docs.strata.io/guides/authentication/ldap-provider
By the end of this guide, you will have a Maverics Orchestrator configured as a virtual LDAP directory -- authenticating LDAP bind requests against a modern cloud identity provider and returning directory data to LDAP-dependent applications, without changing the application's LDAP configuration.
## What Is LDAP Provider Mode?
Many enterprise applications -- especially legacy and commercial off-the-shelf (COTS) products -- depend on LDAP for authentication and directory lookups. These applications perform LDAP bind operations to validate user credentials and LDAP search operations to retrieve user attributes like group memberships, email addresses, and display names.
The Maverics Orchestrator's LDAP Provider mode creates a virtual LDAP directory that presents a standard LDAP interface to these applications while sourcing identity data from modern cloud identity providers such as Microsoft Entra ID, Okta, or PingFederate. Applications continue using their existing LDAP configuration -- the Orchestrator handles the translation between LDAP protocol operations and cloud IdP APIs.
The most common deployment pattern pairs LDAP Provider with [HTTP Proxy](/guides/authentication/http-proxy-auth) mode in a **facade** architecture, where the Orchestrator handles both the browser-facing authentication (via HTTP Proxy) and the application's backend LDAP operations (via LDAP Provider). See Step 6 for details on this pattern.
## Prerequisites
* **A running Maverics Orchestrator** -- If you have not installed the Orchestrator yet, follow the [Quick Start guide](/guides/getting-started/quick-start) or see the [installation reference](/reference/orchestrator/installation).
* **An identity provider account** -- You need credentials for an identity provider such as [Microsoft Entra ID](/reference/orchestrator/identity-fabric/azure-ad), [Okta](/reference/orchestrator/identity-fabric/okta), or [PingFederate](/reference/orchestrator/identity-fabric/pingone). This IdP will serve as the upstream source of identity data that the Orchestrator translates into LDAP responses.
* **A target LDAP-dependent application** -- An application that authenticates users via LDAP bind operations or retrieves user attributes via LDAP search queries.
* **Service Extension development capability (Go)** -- Unlike other Orchestrator modes, the LDAP Provider **requires** Go-based Service Extensions for its core operations. There is no declarative-only configuration path. You will need to write Service Extensions that handle LDAP bind authentication and search queries. See [Service Extensions reference](/reference/orchestrator/service-extensions).
* **Knowledge of your application's LDAP expectations** -- You must know the bind DN format your application uses, the search base DN, and the LDAP attributes it expects in search results (e.g., `cn`, `sAMAccountName`, `memberOf`).
**Service Extensions are required.** Every LDAP Provider integration requires Go-based Service Extensions to handle LDAP operations (bind authentication, search queries, credential lookups). The LDAP Provider cannot function without them. Plan for Service Extension development as part of your integration timeline.
## Configure LDAP Provider Mode
In the Maverics Console, all configuration lives within a **Deployment** -- a managed Orchestrator instance with its own configuration, storage provider, and signing keys. Before you can configure the LDAP Provider, you need a Deployment to hold the configuration.
1. Log in to the [Maverics Console](https://maverics.strata.io).
2. Navigate to **Deployments** in the sidebar and click **Create**.
3. Enter a name for your deployment (e.g., `LDAP Provider`).
4. Select a deployment provider. The Console supports several options:
* **AWS S3**, **Azure Blob Storage**, or **Google Cloud Storage** -- customer-managed cloud storage for production.
* **GitHub** or **GitLab** -- deploy bundles to a Git repository.
* **Download Only** -- manual bundle download for air-gapped environments.
See [Publishing Deployment Configs overview](/reference/console/config-publishing#deployment-providers) for provider setup details.
5. Click **Create**.
Your new deployment opens automatically. You can now configure the LDAP Provider, identity connectors, and Service Extensions within it.
When using direct configuration, no deployment setup is needed -- configuration is defined directly in the `maverics.yaml` file and delivered to the Orchestrator via the `-config` flag or `MAVERICS_CONFIG` environment variable. See [Installation](/reference/orchestrator/installation) for details on configuration delivery options.
The LDAP Provider must be enabled and configured at the deployment level. This sets up the virtual LDAP directory server that LDAP-dependent applications will connect to.
1. Open your deployment and click the **gear icon** in the sidebar to open **Deployment Settings**.
2. Find the **LDAP Provider** section.
3. Toggle **Enable** to on.
4. Select the **Protocol**: `ldap://` (unencrypted) or `ldaps://` (TLS-encrypted). Use `ldaps://` for production deployments.
5. Set the **URI** -- the address and port the LDAP Provider listens on (e.g., `ldaps://0.0.0.0:636` for TLS on the standard LDAPS port, or `ldap://0.0.0.0:389` for unencrypted).
6. If using `ldaps://`, provide the **TLS Certificate** file path and **TLS Key File** path.
7. Click **Save**.
The LDAP Provider Deployment Settings fields are documented in detail in the [LDAP Provider reference](/reference/modes/ldap-provider#setup). Use the Console UI tab there for field-by-field descriptions.
Enable the LDAP Provider in your `maverics.yaml` file. The `ldapProvider` top-level key configures the virtual directory server.
```yaml maverics.yaml theme={null}
tls:
ldap-server-tls:
certFile: /etc/maverics/certs/ldap-server.pem
keyFile: /etc/maverics/certs/ldap-server-key.pem
ldapProvider:
enabled: true
uri: ldaps://0.0.0.0:636
tls: ldap-server-tls
readDeadline: 5m
writeDeadline: 5m
rootDSE:
attributes:
namingContexts:
- dc=example,dc=com
```
The `uri` sets the listen address. Use `ldaps://` with a named TLS profile for production. The `rootDSE.attributes.namingContexts` should match the base DN that your LDAP-dependent application expects when it discovers the directory's capabilities.
See [LDAP Provider Reference](/reference/modes/ldap-provider) for all available fields, including advanced Root DSE configuration.
An identity provider (IdP) is the service that manages your user accounts -- Microsoft Entra ID, Okta, Google Workspace, or an on-premises directory. Connecting the Orchestrator to your IdP tells it where to source identity data for LDAP responses.
The Orchestrator uses [Identity Fabric](/reference/orchestrator/identity-fabric) connectors to communicate with your IdP. The connector provides the upstream identity data that your Service Extensions (configured in the next steps) will translate into LDAP responses.
You will need your IdP's client ID, client secret, and discovery URL. These credentials allow the Orchestrator to query the IdP for user authentication and attribute data.
1. Navigate to **Identity Fabric** in the sidebar and click **Create**.
2. Select your identity provider from the list. Choose a provider-specific option (such as **Okta (OIDC)**, **Microsoft Entra ID (OIDC)**, or **Auth0 (OIDC)**) or select **Generic OIDC Configuration** for any OIDC-compliant provider. SAML and LDAP connector options are also available.
3. Fill in the connector form:
| Field | Required | Description |
| ---------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------- |
| Name | Yes | A friendly name for your identity provider (e.g., `upstream-idp`). |
| OIDC Well Known URL | Yes | Your IdP's OIDC discovery endpoint (e.g., `https://your-idp.example.com/.well-known/openid-configuration`). |
| OAuth Client ID | Yes | The client ID from the application you registered in your IdP for Maverics. |
| Client Authentication Method | Yes | Select **OAuth Client Secret** (default) or **OAuth JWT Client Authentication**. |
| OAuth Client Secret | Yes | The client secret from your IdP. For production, use a [secret provider](/reference/orchestrator/configuration/secret-providers). |
| Redirect URLs | Yes | The callback URL where your IdP redirects after authentication. |
| Scopes | No | Space-separated OIDC scopes (e.g., `openid profile email`). |
4. Click **Save**.
Define a connector in the `connectors` section of your `maverics.yaml` file. The connector specifies how the Orchestrator communicates with your identity provider to retrieve user data.
```yaml maverics.yaml theme={null}
connectors:
- name: upstream-idp
type: oidc
oidcWellKnownURL: https://your-idp.example.com/.well-known/openid-configuration
oauthClientID: ldap-bridge
oauthClientSecret:
```
Replace `your-idp.example.com` with your identity provider's domain. The `oauthClientSecret` uses the `` secret reference syntax -- the Orchestrator retrieves this value at runtime from your [secret provider](/reference/orchestrator/configuration/secret-providers).
Not sure which connector to use? The [Identity Fabric overview](/reference/orchestrator/identity-fabric) includes a comparison table mapping each connector to its supported protocols and use cases.
**Protocol translation:** The Orchestrator's mode (LDAP Provider) determines what protocol your *application* speaks. The connector determines what protocol your *IdP* speaks. These are independent -- you can connect an OIDC-only or SAML-only IdP and the Orchestrator (through your Service Extensions) will translate identity data into LDAP responses for your application. See the [Identity Fabric overview](/reference/orchestrator/identity-fabric) for all connector types.
The authentication Service Extension handles LDAP bind operations. When an LDAP-dependent application sends a bind request (DN + password), this Service Extension validates the credentials against your upstream identity provider and returns success or failure.
This step is **unique to the LDAP Provider** -- other Orchestrator modes handle authentication declaratively. The LDAP Provider requires a Go Service Extension because LDAP bind semantics vary widely across applications, and the translation from LDAP bind to cloud IdP authentication (typically via OIDC Resource Owner Password Credentials grant or a direct API call) requires custom logic.
Your authentication Service Extension should:
1. Receive the bind DN and password from the LDAP client
2. Parse the bind DN to extract the username or identifier
3. Translate the credentials into an authentication request against the upstream IdP (e.g., ROPC grant, SCIM API, or direct API call)
4. Return success or failure to the LDAP client
See the [Service Extensions reference](/reference/orchestrator/service-extensions) for the function signature, available context objects, and build instructions.
**Illustrative example only.** The following Service Extension is a simplified test example with hardcoded credentials. A production implementation would validate credentials against your upstream identity provider (e.g., via ROPC grant or direct API call) and retrieve user data from `api.Session()` or `api.Cache()`. See the [Service Extensions reference](/reference/orchestrator/service-extensions) for production patterns.
```go simple.go theme={null}
import (
"strings"
"github.com/strata-io/service-extension/orchestrator"
)
// This is an example Simple Authentication Service Extension that shows a quick way
// to test a Bind request using the Simple Authentication method between the
// application and the Orchestrator. In this example, only a user with the username
// of `bob` and the password of `th3Bu!ld3R` to be authenticated.
//
// A production version of this Service Extension would typically retrieve the
// password hash of the user from either `api.Cache` or `api.Session` and would
// compute the hash of the password received and compare it with the one stored. The
// user is typically a short-lived / one-time user created by an Orchestrator serving
// as the identity-aware proxy, after the end-user has been authenticated by
// the configured IdP.
func Authenticate(api orchestrator.Orchestrator, username string, password string) (bool, error) {
api.Logger().Debug(
"service", "LDAP Provider",
"extension", "Authenticate",
"msg", "authenticating user",
"username", username,
)
if strings.EqualFold(username, "bob") && password == "th3Bu!ld3R" {
api.Logger().Debug(
"service", "LDAP Provider",
"extension", "Authenticate",
"msg", "user authenticated",
"username", username,
)
return true, nil
}
api.Logger().Debug(
"service", "LDAP Provider",
"extension", "Authenticate",
"msg", "user not authenticated",
"username", username,
)
return false, nil
}
```
1. Open your deployment and click the **gear icon** to open **Deployment Settings**.
2. In the **LDAP Provider** section, find the **Authentication** area.
3. Toggle **Enable Simple Auth** to on.
4. Under **Authentication Service Extension**, select your compiled Service Extension from the dropdown.
5. Click **Save**.
Configure the authentication Service Extension in the `ldapProvider.authentication` section.
```yaml maverics.yaml theme={null}
ldapProvider:
enabled: true
uri: ldaps://0.0.0.0:636
tls: ldap-server-tls
authentication:
allowAnonymous: false
methods:
simple:
enabled: true
authenticateSE:
file: /etc/maverics/extensions/authenticate.go
funcName: Authenticate
```
The `authenticateSE.file` points to the Go source file containing your authentication logic. The `authenticateSE.funcName` specifies the entry point function that the Orchestrator calls when it receives a bind request.
The search Service Extension handles LDAP search operations. When an LDAP-dependent application sends a search request (base DN, scope, filter, requested attributes), this Service Extension translates the query into lookups against your upstream identity sources and returns matching entries in LDAP format.
Your search Service Extension should:
1. Receive the search parameters (base DN, scope, filter, requested attributes) from the LDAP client
2. Parse the LDAP filter to determine what the application is looking for
3. Query the upstream identity source (cloud IdP API, database, etc.) for matching users or groups
4. Map the upstream attributes into the LDAP attribute names the application expects (e.g., `cn`, `sAMAccountName`, `memberOf`, `mail`)
5. Return the matching entries in LDAP format
See the [Service Extensions reference](/reference/orchestrator/service-extensions) for the function signature, available context objects, and build instructions.
**Illustrative example only.** The following Service Extension returns hardcoded attributes for a test user. A production implementation would query your upstream identity provider or attribute source for real user data, typically via `api.Session()`, `api.Cache()`, or `api.AttributeProvider()`. See the [Service Extensions reference](/reference/orchestrator/service-extensions) for production patterns.
```go search.go theme={null}
import (
"strings"
"github.com/strata-io/service-extension/ldap"
"github.com/strata-io/service-extension/orchestrator"
)
// This is an example of an Search Service Extension and shows a simple way to verify
// the LDAP connection between the application and the Orchestrator. It is configured
// to return hard-coded attributes for a test user, regardless of the Search request
// received.
//
// A production version will be dependant on the application and environment; however,
// typically, attributes originate from the end-users Session and would NOT be
// hardcoded. For example, if the policy requires a user to be authenticated
// using Entra ID, then the attributes would likely come from Entra ID, and stored
// on the cache via the Orchestrator servicing as the proxy for the application.
func Search(api orchestrator.Orchestrator, dn string, filter string, reqAttrs []string) (map[string]map[string]interface{}, error) {
api.Logger().Debug(
"service", "LDAP Provider",
"extension", "Search",
"msg", "processing request",
"user", ldap.BindDN(api.Context()),
"dn", dn,
"filter", filter,
"attributes", strings.Join(reqAttrs, ","),
)
result := make(map[string]map[string]interface{})
// User attributes would typically originate from the users Session and would NOT
// be hardcoded. For example, if the policy requires a user to be authenticated
// using Entra ID, then the attributes would likely come from Entra ID.
userAttrs := make(map[string]interface{})
userAttrs["Name"] = "Test User"
userAttrs["mail"] = "test.user@acme.org"
userAttrs["givenName"] = "Test"
userAttrs["sn"] = "User"
result["CN=Test,CN=Domain Users,CN=Users,DC=acme,DC=local"] = userAttrs
api.Logger().Debug(
"service", "LDAP Provider",
"extension", "Search",
"msg", "request processed",
"dn", dn,
"filter", filter,
"attributes", strings.Join(reqAttrs, ","),
)
return result, nil
}
```
1. Open your deployment and click the **gear icon** to open **Deployment Settings**.
2. In the **LDAP Provider** section, find the **Search** area.
3. Under **Search Service Extension**, select your compiled Service Extension from the dropdown.
4. Click **Save**.
Configure the search Service Extension in the `ldapProvider.search` section.
```yaml maverics.yaml theme={null}
ldapProvider:
enabled: true
uri: ldaps://0.0.0.0:636
tls: ldap-server-tls
search:
searchSE:
file: /etc/maverics/extensions/search.go
funcName: Search
```
The `searchSE.file` points to the Go source file containing your search logic. The `searchSE.funcName` specifies the entry point function that the Orchestrator calls when it receives a search request.
The most common LDAP Provider deployment pairs it with [HTTP Proxy](/reference/modes/http-proxy) mode in a **facade** (or "sandwich") pattern. In this architecture, the application sits between two Orchestrator roles:
* **HTTP Proxy** handles browser-facing authentication -- intercepting HTTP requests, redirecting users to a cloud IdP for modern authentication (MFA, conditional access), and injecting identity headers or stuffing login forms
* **LDAP Provider** handles the application's backend LDAP operations -- authenticating bind requests and serving search results from the same cloud IdP
This pattern lets you modernize the full authentication stack for LDAP-dependent applications without changing any application code.
**To set up the facade pattern:**
1. **Configure an HTTP Proxy application** for the web tier -- follow the [HTTP Proxy Auth guide](/guides/authentication/http-proxy-auth) to set up reverse proxy authentication with header injection or form-stuffing.
2. **Configure the LDAP Provider** (this guide) for the backend tier -- the same Orchestrator instance or a separate one handles the application's LDAP bind and search requests.
3. **Add a shared cache** if running separate Orchestrator instances -- when the HTTP Proxy and LDAP Provider run as separate Orchestrator instances (the most common facade deployment), they need a [shared cache](/reference/orchestrator/caches) so that one-time credentials generated by the proxy Orchestrator can be validated by the LDAP Provider Orchestrator.
The facade can be deployed as a single Orchestrator running both HTTP Proxy and LDAP Provider modes, two separate Orchestrator instances, or groups of Orchestrators for high-availability deployments. When both modes run on a single Orchestrator instance, the local in-memory cache is sufficient.
See the [LDAP Provider reference -- Pairing with HTTP Proxy](/reference/modes/ldap-provider#pairing-with-http-proxy) for the complete architecture diagram, credential delivery methods, and shared cache requirements.
With the LDAP Provider enabled, identity connector configured, and Service Extensions in place, you are ready to publish and test the virtual LDAP directory.
1. At the bottom of the deployment Settings page, click **Publish Preview** in the sticky footer bar.
2. In the Deployment Manager dialog, review the configuration diff to verify your changes.
3. Optionally add a revision note describing what changed (e.g., "Initial LDAP Provider setup").
4. Click **Publish** to deploy the configuration bundle to your storage provider.
5. The Orchestrator detects the new bundle on its next poll cycle and applies the configuration automatically.
See [Publishing Deployment Configs overview](/reference/console/config-publishing) for details on the publishing lifecycle, revision history, and bundle verification.
When using direct configuration, start (or restart) the Orchestrator to apply your changes:
```bash theme={null}
maverics -config /etc/maverics/config.yaml
```
**Test the LDAP connection:**
Point your LDAP client application at the Orchestrator's LDAP endpoint and verify the full flow:
1. **Test connectivity** -- Use an LDAP client tool (such as `ldapsearch` or Apache Directory Studio) to connect to the Orchestrator's LDAP URI and verify the connection is accepted.
```bash theme={null}
ldapsearch -H ldaps://your-orchestrator.example.com:636 -x -b "dc=example,dc=com" -s base "(objectClass=*)"
```
2. **Test bind authentication** -- Attempt a bind operation with valid credentials to verify the authentication Service Extension is working.
```bash theme={null}
ldapsearch -H ldaps://your-orchestrator.example.com:636 -x -D "cn=user@example.com,dc=example,dc=com" -W -b "dc=example,dc=com" "(cn=user@example.com)"
```
3. **Test search** -- After a successful bind, perform a search to verify the search Service Extension returns the expected attributes.
4. **Test with your application** -- Point your LDAP-dependent application at the Orchestrator's LDAP endpoint and walk through a full authentication and data retrieval flow.
**Success!** Your Maverics Orchestrator is acting as a virtual LDAP directory --
authenticating LDAP bind requests against your cloud identity provider and
serving directory data to your LDAP-dependent application. The application
continues using its existing LDAP configuration while the actual identity
data comes from your modern cloud IdP.
## What's Next
Complete configuration reference for LDAP Provider mode -- authentication methods, search handling, and Root DSE
Deploy the Orchestrator as a reverse proxy -- pair with LDAP Provider for the facade pattern
Write Go-based Service Extensions for custom authentication, search, and credential handling logic
Connect upstream identity providers to the Orchestrator -- Microsoft Entra ID, Okta, PingFederate, and more
# Overview
Source: https://docs.strata.io/guides/authentication/overview
The Authentication guides walk you through configuring single sign-on and federation with the Maverics Orchestrator. Start with [How Authentication Works](/guides/authentication/how-auth-works) for a conceptual overview of the authentication pipeline, then use [Choosing a Mode](/guides/authentication/choosing-a-mode) to pick the right Orchestrator mode for your applications. The step-by-step guides below walk you through configuration for each protocol.
## Understand Authentication
Understand the shared authentication pipeline across all 5 Orchestrator modes -- from request interception through session establishment
Compare OIDC Provider, SAML Provider, HTTP Proxy, LDAP Provider, and AI Identity Gateway side-by-side to pick the right mode
## Step-by-Step Guides
Configure the Orchestrator as an OIDC Provider -- connect your identity provider, define an OIDC app, map claims, and issue tokens to your application
Federate enterprise SAML applications through the Orchestrator as a SAML Provider -- configure connectors, register relying parties, and map assertion attributes
Deploy the Orchestrator as an identity-aware reverse proxy -- protect legacy applications with header-based authentication, no code changes required
Configure the Orchestrator as a virtual LDAP directory -- authenticate LDAP-dependent applications against modern cloud identity providers
Configure Single Logout to log out of all authenticated identity providers and terminate the Maverics session in one action
Migrate between identity providers with zero downtime -- configure dual connectors with Continuity-based failover and attribute normalization
## Related Pages
Complete configuration reference for the Orchestrator's OIDC Provider mode -- claims, scopes, and token settings
Supported identity providers and connector configuration for Microsoft Entra ID, Okta, Auth0, and more
Rule-based access control with enforcement behavior, per-mode differences, and real-world patterns
Session management, lifetime configuration, and how sessions integrate with authentication
Secure AI agent access to APIs and MCP tools with identity, authorization, and audit
Set up automatic IdP failover with health monitoring, Schema Abstraction Layer, and simulation testing
# Federate SAML Apps
Source: https://docs.strata.io/guides/authentication/saml-federation
By the end of this guide, you will have a Maverics Orchestrator acting as a SAML Provider -- federating authentication between your identity provider and SAML-based enterprise applications.
## What Is SAML?
SAML (Security Assertion Markup Language) is an XML-based authentication protocol that has been the standard for enterprise single sign-on for over two decades. Many enterprise applications -- especially older ones built before OIDC existed -- only support SAML for federated authentication. SAML works by exchanging signed XML documents (called assertions) between an identity provider (IdP) and a service provider (SP) to prove a user's identity.
The Maverics Orchestrator can act as a SAML Provider, receiving assertions from your identity provider and translating them into authenticated sessions for your applications. This means your applications do not need to implement SAML directly -- the Orchestrator handles the protocol complexity for them.
## Prerequisites
* **A running Maverics Orchestrator** -- If you have not installed the Orchestrator yet, follow the [Quick Start guide](/guides/getting-started/quick-start) or see the [installation reference](/reference/orchestrator/installation).
* **An identity provider account** -- While this guide demonstrates a SAML connector, the Orchestrator can connect to your IdP over OIDC, SAML, or LDAP. Your IdP does not need to support SAML specifically. Common IdPs include [Microsoft Entra ID](/reference/orchestrator/identity-fabric/azure-ad), [Okta](/reference/orchestrator/identity-fabric/okta), and [PingFederate](/reference/orchestrator/identity-fabric/pingone).
* **A target SAML application** -- An enterprise application that authenticates users via SAML assertions. Common examples include legacy portals, HR systems, and internal tools that were built for SAML-based SSO.
## Configure SAML Federation
In the Maverics Console, all configuration lives within a **Deployment** -- a managed Orchestrator instance with its own configuration, storage provider, and signing keys. Before you can create identity connectors and applications, you need a Deployment to hold them.
1. Log in to the [Maverics Console](https://maverics.strata.io).
2. Navigate to **Deployments** in the sidebar and click **Create**.
3. Enter a name for your deployment (e.g., `SAML Federation`).
4. Select a deployment provider. The Console supports several options:
* **AWS S3**, **Azure Blob Storage**, or **Google Cloud Storage** -- customer-managed cloud storage for production.
* **GitHub** or **GitLab** -- deploy bundles to a Git repository.
* **Download Only** -- manual bundle download for air-gapped environments.
See [Publishing Deployment Configs overview](/reference/console/config-publishing#deployment-providers) for provider setup details.
5. Click **Create**.
Your new deployment opens automatically. You can now configure identity connectors and applications within it.
When using direct configuration, no deployment setup is needed -- configuration is defined directly in the `maverics.yaml` file and delivered to the Orchestrator via the `-config` flag or `MAVERICS_CONFIG` environment variable. See [Installation](/reference/orchestrator/installation) for details on configuration delivery options.
The SAML Provider must be enabled and configured at the deployment level before creating connectors or applications. This configures the Orchestrator to act as a SAML identity provider to your downstream applications -- issuing signed SAML assertions after authenticating users through your upstream IdP connector.
The SAML Provider requires signing credentials (a certificate and private key) that the Orchestrator uses to sign assertions. Your downstream applications validate these signatures to ensure assertions came from a trusted source.
In the Maverics Console, SAML Provider settings are configured through the **Deployment Settings** dialog.
1. Click the **gear icon** in the sidebar to open **Deployment Settings**.
2. Find the **SAML Provider** section and configure the provider-level settings.
The SAML Provider Deployment Settings fields (Issuer, endpoints, signing options, certificates, and Redis cache) are documented in the [SAML Provider reference](/reference/modes/saml-provider#setup). Use the Console UI tab there for field-by-field details.
The key settings to configure are the **Issuer** (your Orchestrator's Entity ID) and the **Signing Option** (which parts of the SAML response to sign). Click **Generate** after entering the Issuer to auto-populate the Metadata, Single Sign-on, and Single Logout endpoint URLs.
If signing credentials (certificate and private key) are left blank, the Orchestrator auto-generates a self-signed certificate at startup. This certificate is **ephemeral** -- it is regenerated on every restart, which means all previously issued assertions become unverifiable by service providers. For production, always configure explicit signing credentials. Use the `` [secret provider](/guides/security/secrets-management) syntax to store certificates and private keys securely rather than in plaintext configuration.
Define the `samlProvider` section in your `maverics.yaml` file. This configures the Orchestrator's SAML issuer identity and signing credentials.
```yaml maverics.yaml theme={null}
samlProvider:
issuer: https://your-orchestrator.example.com
endpoints:
metadata: https://your-orchestrator.example.com/saml/metadata
singleSignOnService: https://your-orchestrator.example.com/saml/sso
singleLogoutService: https://your-orchestrator.example.com/saml/slo
signature:
certificate:
privateKey:
```
The `signature.certificate` and `signature.privateKey` use secret references -- the Orchestrator retrieves these from your [secret provider](/reference/orchestrator/configuration/secret-providers) at runtime. The certificate is included in the SAML metadata so downstream applications can validate assertion signatures.
See [SAML Provider Reference](/reference/modes/saml-provider) for all available fields.
Next, connect the Orchestrator to your identity provider as a SAML identity source. This tells the Orchestrator where to send users for authentication and how to validate the signed assertions it receives back.
SAML supports two authentication flows, and it helps to understand the difference:
* **SP-initiated** -- The user visits your application first. The Orchestrator (acting as the Service Provider) redirects the user to the identity provider for authentication, and the IdP sends the user back with a SAML assertion. This is the most common flow.
* **IdP-initiated** -- The user logs into the identity provider first (through a portal or dashboard) and then navigates to the application. The IdP sends a SAML assertion directly to the Orchestrator without a prior authentication request.
The Orchestrator supports both flows. You will need your IdP's SAML metadata URL (or metadata XML file), which contains the IdP's signing certificate, SSO endpoint URLs, and entity ID.
1. Navigate to **Identity Fabric** in the sidebar and click **Create**.
2. Select your identity provider from the list. Choose a provider-specific SAML option (such as **Okta (SAML)** or **Microsoft Entra ID (SAML)**) or select **Generic SAML** for any SAML-compliant provider. OIDC and LDAP connector options are also available -- this guide demonstrates the SAML connector path, but any connector type is valid here.
3. Fill in the connector form:
| Field | Required | Description |
| -------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Name | Yes | A friendly name for your identity provider (e.g., `my-saml-idp`). |
| Metadata URL | Yes | Your IdP's SAML metadata URL (e.g., `https://your-idp.example.com/saml/metadata`). The Orchestrator fetches signing certificates and endpoints from this URL automatically. |
| Consumer Service (ACS) URL | Yes | The Assertion Consumer Service URL where your IdP sends SAML responses after authentication (e.g., `https://your-orchestrator.example.com/saml/acs`). |
| Entity ID | Yes | The unique identifier for the Service Provider (e.g., `https://your-orchestrator.example.com`). |
| Logout Callback URL | No | The URL for Single Logout (SLO) callback. |
| SP Certificate Path | No | Path to the Service Provider certificate for request signing. |
| SP Private Key Path | No | Path to the Service Provider private key for request signing. |
| NameID Format | No | The NameID format to use in SAML assertions (e.g., `emailAddress`, `persistent`). |
The **Enable IdP Initiated Login** toggle allows authentication flows started by the identity provider. Enable this if your users will access the application from an IdP portal.
4. Click **Save**.
Define a SAML connector in the `connectors` section of your `maverics.yaml` file. The connector communicates with your identity provider over SAML 2.0.
```yaml maverics.yaml theme={null}
connectors:
- name: my-saml-idp
type: saml
samlMetadataURL: https://your-idp.example.com/saml/metadata
samlConsumerServiceURL: https://your-orchestrator.example.com/saml/acs
samlEntityID: https://your-orchestrator.example.com
```
The `samlMetadataURL` points to your identity provider's SAML metadata endpoint. The Orchestrator fetches this automatically to retrieve the IdP's signing certificate, SSO endpoint, and entity ID.
If your IdP does not publish a metadata URL, you can provide the metadata as a local file using `samlMetadataFile` instead.
Most identity providers publish a SAML metadata URL that the Orchestrator can fetch automatically. This is easier than manually entering certificates and endpoints -- the metadata contains everything the Orchestrator needs to establish the trust relationship.
**Protocol translation:** This guide shows a SAML connector, but the Orchestrator can connect to your IdP using any supported protocol -- OIDC, SAML, or LDAP. The Orchestrator's mode (SAML Provider) determines what protocol your *application* speaks. The connector determines what protocol your *IdP* speaks. These are independent -- you can connect an OIDC-only IdP and the Orchestrator will translate to SAML for your application. See the [Identity Fabric overview](/reference/orchestrator/identity-fabric) for all connector types.
Register your application as a SAML relying party (service provider) in the `apps` section. This tells the Orchestrator which application to issue SAML assertions for, where to send the assertions, and which identity connector to use for authentication.
In the Console, you create the SAML application and connect it to your identity provider in a single flow. The connector you select becomes the application's authentication source.
1. Navigate to **Applications** in the sidebar and click **Create**.
2. Select **SAML-based**.
3. Fill in the application form:
| Field | Required | Description |
| --------------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Name | Yes | A friendly name for your application (e.g., `my-saml-app`). |
| Upload Icon | No | Upload an image for your application (JPEG, PNG, or SVG, up to 2MB). |
| Default Entity ID | Yes | The entity ID identifying the service provider. Click the **Entity ID** button to add additional entity IDs. |
| Default URL (ACS) | Yes | The default Assertion Consumer Service URL. Click the **URL** button to add additional ACS URLs. |
| Logout URL | No | The URL where SAML logout responses are sent. |
| Unauthorized Page | No | Redirect URL for unauthorized users. |
| Duration | No | The duration in seconds for which responses are valid. Defaults to 300 seconds. |
| Name ID Format | No | The NameID format for the SAML assertion. The specific NameID attribute mapping is configured on the application's **Protocol & Assertion Settings** card. |
| Signing Options | No | Select **Use deployment settings** (default), **Sign Response Only**, **Sign Response & Assertion**, or **Sign Assertion Only**. |
| Certificate File (Request Verification) | No | Upload a PEM certificate to verify signed incoming requests from the SP. |
| Login URL (IDP Initiated Login) | No | Endpoint for IdP-initiated login flow. |
| Relay State URL (IDP Initiated Login) | No | Landing page URL after IdP-initiated authentication. |
4. Click **Save**.
5. On the application settings page, find the **Resources** card and click **Edit**. Click **Add Resource**, select the SAML connector you created earlier, and click **Save**. A connector must be added as a resource before it can be selected as an authentication source.
6. Find the **Access Control** card and click **Edit**.
7. From the **Select an authentication source** dropdown, select your identity provider. To add more than one source, click **Add identity provider**.
8. Click **Save**.
For any fields that accept certificates or private keys (such as SP Certificate for request verification), use [secret provider](/guides/security/secrets-management) references to avoid storing sensitive material in plaintext.
Define a SAML application in the `apps` section. The `entityIDs` and `consumerServiceURLs` identify your application in the SAML trust, and `authentication.idps` binds the connector from the first step.
```yaml maverics.yaml theme={null}
apps:
- name: my-saml-app
type: saml
entityIDs:
- identifier: https://your-app.example.com
default: true
consumerServiceURLs:
- url: https://your-app.example.com/saml/acs
default: true
logoutServiceURL: https://your-app.example.com/saml/logout
duration: 300
requestVerification:
skipVerification: true
authentication:
idps:
- my-saml-idp
```
The `entityIDs` array identifies your application in the SAML trust relationship. The `consumerServiceURLs` specify where the Orchestrator sends the SAML assertion after authentication. The `duration` sets the assertion validity period in seconds.
Set `requestVerification.skipVerification` to `true` if your application does not sign its SAML authentication requests. For applications that do sign requests, provide the application's certificate instead:
```yaml theme={null}
requestVerification:
certificate:
```
Configure the `nameID` and `claimsMapping` to control which identity attributes appear in the SAML assertions your application receives. The `nameID` is the primary user identifier in the assertion, and `claimsMapping` adds additional attributes.
1. Open the application you created in the previous step.
2. Find the **Attribute Mappings** card and click **Edit**.
3. Add a claim mapping for each attribute your application needs:
| Field | Description |
| ------------- | --------------------------------------------------------------------------------------- |
| Claim Name | The attribute name that will appear in the SAML assertion (e.g., `email`, `firstName`). |
| Claim Source | Select the identity provider connector to pull the attribute from. |
| Value Mapping | The attribute name from the identity provider (e.g., `email`, `given_name`). |
4. Click the **Claim** button to add additional rows for each claim you need to map.
For example, to pass the user's email, first name, and last name, add three claim rows:
* `email` from your IdP's `email`
* `firstName` from your IdP's `given_name`
* `lastName` from your IdP's `family_name`
5. Click **Save**.
**Configure the NameID:**
The NameID is configured separately, on the **Protocol & Assertion Settings** card.
6. Find the **Protocol & Assertion Settings** card and click **Edit**.
7. Under **NameID**, set the **Dynamic NameID Source** to the identity provider connector that provides the NameID value, and set the **Dynamic NameID Attribute** to the attribute to use as the primary subject identifier (e.g., `email`).
8. Click **Save**.
Add `nameID` and `claimsMapping` to your SAML application definition. The `nameID.attrMapping` references an attribute from your IdP connector using the format `connectorName.attributeName`.
```yaml maverics.yaml theme={null}
apps:
- name: my-saml-app
type: saml
entityIDs:
- identifier: https://your-app.example.com
default: true
consumerServiceURLs:
- url: https://your-app.example.com/saml/acs
default: true
logoutServiceURL: https://your-app.example.com/saml/logout
duration: 300
requestVerification:
skipVerification: true
nameID:
format: urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
attrMapping: my-saml-idp.email
authentication:
idps:
- my-saml-idp
claimsMapping:
email: my-saml-idp.email
firstName: my-saml-idp.given_name
lastName: my-saml-idp.family_name
```
The `nameID.format` specifies the NameID format the application expects. Common formats include `emailAddress`, `persistent`, and `unspecified`. The `attrMapping` value references the connector attribute to use as the NameID value.
The `claimsMapping` keys (`email`, `firstName`, `lastName`) become attribute names in the SAML assertion. The values reference attributes from your IdP connector.
See [SAML Provider Reference](/reference/modes/saml-provider) for all available fields, including IdP-initiated login, per-app signature settings, and advanced assertion configuration.
See the [SAML Provider reference](/reference/modes/saml-provider) for the complete list of configurable attributes, name formats, and assertion settings.
After configuring your deployment, identity connector, application, and assertion attributes in the Console, you need to publish the configuration so the Orchestrator receives it and applies your changes.
1. At the bottom of the deployment Settings page, click **Publish Preview** in the sticky footer bar.
2. In the Deployment Manager dialog, review the configuration diff to verify your changes.
3. Optionally add a revision note describing what changed (e.g., "Initial SAML federation setup").
4. Click **Publish** to deploy the configuration bundle to your storage provider.
5. The Orchestrator detects the new bundle on its next poll cycle and applies the configuration automatically.
See [Publishing Deployment Configs overview](/reference/console/config-publishing) for details on the publishing lifecycle, revision history, and bundle verification.
When using direct configuration, configuration is delivered directly to the Orchestrator via the `-config` flag or `MAVERICS_CONFIG` environment variable. No publishing step is needed -- restart the Orchestrator to apply configuration changes.
With your SAML identity source configured, your application registered as a relying party, and attribute mapping in place, you are ready to test the federated authentication flow.
Start (or restart) the Orchestrator and verify it is healthy:
```bash theme={null}
maverics -config /etc/maverics/config.yaml
curl -s https://localhost:9443/status | jq .
```
Now test the SAML flow by visiting your application's URL:
1. **Visit the application URL** -- The Orchestrator redirects you to your identity provider's login page (SP-initiated flow)
2. **Authenticate** -- Log in with valid credentials at your IdP
3. **Verify redirect** -- After authentication, you should land on your application with a valid session
4. **Check attributes** -- If your application has a profile or debug page, verify that the SAML attributes match your mapping configuration
To test the IdP-initiated flow, log into your identity provider's portal and click the application tile. You should be redirected to your application with a valid session -- no separate login required.
**Success!** Your Maverics Orchestrator is federating SAML authentication
between your identity provider and your enterprise application. Users
authenticate through your IdP, the Orchestrator translates the SAML
assertion, and your application receives the attributes it expects --
all without modifying the application.
## Troubleshooting
SAML assertions are cryptographically signed, and the Orchestrator validates
these signatures using the certificate from your IdP's metadata. If the
certificate has been rotated (updated) on the IdP side but the Orchestrator
still has the old certificate, validation fails. Re-fetch the IdP's metadata
or manually update the signing certificate in your Orchestrator configuration.
If you are using a metadata URL, the Orchestrator can pick up certificate
changes automatically on the next metadata refresh.
Your identity provider rejects the SAML request because the ACS URL
(Assertion Consumer Service URL) does not match what is registered. This is
the URL where the IdP sends the SAML response after authentication. Verify
that the ACS URL configured in the Orchestrator exactly matches the one
registered in your IdP -- including protocol, domain, port, and path. This
is similar to the redirect URI mismatch issue in OIDC.
SAML assertions include timestamps that the Orchestrator validates to prevent
replay attacks. If the clocks on your IdP server and the Orchestrator's host
are not synchronized, the Orchestrator may reject valid assertions because
they appear to be from the future or already expired. Ensure both systems use
NTP (Network Time Protocol) to keep their clocks synchronized. Most SAML
implementations allow a small clock skew tolerance (typically 1-2 minutes) --
check your Orchestrator configuration for a skew tolerance setting.
## What's Next
Move users from one identity provider to another with zero downtime and no application changes
Explore the complete SAML Provider configuration -- assertions, attributes, signing, and advanced settings
# Single Logout (SLO)
Source: https://docs.strata.io/guides/authentication/single-logout
By the end of this guide, you will have Single Logout configured on your Maverics Orchestrator -- enabling users to log out of all identity providers they authenticated with and terminate their Maverics session in a single action.
## What Is Single Logout?
When a user authenticates through the Maverics Orchestrator, they may authenticate with multiple Identity Fabric connectors during a single session. The Orchestrator's session tracks which identity providers the user has authenticated with.
Without Single Logout, ending a session with one identity provider leaves the others active. The Maverics session and other IdP sessions remain, which means the user is still effectively logged in and can access applications without re-authenticating.
Single Logout solves this by propagating the logout signal across all authenticated identity providers via **front-channel logout**. When a user visits the SLO endpoint, the Orchestrator:
1. Checks the session for each Identity Fabric connector the user authenticated with
2. For each authenticated connector, calls that connector's logout method, which redirects the user to the IdP for front-channel logout
3. Each IdP logout redirects back to the SLO handler, allowing the Orchestrator to iterate through remaining authenticated connectors
4. After all IdP logouts complete, terminates the Maverics session (preventing session replay attacks)
5. Runs the `postLogoutSE` Service Extension if configured
6. Redirects the user to the `postLogout.redirectURL`, or displays a default "You have been logged out." message if no redirect URL is configured
Single Logout is separate from any protocol-level logout endpoints you may configure on an Orchestrator running as a SAML or OIDC provider. Provider endpoints (such as `singleLogoutService` for SAML or `endSession` for OIDC) handle protocol-specific logout requests from individual service providers or relying parties. The global SLO handler, by contrast, handles the user-facing logout flow across all authenticated Identity Fabric connectors.
## Prerequisites
* **A running Maverics Orchestrator** -- If you have not installed the Orchestrator yet, follow the [Quick Start guide](/guides/getting-started/quick-start) or see the [installation reference](/reference/orchestrator/installation).
* **At least one configured application** -- An OIDC, SAML, or proxy application registered with the Orchestrator. See the [SSO with OIDC](/guides/authentication/sso-with-oidc), [Federate SAML Apps](/guides/authentication/saml-federation), or [Add SSO to Web Apps](/guides/authentication/http-proxy-auth) guides.
* **An identity provider connector** -- A configured upstream IdP. See the [Identity Fabric reference](/reference/orchestrator/identity-fabric) for supported connectors.
## Configure Single Logout
Add the `singleLogout` block at the top level of your Orchestrator configuration. This defines the post-logout redirect destination and optional Service Extension hook.
Single Logout can be configured in the Maverics Console within a Deployment.
1. Open the **Maverics Console** and navigate to the Deployment you want to configure.
2. Scroll to the **Single Logout** section.
3. Click **Edit** to open the SLO settings.
4. Set the **Logout URL** -- this is the URL that will be registered on the Orchestrator deployment and called by user interaction on an app to initiate the SLO process (e.g., `https://auth.example.com/single-logout`).
5. Under **Post Logout**, set the **Redirect URL** to where users should be sent after logout completes (e.g., `https://enterprise.com/index.html`).
6. Optionally, configure a **Post Logout Service Extension** by specifying the function name and file path for custom post-logout logic.
7. Click **Save** to apply the changes.
Add the `singleLogout` block to your `maverics.yaml` file. This block is a **top-level key** -- it is not nested under `session` or any application.
```yaml maverics.yaml theme={null}
singleLogout:
logoutURL: https://auth.example.com/single-logout
postLogout:
redirectURL: https://enterprise.com/index.html
```
| Key | Type | Required | Description |
| -------------------------------------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `singleLogout.logoutURL` | string | No | The URL registered on the Orchestrator deployment that is called by user interaction on an app to initiate the SLO process. |
| `singleLogout.postLogout.redirectURL` | string | No | Where to redirect the user after logout completes (e.g., a landing page or login screen). If not set, the Orchestrator displays a default "You have been logged out." page. |
| `singleLogout.postLogout.postLogoutSE` | object | No | A [Service Extension](/reference/orchestrator/service-extensions) hook that runs after the logout flow completes but before the redirect. Use for audit logging, cleanup, or custom logic. |
Single Logout works by iterating through the Identity Fabric connectors that the user has authenticated with during their session. Each connector's logout method is called via front-channel redirect, so the connectors must support logout.
Verify that your Identity Fabric connectors are configured correctly. The Orchestrator automatically tracks which connectors the user authenticated with via the session -- no additional per-connector SLO configuration is required beyond the standard connector setup.
If an Identity Fabric connector points to another Orchestrator deployment running as a SAML or OIDC provider, that provider deployment's logout endpoints must be configured for the front-channel logout to propagate correctly. For example, if you have an auth provider deployment and a separate proxy app deployment, and the proxy app's Identity Fabric connector points to the auth provider, ensure the auth provider has its SAML `singleLogoutService` or OIDC `endSession` endpoint configured. See the [SAML Provider](/reference/modes/saml-provider) and [OIDC Provider](/reference/modes/oidc-provider) references for details.
See the [Identity Fabric reference](/reference/orchestrator/identity-fabric) for supported connectors and their logout capabilities.
With Single Logout configured, test the end-to-end flow:
1. **Authenticate** -- Log in to one of your applications through the Orchestrator. If possible, authenticate with multiple Identity Fabric connectors to test the full front-channel logout loop.
2. **Trigger SLO** -- Navigate to the Orchestrator's Single Logout endpoint.
3. **Observe front-channel logout** -- The Orchestrator redirects through each authenticated IdP's logout endpoint in sequence. Each IdP redirects back to the SLO handler so the next IdP can be logged out.
4. **Verify redirect** -- After all IdP logouts complete, you should be redirected to the `postLogout.redirectURL` (or see a default "You have been logged out." page if no redirect URL is configured).
5. **Confirm session termination** -- Try accessing your applications. You should be prompted to re-authenticate, confirming that the Maverics session and all IdP sessions were cleared.
Enable debug-level [logging](/reference/orchestrator/telemetry/logging) to trace the SLO flow. The Orchestrator logs each IdP logout as it iterates through authenticated connectors, making it easy to verify that all IdPs are being logged out in sequence.
## Dynamic Session Expiration with SLO
You can combine Single Logout with [Service Extensions](/reference/orchestrator/service-extensions) to dynamically expire sessions and redirect users to the SLO endpoint. This is useful for enforcing role-based session policies -- for example, giving contractors shorter sessions than full-time employees.
Configure dynamic session expiration using the `evalMaxLifetimeSE` and `evalIdleTimeoutSE` hooks in the `session.lifetime` block:
```yaml maverics.yaml theme={null}
session:
lifetime:
evalMaxLifetimeSE:
funcName: EvalMaxLifetime
file: /etc/maverics/extensions/session.go
evalIdleTimeoutSE:
funcName: EvalIdleTimeout
file: /etc/maverics/extensions/session.go
store:
type: local
local:
capacity: 50000
singleLogout:
logoutURL: https://idp.enterprise.com/single-logout
postLogout:
redirectURL: https://enterprise.com/index.html
```
The Service Extension evaluates session lifetime on each request. When the session exceeds the allowed duration, the SE redirects the user to the SLO endpoint, triggering a full logout across all applications:
```go session.go theme={null}
package main
import (
"net/http"
"time"
"github.com/strata-io/service-extension/orchestrator"
)
const sloEndpoint = "https://auth.example.com/single-logout"
func EvalMaxLifetime(
api orchestrator.Orchestrator,
rw http.ResponseWriter,
req *http.Request,
createdAt time.Time,
) bool {
maxLifetime := 12 * time.Hour
employeeType, err := api.Session().GetString("idp.employeeType")
if err == nil && employeeType == "contractor" {
maxLifetime = 1 * time.Hour
}
if time.Now().After(createdAt.Add(maxLifetime)) {
api.Logger().Info("se", "session expired, redirecting to SLO")
http.Redirect(rw, req, sloEndpoint, http.StatusFound)
return false
}
return false
}
```
The `sloEndpoint` constant in the Go code should point to the Orchestrator's Single Logout endpoint. See [Local Sessions -- Dynamic Session Expiration](/reference/orchestrator/sessions/local#dynamic-session-expiration) for the complete example including idle timeout evaluation.
## Post-Logout Service Extension
The `postLogoutSE` hook runs custom logic after the SLO flow completes -- after all Identity Fabric connector logouts and the Maverics session termination, but before the user is redirected to `postLogout.redirectURL`. Common use cases include audit logging, analytics, and cleanup of external resources.
```yaml maverics.yaml theme={null}
singleLogout:
logoutURL: https://idp.enterprise.com/single-logout
postLogout:
redirectURL: https://enterprise.com/index.html
postLogoutSE:
funcName: PostLogout
file: /etc/maverics/extensions/postLogout.go
```
```go logout.go theme={null}
package main
import (
"net/http"
"github.com/strata-io/service-extension/orchestrator"
)
func PostLogout(
api orchestrator.Orchestrator,
rw http.ResponseWriter,
req *http.Request,
) {
api.Logger().Info("se", "user completed single logout",
"remoteAddr", req.RemoteAddr,
)
}
```
See [Service Extensions](/reference/orchestrator/service-extensions) for the full list of available hooks.
## Local Development
When developing and testing SLO locally, keep these considerations in mind:
* **TLS requirements** -- Session cookies default to `Secure` (HTTPS only). For local HTTP testing, set `session.cookie.disableSecure: true` in your Orchestrator configuration. Do not use this setting in production.
* **Cookie domain** -- If your local applications run on different ports of `localhost`, set `session.cookie.domain` to `localhost` so the session cookie is shared across ports.
* **IdP logout** -- Some IdPs may not support logout redirects to `localhost`. During local development, you can test the Maverics session termination without full IdP front-channel logout propagation.
Example local development configuration:
```yaml maverics.yaml theme={null}
http:
address: 0.0.0.0:8443
tls: server
tls:
server:
certFile: /etc/maverics/certs/localhost.pem
keyFile: /etc/maverics/certs/localhost-key.pem
session:
cookie:
domain: localhost
disableSecure: false
store:
type: local
local:
capacity: 1000
singleLogout:
logoutURL: https://localhost:8443/single-logout
postLogout:
redirectURL: https://localhost:8443/
```
Use tools like [mkcert](https://github.com/FiloSottile/mkcert) to generate locally-trusted TLS certificates. This avoids browser security warnings and keeps your local environment closer to production by keeping the `Secure` cookie flag enabled.
## Troubleshooting
**Symptoms:** After triggering Single Logout, the user is immediately logged back in when accessing an application.
**Causes:**
* An Identity Fabric connector's logout did not fully clear the IdP session. The upstream IdP recognizes the user's existing session and silently re-authenticates without prompting for credentials.
* The connector does not support logout, so the SLO flow skipped it.
**Resolution:**
1. Verify that your Identity Fabric connectors support logout and are configured correctly. See the [Identity Fabric reference](/reference/orchestrator/identity-fabric) for connector-specific logout support.
2. Enable debug-level logging to confirm the Orchestrator is iterating through all authenticated connectors during the SLO flow.
3. Verify that each IdP's logout endpoint redirects back to the Orchestrator so the front-channel logout loop can continue to the next connector.
**Symptoms:** Navigating to the Single Logout endpoint returns a 404 error.
**Causes:**
* The `singleLogout` block is missing from the Orchestrator configuration.
* The Orchestrator has not been restarted after adding the `singleLogout` block.
**Resolution:**
1. Verify that the `singleLogout` block exists at the top level of your configuration (not nested under `session` or any app).
2. Restart the Orchestrator after making configuration changes.
**Symptoms:** The SLO flow starts but gets stuck or only logs out of one IdP.
**Causes:**
* An IdP's logout endpoint does not redirect back to the Orchestrator's SLO handler.
* A network or TLS issue prevents the redirect from reaching the Orchestrator.
**Resolution:**
1. Check that each IdP is configured to redirect back to the Orchestrator after logout. The SLO handler relies on these redirects to iterate through all authenticated connectors.
2. Enable debug-level logging to see which connector the flow stopped at.
3. Verify TLS and network connectivity between the Orchestrator and each IdP.
**Symptoms:** After SLO completes, the user sees "You have been logged out." instead of being redirected.
**Causes:**
* The `postLogout.redirectURL` is not set. The Orchestrator defaults to displaying a plain text message when no redirect URL is configured.
* A `postLogoutSE` is configured and writes its own response, overriding the redirect behavior.
**Resolution:**
1. Set `singleLogout.postLogout.redirectURL` to a valid URL.
2. If using a `postLogoutSE`, ensure the SE does not write its own HTTP response or redirect -- doing so overrides the default redirect behavior.
## What's Next
Complete reference for all logout types including Single Logout configuration
Session store configuration, dynamic session expiration, and session management
Custom Go hooks including postLogoutSE for post-logout logic
Session types, lifecycle, and production deployment guidance
# SSO with OIDC
Source: https://docs.strata.io/guides/authentication/sso-with-oidc
By the end of this guide, you will have a running Maverics Orchestrator configured as an OIDC Provider -- authenticating users through your identity provider and issuing tokens to your application.
## Prerequisites
* **A running Maverics Orchestrator** -- If you have not installed the Orchestrator yet, follow the [Quick Start guide](/guides/getting-started/quick-start) or see the [installation reference](/reference/orchestrator/installation).
* **An identity provider account** -- You need credentials for an identity provider such as [Microsoft Entra ID](/reference/orchestrator/identity-fabric/azure-ad), [Okta](/reference/orchestrator/identity-fabric/okta), or [Auth0](/reference/orchestrator/identity-fabric/auth0). While this guide demonstrates an OIDC connector, the Orchestrator supports OIDC, SAML, and LDAP connectors, so your IdP does not need to support OIDC specifically.
* **A target application** -- Any web application that accepts OIDC tokens or that you want to protect with OIDC-based single sign-on.
## Configure SSO
In the Maverics Console, all configuration lives within a **Deployment** -- a managed Orchestrator instance with its own configuration, storage provider, and signing keys. Before you can create identity connectors and applications, you need a Deployment to hold them.
1. Log in to the [Maverics Console](https://maverics.strata.io).
2. Navigate to **Deployments** in the sidebar and click **Create**.
3. Enter a name for your deployment (e.g., `OIDC SSO`).
4. Select a deployment provider. The Console supports several options:
* **AWS S3**, **Azure Blob Storage**, or **Google Cloud Storage** -- customer-managed cloud storage for production.
* **GitHub** or **GitLab** -- deploy bundles to a Git repository.
* **Download Only** -- manual bundle download for air-gapped environments.
See [Publishing Deployment Configs overview](/reference/console/config-publishing#deployment-providers) for provider setup details.
5. Click **Create**.
Your new deployment opens automatically. You can now configure identity connectors and applications within it.
When using direct configuration, no deployment setup is needed -- configuration is defined directly in the `maverics.yaml` file and delivered to the Orchestrator via the `-config` flag or `MAVERICS_CONFIG` environment variable. See [Installation](/reference/orchestrator/installation) for details on configuration delivery options.
The OIDC Provider must be enabled and configured at the deployment level before creating applications. This sets up the issuer identity, endpoints, and signing keys that all OIDC applications in the deployment share.
1. Open your deployment and click the **gear icon** in the sidebar to open **Deployment Settings**.
2. Find the **OIDC Provider** section.
3. Enter the **Issuer** URL (e.g., `https://your-orchestrator.example.com`). This becomes the `iss` claim in all issued tokens.
4. Click **Generate** to auto-populate the Well-Known, Authorization, Token, Introspect, Revocation, End Session, UserInfo, and JWKS endpoint URLs from the Issuer.
5. Under **JSON Web Keys**, click **Edit JSON Web Keys** to configure the signing key pair used for token signing.
6. Click **Save**.
If JSON Web Keys are left blank, the Orchestrator auto-generates a signing key pair at startup. This key pair is **ephemeral** -- a new one is created every time the Orchestrator restarts, which means all previously issued tokens become unverifiable. Only rely on auto-generated keys for local development and testing. For production, always configure explicit signing keys managed by a [secret provider](/guides/security/secrets-management).
The OIDC Provider Deployment Settings fields are documented in detail in the [OIDC Provider reference](/reference/modes/oidc-provider#setup). Use the Console UI tab there for field-by-field descriptions.
In YAML, the OIDC Provider is configured via the `oidcProvider` top-level key. This is shown in the next step alongside the application configuration.
If the `jwks` array is omitted from `oidcProvider`, the Orchestrator auto-generates a signing key pair at startup. This key pair is **ephemeral** -- it is regenerated on every restart, invalidating all previously issued tokens. For production deployments, always provide explicit keys using [secret provider](/guides/security/secrets-management) references (e.g., ``).
An identity provider (IdP) is the service that manages your user accounts and handles login -- think Microsoft Entra ID (now Microsoft Entra ID), Okta, or Google Workspace. Connecting the Orchestrator to your IdP tells it where to send users when they need to authenticate.
The Orchestrator uses [Identity Fabric](/reference/orchestrator/identity-fabric) connectors to communicate with your IdP. This guide demonstrates an OIDC connector, but the connector protocol is independent of the Orchestrator's mode -- even though the Orchestrator is serving OIDC to your application, the IdP connector can use OIDC, SAML, or LDAP. The Orchestrator handles the protocol translation between your IdP and your application.
You will need your IdP's client ID, client secret, and discovery URL (sometimes called the issuer URL or well-known endpoint). These credentials allow the Orchestrator to establish a trust relationship with your provider.
1. Navigate to **Identity Fabric** in the sidebar and click **Create**.
2. Select your identity provider from the list. Choose a provider-specific option (such as **Okta (OIDC)**, **Microsoft Entra ID (OIDC)**, or **Auth0 (OIDC)**) or select **Generic OIDC Configuration** for any OIDC-compliant provider. SAML and LDAP connector options are also available -- this guide demonstrates the OIDC connector path, but any connector type is valid here.
3. Fill in the connector form:
| Field | Required | Description |
| ---------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------- |
| Name | Yes | A friendly name for your identity provider (e.g., `my-idp`). |
| OIDC Well Known URL | Yes | Your IdP's OIDC discovery endpoint (e.g., `https://your-idp.example.com/.well-known/openid-configuration`). |
| OAuth Client ID | Yes | The client ID from the application you registered in your IdP for Maverics. |
| Client Authentication Method | Yes | Select **OAuth Client Secret** (default) or **OAuth JWT Client Authentication**. |
| OAuth Client Secret | Yes | The client secret from your IdP. For production, use a [secret provider](/reference/orchestrator/configuration/secret-providers). |
| Redirect URLs | Yes | The callback URL where your IdP redirects after authentication (e.g., `https://your-orchestrator.example.com/oidc-callback`). |
| Scopes | No | Space-separated OIDC scopes (e.g., `openid profile email`). |
The **PKCE** toggle is enabled by default. Disable it only if your IdP does not support Proof Key for Code Exchange.
4. Click **Save**.
Define an OIDC connector in the `connectors` section of your `maverics.yaml` file. The connector specifies how the Orchestrator communicates with your identity provider.
```yaml maverics.yaml theme={null}
connectors:
- name: my-idp
type: oidc
oidcWellKnownURL: https://your-idp.example.com/.well-known/openid-configuration
oauthClientID: your-orchestrator-client-id
oauthClientSecret:
oauthLoginRedirect:
urls:
- https://your-orchestrator.example.com/oidc-callback
oauthLogoutRedirect:
urls:
- https://your-orchestrator.example.com/logout
disablePKCE: false
scopes: openid profile email
```
Replace `your-idp.example.com` with your identity provider's domain. The `oidcWellKnownURL` points to the OIDC discovery endpoint, which provides the Orchestrator with all of the IdP's endpoints and signing keys automatically.
The `oauthClientSecret` uses the `` secret reference syntax -- the Orchestrator retrieves this value at runtime from your [secret provider](/reference/orchestrator/configuration/secret-providers) rather than reading a plaintext value from the config file.
Not sure which connector to use? The [Identity Fabric overview](/reference/orchestrator/identity-fabric) includes a comparison table mapping each connector to its supported protocols and use cases.
**Protocol translation:** This guide shows an OIDC connector, but the Orchestrator can connect to your IdP using any supported protocol -- OIDC, SAML, or LDAP. The Orchestrator's mode (OIDC Provider) determines what protocol your *application* speaks. The connector determines what protocol your *IdP* speaks. These are independent -- you can connect a SAML-only IdP and the Orchestrator will translate to OIDC for your application. See the [Identity Fabric overview](/reference/orchestrator/identity-fabric) for all connector types.
Next, register your application with the Orchestrator's [OIDC Provider](/reference/modes/oidc-provider). This tells the Orchestrator which application will receive OIDC tokens and how to handle the authentication flow.
You configure a client ID and secret for your application (separate from the IdP credentials above), the redirect URLs your application accepts after authentication, and which identity connector to use for authenticating users.
In the Console, you create the OIDC application and connect it to your identity provider in a single flow. The connector you select becomes the application's authentication source.
1. Navigate to **Applications** in the sidebar and click **Create**.
2. Select **OIDC-based**.
3. Fill in the application form:
| Field | Required | Description |
| ------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| Name | Yes | A friendly name for your application (e.g., `my-web-app`). |
| Client ID | Yes | The client identifier your application will use to authenticate with the Orchestrator. |
| Client Secret | Yes | Click **Add Client Secret** and enter a secret. Your application will use this to authenticate token requests. |
| Redirect URL | Yes | Click **Add Redirect URL** and enter the callback URL your application accepts after authentication (e.g., `https://your-app.example.com/callback`). |
The default grant types (**Authorization Code**, **Refresh Token**, and **Client Credentials**) work for most applications. Under **Access Token Settings**, the token type defaults to **JWT**.
4. Click **Save**.
5. On the application settings page, find the **Resources** card and click **Edit**. Click **Add Resource**, select the connector you created in the previous step, and click **Save**. A connector must be added as a resource before it can be selected as an authentication source.
6. Find the **Access Control** card and click **Edit**.
7. From the **Select an authentication source** dropdown, select your identity provider. To add more than one source, click **Add identity provider**.
8. Click **Save**.
Store application client secrets using the `` secret reference syntax rather than plaintext values. See [Secrets Management](/guides/security/secrets-management) for setup instructions.
Define the OIDC Provider and register your application in the `apps` section. The `authentication.idps` array binds the connector from the previous step to this application.
```yaml maverics.yaml theme={null}
oidcProvider:
discovery:
issuer: https://your-orchestrator.example.com
endpoints:
wellKnown: https://your-orchestrator.example.com/.well-known/openid-configuration
jwks: https://your-orchestrator.example.com/oauth2/jwks
auth: https://your-orchestrator.example.com/oauth2/auth
token: https://your-orchestrator.example.com/oauth2/token
userinfo: https://your-orchestrator.example.com/oauth2/userinfo
introspect: https://your-orchestrator.example.com/oauth2/introspect
jwks:
- algorithm: RSA256
publicKey:
privateKey:
apps:
- name: my-web-app
type: oidc
clientID: my-web-app
credentials:
secrets:
-
redirectURLs:
- https://your-app.example.com/callback
authentication:
idps:
- my-idp
accessToken:
type: jwt
```
The `authentication.idps` array references the connector name from the previous step (`my-idp`). When a user accesses your application, the Orchestrator redirects them to that IdP for authentication.
The `credentials.secrets` array uses secret references so your application's client secret is never stored in plaintext. The `accessToken.type` can be `jwt` (self-contained tokens) or `opaque` (reference tokens that require introspection).
Claims are pieces of identity information about the user -- their email address, display name, group memberships, roles, and any custom attributes your IdP provides. When the Orchestrator acts as an [OIDC Provider](/reference/modes/oidc-provider), it issues tokens to your application that contain these claims.
Claim mapping lets you control which identity attributes from your IdP end up in the tokens your application receives. You can rename claims (so your app sees `email` instead of `preferred_username`), filter out unnecessary data, or combine claims from multiple sources.
This is where the Orchestrator's protocol translation becomes powerful -- your IdP might use one claim format, but your application expects another. The Orchestrator handles the translation so neither side needs to change.
1. Open the application you created in the previous step.
2. Find the **Claims and OAuth 2.0 Scopes** card and click **Edit**.
3. Under **Attribute to Standard OIDC Claim Mapping**, add a claim mapping for each attribute your application needs:
| Field | Description |
| ------------- | ------------------------------------------------------------------------------------------ |
| Claim Name | The claim name that will appear in the issued token (e.g., `email`, `name`, `given_name`). |
| Claim Source | Select the identity provider connector to pull the attribute from. |
| Value Mapping | The attribute name from the identity provider (e.g., `preferred_username`, `name`). |
4. Click the **Claim** button to add additional rows for each claim you need to map.
For example, to pass the user's email, name, and family name, add three claim rows:
* `email` from your IdP's `preferred_username`
* `name` from your IdP's `name`
* `family_name` from your IdP's `family_name`
5. Click **Save**.
Add a `claimsMapping` section to your application definition. Each entry maps a claim name in the issued token (left side) to an attribute from your IdP connector (right side), using the format `connectorName.attributeName`.
```yaml maverics.yaml theme={null}
apps:
- name: my-web-app
type: oidc
clientID: my-web-app
credentials:
secrets:
-
redirectURLs:
- https://your-app.example.com/callback
authentication:
idps:
- my-idp
accessToken:
type: jwt
claimsMapping:
email: my-idp.preferred_username
name: my-idp.name
family_name: my-idp.family_name
given_name: my-idp.given_name
```
The `claimsMapping` keys (`email`, `name`, `family_name`, `given_name`) are the claim names that appear in the tokens your application receives. The values (`my-idp.preferred_username`, `my-idp.name`, etc.) reference attributes from the identity connector. The prefix before the dot must match the connector `name` from the previous step.
See [OIDC Provider Reference](/reference/modes/oidc-provider) for all available fields, including scopes, token lifetimes, and advanced claim configuration.
See the [OIDC Provider reference](/reference/modes/oidc-provider) for the complete list of configurable claims, scopes, and token settings.
After configuring your deployment, identity connector, application, and claim mapping in the Console, you need to publish the configuration so the Orchestrator receives it and applies your changes.
1. At the bottom of the deployment Settings page, click **Publish Preview** in the sticky footer bar.
2. In the Deployment Manager dialog, review the configuration diff to verify your changes.
3. Optionally add a revision note describing what changed (e.g., "Initial OIDC SSO setup").
4. Click **Publish** to deploy the configuration bundle to your storage provider.
5. The Orchestrator detects the new bundle on its next poll cycle and applies the configuration automatically.
See [Publishing Deployment Configs overview](/reference/console/config-publishing) for details on the publishing lifecycle, revision history, and bundle verification.
When using direct configuration, configuration is delivered directly to the Orchestrator via the `-config` flag or `MAVERICS_CONFIG` environment variable. No publishing step is needed -- restart the Orchestrator to apply configuration changes.
With your identity provider connected, your application defined, and claim mapping configured, you are ready to test the complete SSO flow.
Start (or restart) the Orchestrator to pick up your configuration and verify it is healthy:
```bash theme={null}
maverics -config /etc/maverics/config.yaml
curl -s https://localhost:9443/status | jq .
```
A healthy response confirms the Orchestrator is running:
```json theme={null}
{
"status": "up"
}
```
Now open your application's public URL in a browser and walk through the SSO flow:
1. **Visit your application URL** -- You should be redirected to your identity provider's login page
2. **Authenticate** -- Log in with valid credentials
3. **Verify redirect** -- After authentication, you should land on your application with full access
4. **Inspect tokens** -- If your application exposes token details, verify the claims match your mapping configuration
**Success!** Your Maverics Orchestrator is acting as an OIDC Provider --
authenticating users through your identity provider and issuing tokens with
the claims your application expects. Users experience seamless single
sign-on without your application needing to integrate directly with your IdP.
## Troubleshooting
This is the most common OIDC configuration issue. Your identity provider
rejects the authentication request because the redirect URI (callback URL)
the Orchestrator sends does not exactly match what is registered in your IdP.
Check both sides -- the URI configured in the Orchestrator and the URI
registered in your IdP's application settings must be character-for-character
identical, including the protocol (`https://`), domain, port, and path. Trailing
slashes matter.
If your application receives a token but cannot validate it, verify that the
audience (`aud`) claim in the token matches what your application expects.
The audience is set during claim mapping -- make sure it points to your
application's client ID or expected identifier. If claims are missing from
the token, check that the scopes requested during authentication include the
data you need (for example, `email` scope for email claims, `profile` scope
for name claims). See the [OIDC Provider reference](/reference/modes/oidc-provider)
for scope-to-claim mappings.
This usually indicates the Orchestrator successfully authenticated the user
but cannot reach the upstream application. Verify that the upstream URL in
your application route is correct and that the application is running and
accessible from the Orchestrator's network. Check the Orchestrator logs for
connection errors or timeouts.
## What's Next
Set up SAML 2.0 federation for legacy enterprise applications that do not support OIDC
Explore the complete OIDC Provider configuration -- scopes, claims, token lifetimes, and advanced settings
# Protect Your First Application
Source: https://docs.strata.io/guides/getting-started/first-application
This guide picks up where the Quick Start left off. You already have a running Orchestrator with SSO protecting a basic route. Now you will add session management, identity header injection, and production-ready configuration.
## Prerequisites
* **Completed the [Quick Start guide](/guides/getting-started/quick-start)** -- You should have a running Orchestrator with an identity provider connected and a working application route protected by SSO.
* **A configured identity provider connector** -- Your Orchestrator should already be connected to an identity provider (Microsoft Entra ID, Okta, or another supported IdP) from the Quick Start.
## Configure Your Application
You should already have a working application route from the Quick Start guide. The steps below add session management and header injection to that existing configuration.
Session management controls how the Orchestrator tracks authenticated users between requests. Without session management, users would need to re-authenticate on every page load -- which is not a practical experience.
The Orchestrator creates a session after a user successfully authenticates. This session stores the user's identity information (who they are, what claims they have) so that subsequent requests can be authorized without a full round-trip to the identity provider. Sessions can be stored in-memory for development or configured with [cookie-based sticky sessions](/reference/orchestrator/sessions/local) for production multi-node deployments (the load balancer uses the `maverics_session` cookie for affinity).
Session management is configured in the Deployment settings, not on an individual application.
1. Navigate to **Deployments** in the sidebar and select your deployment.
2. Under **Orchestrator Settings**, find the **Session and Cookie** section.
3. Click **Edit Session and Cookie** to open the settings dialog.
4. Configure session lifetime settings:
| Field | Default | Description |
| -------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| Max Lifetime Seconds | 86400 (24 hours) | The maximum number of seconds that can elapse post-authentication before a session's authentication state becomes invalidated. |
| Idle Timeout | 0 (disabled) | The number of seconds a session may remain idle before timing out. Set to `0` to disable idle timeout. |
| Cache Size | 50,000 | Limits the number of sessions maintained in memory. |
5. Optionally configure the **Cookie** settings:
| Field | Description |
| ------------------------------- | ---------------------------------------------------------------------------------------------------- |
| Domain | Specifies the hosts to which the session cookie will be sent (e.g., `example.com`). |
| Name | The name of your Maverics session cookie. |
| Disable HttpOnly Attribute | If enabled, the session cookie can be accessed via client-side scripts. Leave disabled for security. |
| Disable Secure Cookie Attribute | If enabled, the cookie can be sent over unencrypted HTTP. Leave disabled for security. |
6. Click **Save**.
The dialog also offers optional **Service Extension** dropdowns for evaluating session maximum lifetime and idle timeout programmatically. See the [Sessions reference](/reference/orchestrator/sessions) for details.
```yaml theme={null}
session:
cookie:
name: "maverics_session"
domain: "example.com"
lifetime:
maxTimeout: "12h"
idleTimeout: "30m"
store:
type: "local"
local:
capacity: 50000
```
The `cookie.domain` scopes the session cookie to your domain. The `lifetime` settings control how long sessions remain valid. The `store.type: "local"` uses in-memory storage suitable for both development and production. See the [Sessions Reference](/reference/orchestrator/sessions) for all session configuration options.
Header injection (also called identity propagation) is how the Orchestrator passes user identity information to your upstream application. After the Orchestrator authenticates a user, it adds HTTP headers to the proxied request -- telling your application who the user is without your application needing to handle authentication directly.
Common headers include the user's email address, display name, group memberships, and any custom claims from the identity provider. Your upstream application reads these headers to identify the user and make authorization decisions.
For example, the Orchestrator might inject:
* `X-Forwarded-User` -- The authenticated user's unique identifier
* `X-Forwarded-Email` -- The user's email address from the identity provider
* `X-Forwarded-Groups` -- A comma-separated list of the user's group memberships
Header injection is configured per-location within the application's access control policy.
1. Open your application's settings.
2. In the **Resources** card, click **Edit**, click **Add Resource**, and add your identity provider connector. A connector must be added as a resource before it can be used as an authentication source.
3. Find the **Access Control** card and click **Edit**, then click **Policy** to add a policy (or edit an existing one) in the **Edit Access Control** drawer.
4. Set the **Location** for the route you want to protect (e.g., `/`).
5. From the **Select an authentication source** dropdown, select the identity provider connector that will authenticate users for this location.
6. For **Authorization method**, choose **Allow all access**.
7. Under **Headers**, add the identity headers your application needs:
| Header Name | Identity Source | Attribute Mapping |
| -------------------- | ------------------ | ----------------- |
| `X-Forwarded-User` | Your IdP connector | `sub` |
| `X-Forwarded-Email` | Your IdP connector | `email` |
| `X-Forwarded-Groups` | Your IdP connector | `groups` |
Click **Header** to add each additional header.
8. Click **Save**.
You can also use the **Global Request Headers & Service Extensions** card on the application to add headers to all locations without repeating them in each access control policy.
Add the `headers` array to your existing app entry from the Quick Start:
```yaml theme={null}
# Add to your existing app entry from Quick Start
headers:
- name: "X-Forwarded-User"
value: "{{ azure.sub }}"
- name: "X-Forwarded-Email"
value: "{{ azure.email }}"
- name: "X-Forwarded-Groups"
value: "{{ azure.groups }}"
```
Headers are defined as an array of `{name, value}` objects. Values use the `{{ connector.claim }}` template syntax, where the connector name (e.g., `azure`) is the namespace and the claim name (e.g., `email`, `sub`, `groups`) comes from the identity provider.
Your complete app entry with headers should look like this:
```yaml theme={null}
apps:
- name: my-application
type: proxy
upstream: "https://internal-app.example.com"
routePatterns:
- "app.example.com"
headers:
- name: "X-Forwarded-User"
value: "{{ azure.sub }}"
- name: "X-Forwarded-Email"
value: "{{ azure.email }}"
- name: "X-Forwarded-Groups"
value: "{{ azure.groups }}"
policies:
- location: "/"
authentication:
idps: ["azure"]
authorization:
allowAll: true
```
Make sure your upstream application only trusts these headers when they come
from the Orchestrator. If users can reach your application directly (bypassing
the Orchestrator), they could forge these headers. Configure your application
to only accept traffic from the Orchestrator's IP address or network, or use
[mTLS](/guides/security/tls) between the Orchestrator and your upstream so
both sides verify each other's identity cryptographically.
With session management and header injection configured, restart the Orchestrator to pick up your updated configuration.
Now open your application's public URL in a browser and walk through the complete flow:
1. **Visit your application URL** -- You should be redirected to your identity provider's login page
2. **Authenticate** -- Log in with valid credentials
3. **Verify redirect** -- After authentication, you should land on your application with full access
4. **Verify session persistence** -- Close and reopen your browser, then revisit the application URL. Your session should persist without requiring re-authentication (within the configured timeout)
5. **Check headers** -- If your application has a debug or profile page, verify that the injected identity headers (`X-Forwarded-User`, `X-Forwarded-Email`, `X-Forwarded-Groups`) are present and contain the correct values
**Success!** Your application is fully protected by the Maverics Orchestrator.
Users authenticate through your identity provider, sessions are managed
automatically, and your application receives user identity through HTTP
headers -- all without modifying your application code.
## Troubleshooting
A 403 error after successful authentication usually means an authorization
policy is blocking the user. Check whether you have configured any access
policies that restrict which users can access the application. Also verify
that the user's claims from the identity provider include the required
attributes (such as group membership) that your policies expect.
Verify that header injection is configured for the correct application entry.
If your upstream application is behind a load balancer or reverse proxy, that
intermediate layer may be stripping non-standard headers. Check each hop in
the request path. You can use a tool like `curl -v` to inspect the headers
the Orchestrator sends to your upstream.
Session behavior is controlled by the session store configuration. Check the
session timeout value -- it may be set too low for your use case. If sessions
are not expiring, verify that the session store is correctly configured and
that the Orchestrator is reading from the same store it writes to (important
in multi-instance deployments). See the
[Sessions reference](/reference/orchestrator/sessions) for all
timeout and expiration options.
## What's Next
Explore SSO with OIDC, SAML federation, and identity provider migration
Learn how to deploy the Orchestrator for production workloads with high availability
# Overview
Source: https://docs.strata.io/guides/getting-started/overview
The Getting Started guides walk you through your first experience with the Maverics Orchestrator -- from installing it on your infrastructure to protecting a real application with single sign-on. Whether you are an IAM administrator setting up identity routing for the first time or a developer integrating authentication into your stack, these guides give you a hands-on path to a working deployment.
Before you begin, make sure you have [Console access and an organization set up](/introduction/getting-started).
Start with the Quick Start if you want to get up and running fast. Move to Protect Your First Application when you are ready to see a complete, production-style configuration with session management and identity propagation.
## Guides
Install the Orchestrator, connect an identity provider, and protect your first route in minutes
Build a complete deployment with SSO, session management, and header-based identity propagation
## Related Pages
Get access to the Console and set up your organization
Dive deeper into SSO, OIDC, SAML federation, and identity provider migration
# Quick Start
Source: https://docs.strata.io/guides/getting-started/quick-start
By the end of this guide, you will have a running Maverics Orchestrator connected to your identity provider with your first application route protected by single sign-on.
## Prerequisites
* **A supported operating system** -- The Orchestrator runs on Linux, macOS, Windows, and in containers. See the [installation reference](/reference/orchestrator/installation) for full system requirements.
* **An identity provider account** -- You need an account with an identity provider such as [Microsoft Entra ID](/reference/orchestrator/identity-fabric/azure-ad) or [Okta](/reference/orchestrator/identity-fabric/okta). This is the system your users log into today.
* **A target application** -- Any web application running on a URL you can reach from the machine where the Orchestrator will run.
## Install and Configure
The Maverics Orchestrator is a small, lightweight runtime that deploys almost anywhere -- on a virtual machine, in a container, or on bare metal. Installation takes just a few minutes.
The Orchestrator sits between your users and your applications, handling authentication and identity routing so your apps do not have to. Think of it as an identity abstraction layer -- it authenticates users against your identity provider and then forwards authenticated requests to your upstream applications.
1. Log in to the [Maverics Console](https://maverics.strata.io)
2. Navigate to **Deployments** and create a new Deployment
3. Select a configuration storage provider (e.g., **No Cloud Storage Service Configured** for a quick start, or an S3/Azure/GCS bucket for production)
4. Open the **Download Orchestrator Software** modal
5. Download the installer for your platform and follow the platform-specific installation steps
Download the Orchestrator binary from the [Maverics Console](https://maverics.strata.io). The Console provides platform-specific installers through the **Download Orchestrator Software** modal inside any Deployment.
After downloading and extracting the binary for your platform:
```bash theme={null}
# Verify the installation
maverics -version
```
For a quick look at the available installation methods -- including Docker, Kubernetes, and direct install -- see the [Installation reference](/reference/orchestrator/installation).
An identity provider (IdP) is the system that manages your user accounts and handles login -- services like Microsoft Entra ID (now called Microsoft Entra ID), Okta, or Google Workspace. Connecting the Orchestrator to your IdP tells it where to send users when they need to authenticate.
The Orchestrator uses [Identity Fabric](/reference/orchestrator/identity-fabric) connectors to communicate with your IdP. Each connector handles the protocol details -- OIDC, SAML, or LDAP -- so you just need to provide your provider's credentials and endpoint information.
1. Navigate to **Identity Fabric** in the sidebar.
2. Click **Create**.
3. In the **Create Identity Fabric** dialog, search for and select your identity provider (e.g., **Microsoft Entra ID (OIDC)**).
4. Fill in the connector fields:
| Field | Description |
| ----------------------- | -------------------------------------------------------------------------------------- |
| **Name** | A friendly name for this connector (e.g., `azure`). |
| **OIDC Well Known URL** | Your provider's OpenID Connect discovery endpoint. |
| **OAuth Client ID** | The client ID of the application registered in your identity provider. |
| **OAuth Client Secret** | The corresponding client secret. |
| **Redirect URLs** | The callback URL the Orchestrator will use (e.g., `https://app.example.com/callback`). |
5. Leave **PKCE** enabled (recommended) and configure optional fields like **Scopes** or **Logout Callback URLs** if needed.
6. Click **Save**.
The dialog supports a wide range of providers including Okta, Auth0, Ping, LDAP, Active Directory, and more. Pick the connector that matches your identity provider's protocol.
```yaml theme={null}
connectors:
- name: azure
type: azure
oauthClientID: "{{ env.AZURE_CLIENT_ID }}"
oauthClientSecret:
oidcWellKnownURL: "https://login.microsoftonline.com/{{ env.AZURE_TENANT_ID }}/v2.0/.well-known/openid-configuration"
oauthRedirectURL: "https://app.example.com/callback"
```
Replace the environment variable values with your Microsoft Entra ID tenant details. The `{{ env.VAR }}` syntax reads from environment variables. The `` syntax reads from your configured [secret provider](/reference/orchestrator/configuration/secret-providers).
Not sure which connector to use? The [Identity Fabric overview](/reference/orchestrator/identity-fabric) has a comparison table that maps each connector to its supported protocols and use cases.
An application route tells the Orchestrator which upstream application to protect and how to route traffic. When a user requests your application URL, the Orchestrator intercepts the request, authenticates the user against your IdP, and then forwards the authenticated request to your upstream service.
This step connects the identity connector you just configured to a specific application -- creating the link between "who the user is" and "what they can access."
1. Navigate to **Applications** in the sidebar.
2. Click **Create**.
3. In the **Create a new Application** dialog, select **Proxied App**.
4. Fill in the application fields:
| Field | Description |
| ---------------- | ------------------------------------------------------------------------------------------------------------- |
| **Name** | A friendly name for your application. |
| **Upstream URL** | The URL of the application the Orchestrator will proxy traffic to (e.g., `https://internal-app.example.com`). |
5. Click **Save**.
6. In the application's settings, open the **Resources** card, click **Edit**, then click **Add Resource** and add your identity provider connector. A connector must be added as a resource before it can be used as an authentication source.
7. Find the **Access Control** card and click **Edit**. Add a policy with **Location** `/`, select your connector from the **Select an authentication source** dropdown, and choose **Allow all access** for the **Authorization method**.
8. Click **Save**, then publish your configuration.
Route patterns, identity provider assignment, and authorization policies are configured on the application. The [Protect Your First Application](/guides/getting-started/first-application) guide covers this in more detail.
```yaml theme={null}
apps:
- name: my-application
type: proxy
upstream: "https://internal-app.example.com"
routePatterns:
- "app.example.com"
policies:
- location: "/"
authentication:
idps: ["azure"]
authorization:
allowAll: true
```
The `policies[].authentication.idps` array specifies which connectors handle authentication for this route. The `authorization.allowAll: true` allows any authenticated user.
With the Orchestrator installed, your identity provider connected, and your application route defined, you are ready to start the Orchestrator and confirm everything works.
Start the Orchestrator and check its health endpoint to verify it is running:
```bash theme={null}
maverics -config /etc/maverics/maverics.yaml
curl -s https://localhost:9443/status
```
The health endpoint returns a JSON response showing the status of the Orchestrator:
```json theme={null}
{
"status": "up"
}
```
Next, open your application URL in a browser. You should be redirected to your identity provider's login page. After authenticating, you will be redirected back to your application -- now with a valid session managed by the Orchestrator.
**Success!** Your Orchestrator is running and your first application route is
protected with single sign-on. Users authenticate through your identity
provider, and the Orchestrator manages the session lifecycle.
To add session management and identity header injection to this route, continue to the [Protect Your First Application](/guides/getting-started/first-application) guide.
## Troubleshooting
Check that the configuration file path is correct and that the file is valid
YAML. The Orchestrator logs the specific parsing error on startup -- look for
a line starting with `error` in the output. Common causes include indentation
issues, missing required fields, or referencing a connector name that does not
match the name in your connectors block.
Verify that your IdP credentials (client ID, client secret, tenant ID) are
correct and that the Orchestrator can reach your IdP's endpoints over the
network. If you are using environment variables for secrets, confirm they are
set in the shell where the Orchestrator is running. See the
[secret providers reference](/reference/orchestrator/configuration/secret-providers) for
alternative secret management options.
A redirect loop usually means the callback URL configured in your identity
provider does not match the Orchestrator's expected redirect URI. Double-check
both sides. A 502 error means the Orchestrator cannot reach your upstream
application -- verify the upstream URL is correct and the application is
running.
## What's Next
Add session management and header injection to your route
Dive deeper into OpenID Connect single sign-on configuration and claim mapping
# Overview
Source: https://docs.strata.io/guides/identity-continuity/overview
Identity Continuity ensures uninterrupted authentication by automatically routing users to a healthy identity provider when the primary becomes unavailable. Whether your cloud IdP has a regional failure, a network partition isolates your on-premises directory, or a provider pushes a breaking change, the Maverics Orchestrator detects the problem and switches traffic transparently -- no user action required.
These guides cover configuring Identity Continuity from initial setup through advanced multi-tier high availability architectures.
## Guides
Configure automatic IdP failover with health monitoring, Schema Abstraction Layer, and simulation testing
Layer Identity Continuity configurations across deployment tiers to eliminate IdP single points of failure
***
By the end of this guide, you will have a Maverics deployment that automatically fails over between identity providers when one becomes unavailable -- keeping your users authenticated without any service interruption.
**Console terminology:** In the Maverics Console, Continuity is configured as a
**Continuity Strategy** under **Identity Fabric**. In YAML, this maps to a connector
with `type: continuity`.
## Why Identity Continuity?
Unplanned identity provider outages can lock out every user in the organization. Whether your cloud IdP has a regional failure, a network partition isolates your on-premises directory, or a provider pushes a breaking change -- the result is the same: nobody can log in.
Identity Continuity is a **high availability prevention system**, not a backup or recovery tool. It does not restore service after an outage -- it reduces the risk of an outage affecting users. The Orchestrator continuously monitors each identity provider's health and reroutes traffic to a healthy alternative before users ever see a login failure.
Two primary use cases drive most Continuity deployments:
* **Cloud IdP fails over to on-premises directory** -- Your primary cloud IdP (e.g., Okta, Entra ID) becomes unavailable, and the Orchestrator routes authentication to an on-premises LDAP or AD connector.
* **Cloud IdP fails over to another cloud IdP** -- Your primary cloud IdP becomes unavailable, and the Orchestrator routes to a secondary cloud provider.
Identity Continuity keeps authentication working when a provider goes down. If you need to **permanently migrate users** from one identity provider to another, see the [IdP Migration guide](/guides/authentication/idp-migration) instead.
## Prerequisites
* **A running Maverics Orchestrator** -- If you have not installed the Orchestrator yet, follow the [Quick Start guide](/guides/getting-started/quick-start) or see the [installation reference](/reference/orchestrator/installation).
* **At least two identity provider connectors configured** -- You need a primary and one or more backup identity providers. See the [Identity Fabric reference](/reference/orchestrator/identity-fabric) for supported providers and connector setup.
* **User identities synced across identity providers** -- Your identity providers must already have the same user accounts provisioned. Failover to a backup IdP will fail if that IdP does not have the user's account. Typically this is handled by an Identity Governance and Administration (IGA) product or directory synchronization tool that keeps your identity stores in sync.
* **A deployment configured** -- Your Orchestrator needs an active deployment with a configured storage provider. See the [Publishing Deployment Configs overview](/reference/console/config-publishing) for setup details.
## Configure Identity Continuity
You need at least two identity services -- a primary that handles authentication under normal conditions and one or more backups that take over when the primary is unavailable. Each provider gets its own [Identity Fabric](/reference/orchestrator/identity-fabric) connector with independent credentials and configuration.
1. Navigate to **Identity Fabric** in the sidebar and click **Create**.
2. Select your primary provider type from the list (e.g., **Okta (OIDC)**, **Microsoft Entra ID (OIDC)**, or **Generic OIDC Configuration**).
3. Fill in the connector form with your primary IdP's credentials -- client ID, client secret, and discovery URL.
4. Click **Save**.
5. Repeat steps 1-4 for each backup identity provider.
Name your connectors clearly (e.g., `primary-okta` and `backup-entra-id`) to make the failover order obvious when configuring the Continuity Strategy.
Define both connectors in the `connectors` section. Each connector has its own credentials and discovery endpoint.
```yaml maverics.yaml theme={null}
connectors:
- name: primary-idp
type: oidc
oidcWellKnownURL: https://primary-idp.example.com/.well-known/openid-configuration
oauthClientID: orchestrator-client
oauthClientSecret:
oauthLoginRedirect:
urls:
- https://your-orchestrator.example.com/oidc-callback
oauthLogoutRedirect:
urls:
- https://your-orchestrator.example.com/logout
scopes: openid profile email
- name: backup-idp
type: oidc
oidcWellKnownURL: https://backup-idp.example.com/.well-known/openid-configuration
oauthClientID: orchestrator-backup-client
oauthClientSecret:
oauthLoginRedirect:
urls:
- https://your-orchestrator.example.com/oidc-callback
oauthLogoutRedirect:
urls:
- https://your-orchestrator.example.com/logout
scopes: openid profile email
```
Name your connectors descriptively (e.g., `primary-okta` and `backup-entra-id`) so the failover order is clear when configuring the Continuity connector.
The Orchestrator can maintain active connections to both providers simultaneously. Users authenticating against either provider will have a seamless experience.
Health monitoring must be enabled on each **individual IdP connector**, not on the Continuity connector itself. The Orchestrator polls each IdP's health endpoint at a configurable interval and uses the results to decide when to trigger failover.
1. Open each identity service you configured in the previous step.
2. Scroll to **Identity Service Health Monitoring** and enable it.
3. Configure the health check settings:
| Setting | Recommended (Testing) | Recommended (Production) | Description |
| ------------------ | --------------------- | ------------------------ | ------------------------------------------------------------------------ |
| Polling frequency | 10s | 30s-60s | How often the Orchestrator checks the IdP's health |
| Timeout | 10s | 10s | How long to wait for a health check response before marking it as failed |
| Failover threshold | 3 | 3 | Number of consecutive failures before triggering failover |
| Fallback threshold | 3 | 3 | Number of consecutive successes before routing traffic back |
4. Optionally enable **Custom Health Check** for more granular control over what constitutes a healthy response.
5. Click **Save**.
6. Repeat for each identity service in your Continuity configuration.
Add a `healthCheck` block to each connector that participates in the Continuity Strategy.
```yaml maverics.yaml theme={null}
connectors:
- name: primary-idp
type: oidc
oidcWellKnownURL: https://primary-idp.example.com/.well-known/openid-configuration
oauthClientID: orchestrator-client
oauthClientSecret:
healthCheck:
enabled: true
interval: 30s
timeout: 10s
unhealthyThreshold: 3
healthyThreshold: 3
```
Repeat the `healthCheck` configuration for each connector in the failover list.
For OIDC-based identity services, health checks automatically call the well-known endpoint and authorization server. For LDAP/AD services, health checks attempt a connection and bind.
The Continuity Strategy is the component that orchestrates failover between your identity providers. It wraps your IdP connectors and adds routing logic based on health status.
1. Navigate to **Identity Fabric** in the sidebar and click **Create**.
2. Select **Continuity Strategy** from the list.
3. Enter a name for the strategy (e.g., `ha-failover`).
4. In the **Fallback Strategy** section, add your identity providers in priority order -- primary first, then backups. The dropdown lists only identity services you have already configured.
Add a connector with `type: continuity` that references your IdP connectors in the `failover.idps` array. The first entry is the primary; subsequent entries are fallbacks tried in order.
```yaml maverics.yaml theme={null}
connectors:
- name: ha-failover
type: continuity
strategy: failover
failover:
idps:
- primary-idp
- backup-idp
```
See the [Continuity connector reference](/reference/orchestrator/identity-fabric/continuity) for all available configuration fields.
The Schema Abstraction Layer maps attributes from different IdPs to consistent names. When failover occurs, your applications receive the same attribute names regardless of which IdP authenticated the user.
For example, one IdP might call the email attribute `preferred_username` while another calls it `mail`. The Schema Abstraction Layer normalizes both to a single attribute name (e.g., `email`) that your applications can rely on.
1. In the Continuity Strategy configuration, scroll to the **Schema Abstraction Layer** section.
2. For each attribute your applications need (e.g., email, name, role), click to add a row.
3. Enter the normalized attribute **Name** (what your applications will see).
4. Map it to the corresponding claim name from each identity service.
5. Optionally set a **Default** value for cases where the attribute is unavailable from any IdP.
6. Click **Save**.
Add an `attributes` section to the Continuity connector. Each entry maps a normalized name to the corresponding attribute name from each IdP.
```yaml maverics.yaml theme={null}
connectors:
- name: ha-failover
type: continuity
strategy: failover
failover:
idps:
- primary-idp
- backup-idp
attributes:
- name: email
mapping:
primary-idp: preferred_username
backup-idp: mail
- name: displayName
mapping:
primary-idp: name
backup-idp: displayName
```
Update your application configuration to use the Continuity Strategy as its authentication provider instead of a specific IdP connector. This is the same binding pattern used in other authentication guides -- the only difference is that you reference the Continuity Strategy instead of an individual IdP.
1. Open your application's settings.
2. In the **Resources** card, click **Edit**, click **Add Resource**, and add your Continuity Strategy. A resource must be added before it can be selected as an authentication source.
3. In the **Access Control** card, select the Continuity Strategy from the **Select an authentication source** dropdown.
4. For headers or claims, update the source to the Continuity Strategy and select attributes from the Schema Abstraction Layer.
5. Click **Publish Preview** to review changes, then click **Publish** to deploy.
For all application types, the Continuity Strategy is selected from the **Select an authentication source** dropdown on the **Access Control** card. For proxy applications, add it within an access control policy.
Update the `authentication.idps` array in your application definition to reference the Continuity connector. Use the Schema Abstraction Layer attribute names in `claimsMapping`.
```yaml maverics.yaml theme={null}
apps:
- name: my-app
type: oidc
clientID: my-app
authentication:
idps:
- ha-failover
claimsMapping:
email: ha-failover.email
name: ha-failover.displayName
```
The `claimsMapping` references the Continuity connector's normalized attribute names -- not the individual IdP connectors. This ensures your application receives consistent claims regardless of which IdP authenticated the user.
The Orchestrator handles **protocol translation** automatically. Your application does not need to support the same protocol as your identity providers. For example, an OIDC application can authenticate users through a SAML or LDAP identity provider -- the Orchestrator translates between protocols transparently.
The Maverics Console includes a simulation feature that lets you test failover behavior without waiting for a real outage. When publishing changes, you can enable simulation to cycle through test phases automatically.
1. When publishing your configuration, toggle **Simulate Continuity Strategy**.
2. Set a time interval for the simulation cycle (e.g., 60 seconds per phase).
3. Click **Publish** to deploy with simulation enabled.
The simulation cycles through test phases automatically. During each phase, open an **incognito/private browser window**, navigate to your application URL, and verify the correct IdP login page appears.
Simulation mode is only available through the Console UI publish flow. When using direct configuration, you can test failover manually by stopping the primary IdP's service or blocking its health check endpoint, then verifying that authentication routes to the backup IdP.
The simulation runs through these phases:
1. **Test primary** -- Authenticate using your primary IdP credentials. Verify login works normally.
2. **Test failover to secondary** -- The primary appears unavailable. Open an incognito window, go to your app URL, and verify the login redirects to your secondary (backup) IdP.
3. **Test tertiary** (if configured) -- The secondary also appears unavailable. Verify failover to the third IdP.
4. **Test fallback** -- The secondary comes back online. Verify traffic routes back to the secondary.
5. **Test fallback to primary** -- The primary comes back online. Verify traffic routes back to the primary.
For each phase, use a fresh incognito window to avoid cached sessions interfering with the test.
Your Maverics Orchestrator is automatically routing authentication between your identity providers based on health status.
## Troubleshooting
Check the Orchestrator's debug logs for health check messages. Look for log entries like:
```
level=debug msg="idp health check failed: well-known metadata unavailable"
```
Common causes:
* The well-known endpoint or LDAP server is not reachable from the Orchestrator's network.
* The `unhealthyThreshold` has not been reached yet -- the Orchestrator requires the configured number of consecutive failures before triggering failover.
* Health monitoring is not enabled on the individual IdP connectors (health checks are configured on each connector, not on the Continuity connector itself).
Verify the Schema Abstraction Layer mappings cover all attributes your application needs. Each IdP may use different claim names for the same data (e.g., `email` vs `mail` vs `preferred_username`).
Check that `attributes[].mapping` entries exist for **every** IdP listed in the `failover.idps` array. If a mapping is missing for an IdP, the attribute will be empty when that IdP handles authentication.
Simulation mode is only available through the Console UI publish flow. Verify that you:
1. Toggled the **Simulate Continuity Strategy** switch before publishing.
2. Set a time interval for the simulation cycle.
3. Published the configuration after enabling simulation.
Check the Orchestrator logs for simulation-related messages. If you are using direct configuration (YAML), simulation mode is not available -- test failover manually by making the primary IdP's health check endpoint unreachable.
Verify that `healthyThreshold` is configured on the individual IdP connectors. The Orchestrator requires the configured number of consecutive healthy checks before routing traffic back to a recovered IdP.
Also check:
* The health check `interval` -- enough time must pass for the required number of healthy checks to accumulate.
* The recovered IdP's health check endpoint is actually responding successfully.
* The Orchestrator logs show health check success messages for the recovered IdP.
## Related Pages
Complete configuration reference for the Continuity connector -- failover, routing, and attribute normalization settings
Migrate between identity providers with zero downtime using the same Continuity connector
Supported identity providers and connector configuration for Microsoft Entra ID, Okta, Auth0, and more
Session management, invalidation, and storage options for the Orchestrator
# Reducing Single Points of Failure
Source: https://docs.strata.io/guides/identity-continuity/reducing-spofs
The most common question reliability architects ask about the Orchestrator is: **"Isn't it a single point of failure?"** The short answer is no -- the Orchestrator scales horizontally behind a load balancer (see the [Scale for Production guide](/guides/operations/scale)). If one instance goes down, the others continue serving traffic and users are transparently re-authenticated.
But scaling the Orchestrator itself only solves half the problem. Your **identity providers** can still be single points of failure. If your sole IdP goes down, it does not matter how many Orchestrator instances you have -- nobody can authenticate. [Identity Continuity](/reference/orchestrator/identity-fabric/continuity) is how you address that: the Orchestrator monitors IdP health and automatically fails over to a backup when an outage is detected.
This guide presents a tiered approach to Identity Continuity. Each tier adds resilience against progressively more severe failure scenarios. Choose the tier that matches your risk tolerance.
## Understanding Failure Modes
Before choosing a tier, understand what can go wrong:
| Failure mode | Example | Impact |
| ------------------------------ | ------------------------------------------------------ | ------------------------------------------------------------------------- |
| **Single IdP outage** | Unplanned incident, scheduled maintenance window | Users who authenticate through that IdP cannot log in |
| **Vendor-wide outage** | An entire IdP vendor's service is unavailable | Every application relying on that vendor is affected |
| **Regional network partition** | Orchestrator in US-East cannot reach IdPs in EU-West | Users at affected sites cannot authenticate, even if the IdPs are healthy |
| **Multi-provider outage** | Two or more IdP vendors are unavailable simultaneously | Rare but catastrophic -- all failover targets are unavailable |
## Tier 1: Basic Continuity
**Protects against:** Single IdP outage
The simplest configuration: one [Continuity connector](/reference/orchestrator/identity-fabric/continuity) with a primary IdP and one backup. If the primary goes down, the Orchestrator automatically routes authentication to the backup.
```yaml maverics.yaml theme={null}
connectors:
- name: primary-idp
type: oidc
oidcWellKnownURL: https://primary.example.com/.well-known/openid-configuration
oauthClientID: orchestrator-client
oauthClientSecret:
oauthRedirectURL: https://orch.example.com/oidc/callback
scopes: openid profile email
healthCheck:
enabled: true
interval: 30s
timeout: 10s
unhealthyThreshold: 3
healthyThreshold: 2
- name: backup-idp
type: oidc
oidcWellKnownURL: https://backup.example.com/.well-known/openid-configuration
oauthClientID: orchestrator-backup-client
oauthClientSecret:
oauthRedirectURL: https://orch.example.com/oidc/callback
scopes: openid profile email
healthCheck:
enabled: true
interval: 30s
timeout: 10s
unhealthyThreshold: 3
healthyThreshold: 2
- name: ha-failover
type: continuity
strategy: failover
failover:
idps:
- primary-idp
- backup-idp
```
**Limitation:** If both IdPs are from the same vendor or hosted in the same region, a vendor-wide or regional outage takes both down simultaneously. Tier 2 addresses this.
For a full walkthrough of setting up Continuity with health monitoring and the Schema Abstraction Layer, see the [Identity Continuity setup guide](/guides/identity-continuity/overview).
## Tier 2: Diversified Continuity
**Protects against:** Vendor-specific outage, regional outage
Tier 2 applies a single principle: **diversity**. Add three or more IdPs from different vendors, deployed in different regions, using different protocols. A vendor-wide outage or regional network partition only takes out one link in the chain.
```yaml maverics.yaml theme={null}
connectors:
# Cloud IdP - Vendor A (US region)
- name: okta-idp
type: oidc
oidcWellKnownURL: https://corp.okta.com/.well-known/openid-configuration
oauthClientID: orchestrator-client
oauthClientSecret:
oauthRedirectURL: https://orch.example.com/oidc/callback
scopes: openid profile email
healthCheck:
enabled: true
interval: 30s
timeout: 10s
unhealthyThreshold: 3
healthyThreshold: 2
# Cloud IdP - Vendor B (EU region)
- name: entra-idp
type: saml
samlMetadataURL: https://login.microsoftonline.com/TENANT/federationmetadata/2007-06/federationmetadata.xml
samlConsumerServiceURL: https://orch.example.com/saml/callback
samlEntityID: https://orch.example.com
healthCheck:
enabled: true
interval: 30s
timeout: 10s
unhealthyThreshold: 3
healthyThreshold: 2
# On-premises IdP - different network path entirely
- name: onprem-ldap
type: ldap
url: ldaps://dc.corp.example.com:636
baseDN: dc=corp,dc=example,dc=com
bindDN: cn=svc-maverics,ou=service-accounts,dc=corp,dc=example,dc=com
bindPassword:
healthCheck:
enabled: true
interval: 30s
timeout: 10s
unhealthyThreshold: 3
healthyThreshold: 2
- name: diversified-failover
type: continuity
strategy: failover
failover:
idps:
- okta-idp
- entra-idp
- onprem-ldap
# The Schema Abstraction Layer normalizes attributes across
# providers so downstream apps see consistent claim names
# regardless of which IdP authenticated the user.
attributes:
- name: email
mapping:
okta-idp: email
entra-idp: preferred_username
onprem-ldap: mail
- name: displayName
mapping:
okta-idp: name
entra-idp: displayName
onprem-ldap: cn
- name: role
mapping:
okta-idp: role
entra-idp: group
default: "user"
```
The key decisions in this tier:
* **Different vendors** -- Okta and Entra ID are independent services. A vendor-specific incident only affects one.
* **Different regions** -- Cloud IdPs in US and EU, plus an on-premises LDAP server. A regional network partition cannot take all three offline.
* **Different protocols** -- OIDC, SAML, and LDAP. A protocol-specific bug or misconfiguration is contained to one connector.
* **Schema Abstraction Layer** -- The `attributes` block normalizes claim names so your applications see `email`, `displayName`, and `role` regardless of which IdP responded. Without this, failover would break applications that depend on specific claim names.
Health monitoring is configured on each **individual IdP connector**, not on the Continuity connector. The Continuity connector reads health status from its member connectors to make routing decisions. See the [Identity Continuity reference](/reference/orchestrator/identity-fabric/continuity) for the full health check configuration.
## Tier 3: Cascading Continuity
**Protects against:** Regional isolation, near-total IdP infrastructure failure
Tier 3 introduces **Orchestrator-to-Orchestrator federation**. Instead of every Orchestrator instance connecting directly to every IdP, you create a two-layer architecture:
* **Root Orchestrators** in primary data centers connect directly to the actual IdPs via Continuity. They run as [OIDC Providers](/reference/modes/oidc-provider) or [SAML Providers](/reference/modes/saml-provider), acting as a stable identity endpoint.
* **Edge Orchestrators** in secondary regions or branch offices use [Generic OIDC](/reference/orchestrator/identity-fabric/custom-oidc) or [Generic SAML](/reference/orchestrator/identity-fabric/custom-saml) connectors pointed at the root Orchestrators. They use Continuity to fail over between multiple root Orchestrators.
```mermaid theme={null}
%%{init: {'theme': 'neutral', 'themeVariables': {'edgeWidth': 4}}}%%
flowchart TB
subgraph IdPs["Identity Providers"]
Okta["Okta (Vendor A)"]
Entra["Entra ID (Vendor B)"]
end
subgraph Roots["Root Orchestrators — Continuity failover across IdPs"]
RootDC1["Root Orch (DC1) OIDC Provider"]
RootDC2["Root Orch (DC2) OIDC Provider"]
RootN["Root Orch (N...) OIDC Provider"]
end
subgraph Edge["Edge Orchestrators — Continuity failover across roots"]
EdgeA["Edge Orch (Branch A)"]
EdgeB["Edge Orch (Branch B)"]
EdgeC["Edge Orch (Branch C)"]
end
Okta --> RootDC1
Okta --> RootDC2
Okta --> RootN
Entra --> RootDC1
Entra --> RootDC2
Entra --> RootN
RootDC1 --> EdgeA
RootDC1 --> EdgeB
RootDC1 --> EdgeC
RootDC2 --> EdgeA
RootDC2 --> EdgeB
RootDC2 --> EdgeC
RootN --> EdgeA
RootN --> EdgeB
RootN --> EdgeC
classDef orch stroke:#6A3EC8,stroke-width:6px
class RootDC1,RootDC2,RootN,EdgeA,EdgeB,EdgeC orch
```
Only root Orchestrators need direct IdP credentials and configurations. Edge sites treat the root Orchestrators as their identity providers. If an edge site loses connectivity to one root, it fails over to another. If all roots are unreachable (full regional isolation), only that edge site is affected -- other edge sites continue operating through whichever root they can reach.
### Root Orchestrator Configuration
Root Orchestrators connect directly to your IdPs via Continuity and expose an OIDC Provider endpoint that edge Orchestrators authenticate against.
```yaml root-orch.yaml theme={null}
connectors:
- name: okta-idp
type: oidc
oidcWellKnownURL: https://corp.okta.com/.well-known/openid-configuration
oauthClientID: orchestrator-client
oauthClientSecret:
oauthRedirectURL: https://root-dc1.example.com/oidc/callback
scopes: openid profile email
healthCheck:
enabled: true
interval: 30s
timeout: 10s
unhealthyThreshold: 3
healthyThreshold: 2
- name: entra-idp
type: saml
samlMetadataURL: https://login.microsoftonline.com/TENANT/federationmetadata/2007-06/federationmetadata.xml
samlConsumerServiceURL: https://root-dc1.example.com/saml/callback
samlEntityID: https://root-dc1.example.com
healthCheck:
enabled: true
interval: 30s
timeout: 10s
unhealthyThreshold: 3
healthyThreshold: 2
- name: root-failover
type: continuity
strategy: failover
failover:
idps:
- okta-idp
- entra-idp
attributes:
- name: email
mapping:
okta-idp: email
entra-idp: preferred_username
- name: displayName
mapping:
okta-idp: name
entra-idp: displayName
# Expose this Orchestrator as an OIDC Provider so edge
# Orchestrators can authenticate against it.
oidcProvider:
discovery:
issuer: https://root-dc1.example.com
jwks:
- name: signing-key
type: rsa
file: /etc/maverics/keys/signing.key
apps:
- name: edge-app
type: oidc
clientID: edge-orchestrator
clientSecret:
authentication:
idps:
- root-failover
claimsMapping:
email: root-failover.email
name: root-failover.displayName
```
### Edge Orchestrator Configuration
Edge Orchestrators treat root Orchestrators as IdPs using Generic OIDC connectors, with Continuity providing failover between roots.
```yaml edge-orch.yaml theme={null}
connectors:
# Root Orchestrator in DC1, treated as an OIDC IdP
- name: root-dc1
type: oidc
oidcWellKnownURL: https://root-dc1.example.com/.well-known/openid-configuration
oauthClientID: edge-orchestrator
oauthClientSecret:
oauthRedirectURL: https://edge-branch-a.example.com/oidc/callback
scopes: openid profile email
healthCheck:
enabled: true
interval: 30s
timeout: 10s
unhealthyThreshold: 3
healthyThreshold: 2
# Root Orchestrator in DC2, treated as an OIDC IdP
- name: root-dc2
type: oidc
oidcWellKnownURL: https://root-dc2.example.com/.well-known/openid-configuration
oauthClientID: edge-orchestrator
oauthClientSecret:
oauthRedirectURL: https://edge-branch-a.example.com/oidc/callback
scopes: openid profile email
healthCheck:
enabled: true
interval: 30s
timeout: 10s
unhealthyThreshold: 3
healthyThreshold: 2
- name: edge-failover
type: continuity
strategy: failover
failover:
idps:
- root-dc1
- root-dc2
# Edge Orchestrator serves local applications.
# Configure apps here using the edge-failover connector.
apps:
- name: branch-app
type: oidc
clientID: branch-app
authentication:
idps:
- edge-failover
claimsMapping:
email: edge-failover.email
name: edge-failover.name
```
Since root Orchestrators already normalize attributes via their Schema Abstraction Layer, edge Orchestrators receive consistent claims regardless of which root (or underlying IdP) handled authentication. You only need Schema Abstraction Layer mappings at the edge if the two root Orchestrators emit different claim names.
## Tier 4: Tactical Edge Continuity
**Protects against:** Total connectivity loss (DDIL -- Denied, Degraded, Intermittent, or Limited)
Tiers 1-3 assume that at least one upstream IdP is reachable at all times. Tactical and field deployments break that assumption. In DDIL environments -- forward-deployed operations, remote industrial sites, shipboard networks, or disaster-response staging areas -- connectivity to cloud identity providers can be intermittent or severed entirely.
Tier 4 addresses this with a **co-located on-premises IdP** (such as Keycloak) deployed alongside the tactical Orchestrator on the same local network segment. When cloud connectivity is available, the Orchestrator routes authentication to the cloud IdP normally. When connectivity is lost, the Orchestrator detects the failure and falls back to the local IdP autonomously -- no operator intervention required.
```mermaid theme={null}
%%{init: {'theme': 'neutral', 'themeVariables': {'edgeWidth': 4}}}%%
flowchart TB
subgraph Cloud["Cloud Identity Providers"]
Okta["Okta"]
Entra["Entra ID"]
end
subgraph Tactical["Tactical Deployment (Local Network)"]
TactOrch["Tactical Orchestrator"]
LocalIdP["Keycloak"]
end
Okta -. "intermittent connectivity" .-> TactOrch
Entra -. "intermittent connectivity" .-> TactOrch
LocalIdP -- "always available" --> TactOrch
classDef orch stroke:#6A3EC8,stroke-width:6px
classDef local stroke:#2E7D32,stroke-width:4px
class TactOrch orch
class LocalIdP local
```
```yaml tactical-orch.yaml theme={null}
connectors:
# Cloud IdP -- preferred when connectivity is available
- name: cloud-idp
type: oidc
oidcWellKnownURL: https://corp.okta.com/.well-known/openid-configuration
oauthClientID: tactical-client
oauthClientSecret:
oauthRedirectURL: https://tactical-orch.local/oidc/callback
scopes: openid profile email
healthCheck:
enabled: true
interval: 10s
timeout: 5s
unhealthyThreshold: 2
healthyThreshold: 3
# Co-located Keycloak -- always reachable on the local network
- name: local-keycloak
type: oidc
oidcWellKnownURL: https://keycloak.local/realms/tactical/.well-known/openid-configuration
oauthClientID: tactical-client
oauthClientSecret:
oauthRedirectURL: https://tactical-orch.local/oidc/callback
scopes: openid profile email
healthCheck:
enabled: true
interval: 10s
timeout: 5s
unhealthyThreshold: 2
healthyThreshold: 2
- name: tactical-failover
type: continuity
strategy: failover
failover:
idps:
- cloud-idp
- local-keycloak
# Schema Abstraction Layer ensures apps see consistent attributes whether the user
# authenticated against the cloud IdP or local Keycloak.
attributes:
- name: email
mapping:
cloud-idp: email
local-keycloak: email
- name: displayName
mapping:
cloud-idp: name
local-keycloak: preferred_username
- name: role
mapping:
cloud-idp: role
local-keycloak: realm_access.roles
default: "user"
```
Key design decisions for tactical deployments:
* **Aggressive health check intervals** -- The `interval: 10s` and `unhealthyThreshold: 2` configuration detects connectivity loss in as little as 20 seconds. Standard deployments use 30-second intervals and a threshold of 3 (90 seconds to detect). In DDIL environments, fast detection is critical because users cannot wait minutes for the system to recognize that the cloud is unreachable.
* **Co-located on the same network segment** -- The local IdP or directory must be reachable without traversing any WAN link. If the local IdP depends on the same network path as the cloud, it will fail at the same time.
* **Schema Abstraction Layer bridges the gap** -- Cloud IdPs and on-premises IdPs rarely use the same attribute names. The Schema Abstraction Layer ensures applications see `email`, `displayName`, and `role` regardless of whether Okta or local Keycloak responded.
* **Automatic recovery** -- When cloud connectivity restores, the Orchestrator's health checks detect the cloud IdP as healthy again and automatically route traffic back. No manual switchover is required.
## Choosing the Right Tier
| | Tier 1: Basic | Tier 2: Diversified | Tier 3: Cascading | Tier 4: Tactical Edge |
| ----------------------------- | --------------------------------- | --------------------------------------- | ----------------------------------------------- | --------------------------------------------- |
| **Protects against** | Single IdP outage | Vendor or regional outage | Regional isolation, near-total failure | Total connectivity loss (DDIL) |
| **Number of IdPs** | 2 | 3+ | 3+ (at root), 2+ roots (at edge) | 1+ cloud, 1+ local |
| **Vendor diversity** | Optional | Required | Required at root layer | Required (cloud + on-prem) |
| **IdP credentials needed at** | Every Orchestrator | Every Orchestrator | Root Orchestrators only | Tactical Orchestrator (both cloud and local) |
| **Configuration complexity** | Low | Medium | High | Medium-High |
| **Best for** | Most organizations, internal apps | Regulated workloads, SLA-bound services | Global deployments, zero-tolerance environments | Tactical/field deployments, DDIL environments |
**Start simple.** Most organizations begin at Tier 1 -- a primary IdP with a single backup handles the vast majority of outage scenarios. Move to Tier 2 when you need protection against vendor-wide incidents or have compliance requirements for vendor diversity. Tier 3 is for global deployments where regional isolation is a realistic threat and downtime tolerance is near zero. Tier 4 is purpose-built for tactical and field deployments where cloud connectivity cannot be guaranteed -- DDIL environments, disconnected operations, and forward-deployed sites.
## Custom Health Checks and Manual Failover
The default health check polls each IdP automatically, but you are not limited to automatic detection. [Custom health check endpoints](/reference/orchestrator/identity-fabric/continuity#custom-health-check-fields) let you point the Orchestrator at any URL and define what a healthy response looks like -- specific status codes, expected response body values, or custom headers.
This opens up scenarios beyond automatic IdP monitoring:
* **Manual failover** -- Stand up a simple internal endpoint (e.g., `/idp-status`) that your operations team controls. Flipping that endpoint to return a non-healthy status forces the Orchestrator to fail over immediately, without waiting for the IdP to actually go down. Useful for planned maintenance windows or preemptive action.
* **External monitoring signals** -- Wire the custom endpoint to your existing monitoring infrastructure (SIEM, network monitoring, threat detection). If your SOC detects that an IdP has been compromised or a network path is degraded, the monitoring system can flip the health endpoint and trigger failover before users are impacted.
* **Composite health** -- Build a health endpoint that aggregates multiple signals -- network latency, certificate expiry, IdP vendor status pages -- into a single healthy/unhealthy decision. The Orchestrator doesn't need to understand each signal; it just needs a status code.
```yaml maverics.yaml theme={null}
connectors:
- name: primary-idp
type: oidc
oidcWellKnownURL: https://corp.okta.com/.well-known/openid-configuration
oauthClientID: orchestrator-client
oauthClientSecret:
healthCheck:
enabled: true
interval: 10s
timeout: 5s
unhealthyThreshold: 2
healthyThreshold: 3
customEndpoint:
type: http
endpoint: https://internal-monitoring.example.com/idp-status/okta
responseMatcher:
expectedStatuses: [200]
body:
contains: "healthy"
```
With this configuration, the Orchestrator checks `https://internal-monitoring.example.com/idp-status/okta` instead of the IdP's well-known endpoint. If that endpoint returns anything other than a `200` with `"healthy"` in the body, failover begins.
## Supporting Infrastructure
Identity Continuity handles the authentication layer, but a production HA deployment also depends on infrastructure outside the Orchestrator:
* **Global load balancers or GeoDNS** -- Route users to the nearest healthy Orchestrator instances. Required for Tier 3 to direct edge traffic to the closest root.
* **Health check integration** -- Your load balancer should poll each Orchestrator's `/status` endpoint and remove unhealthy instances from the pool. See the [Scale for Production guide](/guides/operations/scale) for load balancer configuration examples.
* **Network path diversity** -- If all your IdP connections traverse the same network link, a single link failure defeats the purpose of multiple IdPs. Ensure root Orchestrators have diverse network paths to their upstream IdPs.
* **Monitoring and alerting** -- Configure alerts on Continuity failover events so your team knows when a backup IdP is actively handling traffic. See the [Monitor and Observe guide](/guides/operations/monitor) for telemetry configuration.
## Related Pages
Step-by-step guide to configuring your first Continuity connector with health monitoring
Full configuration reference for the Continuity connector, health checks, and Schema Abstraction Layer
Scale horizontally with sticky sessions, local session storage, and load balancer configuration
Deploy with CLI flags, Docker or systemd, secret provider configuration, and health probes
# Deploy to Production
Source: https://docs.strata.io/guides/operations/deploy
By the end of this guide, you will have a production-ready Maverics Orchestrator deployment with environment-specific configuration, health monitoring, and automated restarts.
This guide focuses on production deployment -- not installation. If you have not yet installed the Orchestrator, start with the [installation reference](/reference/orchestrator/installation) for system requirements and platform options. This guide picks up where installation leaves off, covering the production-specific concerns that matter when real users depend on your deployment.
**Console terminology:** In the Maverics Console, Orchestrator instances and
configuration delivery are managed through **Deployments**. When working directly
with YAML, configuration is managed as files delivered via the `-config` flag or
`MAVERICS_CONFIG` environment variable.
## Prerequisites
* **The Orchestrator installed** -- See the [installation reference](/reference/orchestrator/installation) for system requirements and installation methods.
* **A working configuration file** -- You should have a YAML configuration that works in development. See the [configuration reference](/reference/orchestrator/configuration) for config file structure.
* **A target environment** -- Docker, Kubernetes, a Linux/macOS host, or a Windows server where the Orchestrator will run.
## Deploy to Production
Production configuration differs from development in a few important ways. In development, you might hardcode secrets and use default ports. In production, you want secrets managed externally, environment-specific values injected at runtime, and explicit resource boundaries.
The Orchestrator supports environment variable substitution in YAML configuration -- so you can keep a single config file and vary behavior per environment. For secrets like IdP client credentials and TLS certificates, use an external [secret provider](/reference/orchestrator/configuration/secret-providers) instead of putting values directly in your config file.
Key production configuration concerns:
* **Secrets** -- Use a [secret provider](/reference/orchestrator/configuration/secret-providers) (HashiCorp Vault, AWS Secrets Manager, Azure Key Vault) instead of plaintext values
* **External config sources** -- Pull configuration from a [config source](/reference/orchestrator/configuration/config-sources) for centralized management across multiple Orchestrator instances
* **TLS** -- Enable TLS termination at the Orchestrator or ensure your load balancer handles it. See the [Transport Layer Security (TLS) Reference](/reference/orchestrator/tls-security)
* **Logging** -- Set log level to `info` or `warn` for production (not `debug`). See the [Monitor guide](/guides/operations/monitor) for full observability setup
**Console UI documentation is coming soon.** This section will walk you
through configuring this component using the Maverics Console's visual
interface, including step-by-step screenshots and field descriptions.
A minimal production `maverics.yaml` uses environment variable substitution for environment-specific values and secret references for sensitive data:
```yaml maverics.yaml theme={null}
version: "1"
http:
address: "{{ env.MAVERICS_HTTP_ADDRESS }}"
tls: "default"
tls:
"default":
certFile: "{{ env.TLS_CERT_PATH }}"
keyFile: "{{ env.TLS_KEY_PATH }}"
minVersion: "1.2"
logger:
level: "info"
jsonOutput: true
health:
location: "/status"
heartbeat:
interval: "60s"
connectors:
- name: my-idp
type: oidc
oauthClientID: "{{ env.OIDC_CLIENT_ID }}"
oauthClientSecret:
oidcWellKnownURL: "{{ env.OIDC_WELL_KNOWN_URL }}"
apps:
- name: my-app
type: proxy
upstream: "{{ env.APP_UPSTREAM_URL }}"
routePatterns:
- "{{ env.APP_ROUTE_PATTERN }}"
policies:
- location: "/"
authentication:
idps: ["my-idp"]
```
Use `{{ env.VAR }}` for values that change between environments (addresses, URLs, non-sensitive IDs). Use `` for secrets that should be retrieved from a secret provider at runtime.
See [Configuration Reference](/reference/orchestrator/configuration) for complete config file structure.
Keep your production configuration in version control -- but use environment variable references for anything sensitive. This way your config file is auditable without exposing secrets.
Secret providers are configured via the `MAVERICS_SECRET_PROVIDER` environment variable or the `-secretProvider` CLI flag -- not in YAML. Only one secret provider may be active at a time.
**Console UI documentation is coming soon.** This section will walk you
through configuring this component using the Maverics Console's visual
interface, including step-by-step screenshots and field descriptions.
Secret providers are configured via environment variable or CLI flag, not in YAML configuration. The examples below show shell commands for setting up each provider type.
```bash theme={null}
# HashiCorp Vault
export MAVERICS_SECRET_PROVIDER="hashivault://vault.example.com:8200/secret/data/maverics?token="
# AWS Secrets Manager
export MAVERICS_SECRET_PROVIDER="awssecretsmanager://us-east-1"
# Azure Key Vault
export MAVERICS_SECRET_PROVIDER="azurekeyvault://my-vault.vault.azure.net"
# Secret File (development only)
export MAVERICS_SECRET_PROVIDER="secretfile:////etc/maverics/secrets.json"
```
Once configured, reference secrets in YAML using angle bracket syntax:
```yaml theme={null}
oauthClientSecret:
```
See [Secret Providers Reference](/reference/orchestrator/configuration/secret-providers) for all 7 provider types and their URL schemes.
The Orchestrator is small and lightweight -- it deploys almost anywhere. Choose the deployment model that matches your infrastructure.
**Docker deployment** is the simplest path to production. Mount your configuration file and any TLS certificates, expose the Orchestrator's listening port, and set environment variables for secrets.
**Kubernetes deployment** is ideal for teams already running workloads on Kubernetes. The Orchestrator runs as a Deployment with a Service, and you configure it through ConfigMaps (for YAML configuration) and Secrets (for credentials). Kubernetes also gives you built-in health check integration, rolling updates, and automatic restarts. Strata provides an [official Helm chart](https://github.com/strata-io/helm-charts) for streamlined Kubernetes installation.
**Windows deployment** is supported via the MSI installer, which registers the Orchestrator as a Windows service with automatic startup. The installer provides a guided setup for configuration source, TLS certificates, and environment variables.
**Console UI documentation is coming soon.** This section will walk you
through configuring this component using the Maverics Console's visual
interface, including step-by-step screenshots and field descriptions.
**CLI invocation** -- The Orchestrator accepts the following flags:
```bash theme={null}
maverics \
-config /etc/maverics/maverics.yaml \
-secretProvider "hashivault://vault.example.com:8200/secret/data/maverics?token="
```
Available CLI flags:
| Flag | Description |
| ----------------- | ----------------------------------------------------------------------- |
| `-config` | Path to YAML configuration file (required) |
| `-secretProvider` | Secret provider URL (alternative to `MAVERICS_SECRET_PROVIDER` env var) |
| `-version` | Print version and exit |
| `-verbose` | Enable debug-level logging |
**Docker deployment:**
```bash theme={null}
docker run -d \
--name maverics \
-p 9443:9443 \
-v /etc/maverics/maverics.yaml:/etc/maverics/maverics.yaml:ro \
-v /etc/maverics/certs:/etc/maverics/certs:ro \
-e MAVERICS_SECRET_PROVIDER="hashivault://vault.example.com:8200/secret/data/maverics?token=" \
-e MAVERICS_HTTP_ADDRESS="0.0.0.0:9443" \
maverics-orchestrator \
-config /etc/maverics/maverics.yaml
```
**systemd deployment:**
```ini theme={null}
# /etc/systemd/system/maverics.service
[Unit]
Description=Maverics Orchestrator
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/local/bin/maverics -config /etc/maverics/maverics.yaml
EnvironmentFile=/etc/maverics/env
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
```
```bash theme={null}
# /etc/maverics/env
MAVERICS_SECRET_PROVIDER=hashivault://vault.example.com:8200/secret/data/maverics?token=
MAVERICS_HTTP_ADDRESS=0.0.0.0:9443
TLS_CERT_PATH=/etc/maverics/certs/server.pem
TLS_KEY_PATH=/etc/maverics/certs/server-key.pem
```
Whichever deployment model you choose, the Orchestrator behaves the same way. The only differences are how you deliver the configuration file and how you manage the process lifecycle (restarts, scaling, health checks).
The Orchestrator exposes a health endpoint that reports its operational status -- whether it has started successfully and is ready to handle traffic. In production, you should configure your infrastructure to poll this endpoint and take action when the Orchestrator is unhealthy.
The status endpoint returns a JSON response indicating the Orchestrator's operational state. Your load balancer, container orchestrator, or process manager can use this endpoint to:
* **Route traffic only to healthy instances** -- Remove unhealthy instances from the load balancer pool
* **Restart failed instances** -- Kubernetes liveness probes and Docker restart policies use health checks to detect and recover from failures automatically
* **Block traffic during startup** -- Readiness probes prevent traffic from reaching an instance before it has finished initializing
```bash theme={null}
# Check the status endpoint
curl -s https://localhost:9443/status | jq .
```
```json theme={null}
{
"status": "up"
}
```
**Console UI documentation is coming soon.** This section will walk you
through configuring this component using the Maverics Console's visual
interface, including step-by-step screenshots and field descriptions.
Configure the health endpoint path and heartbeat monitoring:
```yaml maverics.yaml theme={null}
health:
location: "/status"
heartbeat:
disabled: false
logLevel: "info"
interval: "60s"
```
**Kubernetes probes** using the health endpoint:
```yaml theme={null}
# Kubernetes deployment snippet
livenessProbe:
httpGet:
path: /status
port: 9443
scheme: HTTPS
initialDelaySeconds: 10
periodSeconds: 15
readinessProbe:
httpGet:
path: /status
port: 9443
scheme: HTTPS
initialDelaySeconds: 5
periodSeconds: 10
```
**Docker health check:**
```bash theme={null}
docker run -d \
--health-cmd="curl -kf https://localhost:9443/status || exit 1" \
--health-interval=15s \
--health-timeout=5s \
--health-retries=3 \
# ... rest of docker run command
```
With the Orchestrator deployed and health checks configured, verify that everything is working end-to-end. Start by confirming the health endpoint returns a healthy status, then test the full authentication flow.
```bash theme={null}
# Verify status
curl -s https://your-orchestrator-host:9443/status | jq .
# Check that the Orchestrator is serving traffic
curl -I https://your-orchestrator-host:9443/
```
Walk through the full user flow to confirm end-to-end functionality:
1. **Visit a protected URL** -- You should be redirected to your identity provider
2. **Authenticate** -- Log in with valid credentials
3. **Verify redirect** -- After authentication, you should land on your protected application
4. **Check logs** -- Confirm the Orchestrator logged the authentication event
**Success!** Your Orchestrator is deployed in production with environment-specific
configuration, health monitoring, and automated restarts. The health endpoint
reports a healthy status, and the full authentication flow works end-to-end.
## Troubleshooting
Check the Orchestrator's startup logs for the specific error. The most common
causes are:
* **Invalid YAML** -- Indentation errors, missing colons, or unclosed quotes.
Run your config through a YAML validator.
* **Missing required fields** -- The Orchestrator validates its configuration on
startup and logs which fields are missing.
* **Port conflict** -- Another process is already using the configured listening
port. Check with `lsof -i :8080` or change the port in your configuration.
* **Permission denied** -- The Orchestrator process does not have permission to
read the config file, TLS certificates, or bind to the configured port.
If you are using an external [config source](/reference/orchestrator/configuration/config-sources),
verify that:
* The config source credentials are correct and the Orchestrator can reach the
external service over the network
* The config source path or key matches what the Orchestrator expects
* Environment variables referenced in the configuration are set in the
Orchestrator's runtime environment (not just your local shell)
Enable `debug` logging temporarily to see the exact config source requests and
responses.
An unhealthy status usually means one or more connectors failed to initialize.
Check the Orchestrator's logs for startup errors.
If the health endpoint times out entirely, the Orchestrator may not be listening
on the expected port. Verify the port configuration and check that no firewall
rules are blocking access to the health endpoint.
## Related Pages
Back to the Operations guides hub
Full reference for configuration file structure, environment variables, and runtime settings
Scale your deployment horizontally with sticky sessions and Redis caching
# Monitor and Observe
Source: https://docs.strata.io/guides/operations/monitor
By the end of this guide, you will have a fully instrumented Maverics Orchestrator with OpenTelemetry-based metrics and traces, structured log output, and health check monitoring for key operational events.
Good observability means you know what your Orchestrator is doing before users tell you something is wrong. The Orchestrator exports metrics and traces via OpenTelemetry (OTLP), emits structured logs, and provides health endpoints -- giving you the raw data you need to build dashboards, set up alerts, and debug issues when they arise.
**Console terminology:** In the Maverics Console, Orchestrator instances and
configuration delivery are managed through **Deployments**. When working directly
with YAML, configuration is managed as files delivered via the `-config` flag or
`MAVERICS_CONFIG` environment variable.
## Prerequisites
* **A running Maverics Orchestrator** -- If you have not deployed yet, follow the [Deploy to Production guide](/guides/operations/deploy) first.
* **An OpenTelemetry collector** -- The Orchestrator exports telemetry via OTLP. You need an OpenTelemetry Collector (or compatible endpoint like Grafana Alloy, Datadog Agent, or New Relic) to receive metrics and traces.
* **A log aggregation system** (recommended) -- Elasticsearch, Loki, Splunk, or any system that can ingest structured JSON logs.
## Set Up Observability
The Orchestrator uses OpenTelemetry to export metrics and traces via the OTLP protocol. Metrics are collected through periodic readers that push to your OTLP endpoint at a configured interval. Traces are exported through simple processors.
The Orchestrator can export telemetry data including:
* **Request metrics** -- Total requests, response status codes, and request duration histograms
* **Authentication metrics** -- Authentication event data (availability varies by Orchestrator version)
* **Runtime metrics** -- Process-level metrics such as memory and concurrency data
* **Distributed traces** -- End-to-end request tracing through authentication and authorization flows
The specific metrics and trace data available depend on your Orchestrator version and configuration. Consult your Orchestrator's actual OTLP output to confirm which metrics are exported in your deployment.
**Console UI documentation is coming soon.** This section will walk you
through configuring this component using the Maverics Console's visual
interface, including step-by-step screenshots and field descriptions.
Configure OTLP exporters for both metrics and traces:
```yaml maverics.yaml theme={null}
telemetry:
metrics:
readers:
- periodic:
exporter:
otlp:
protocol: "http/protobuf"
endpoint: "http://otelcol.example.com:4318/v1/metrics"
insecure: true
timeout: 5000
interval: 5000
traces:
processors:
- simple:
exporter:
otlp:
protocol: "http/protobuf"
endpoint: "http://otelcol.example.com:4318/v1/traces"
```
| Field | Description |
| --------------------------------------------------- | -------------------------------------------------- |
| `metrics.readers[].periodic.exporter.otlp.protocol` | OTLP transport -- use `"http/protobuf"` |
| `metrics.readers[].periodic.exporter.otlp.endpoint` | Your OTLP collector's metrics endpoint |
| `metrics.readers[].periodic.exporter.otlp.insecure` | Skip TLS verification for the collector connection |
| `metrics.readers[].periodic.exporter.otlp.timeout` | Export timeout in milliseconds |
| `metrics.readers[].periodic.interval` | Collection interval in milliseconds |
| `traces.processors[].simple.exporter.otlp.protocol` | OTLP transport for traces |
| `traces.processors[].simple.exporter.otlp.endpoint` | Your OTLP collector's traces endpoint |
The OTLP exporter supports additional production options including TLS certificates, gzip compression, custom headers, and aggregation temporality preferences. For traces, a batch processor is available for high-volume environments. See [Telemetry Reference](/reference/orchestrator/telemetry) for the complete field reference.
See [Telemetry Reference](/reference/orchestrator/telemetry) for all telemetry fields.
If you manage Orchestrator configuration through the Maverics Console, advanced telemetry settings like batch processing, TLS, compression, and custom headers require the [**config override**](/reference/console/config-publishing#override-config) feature. Config override requires enablement for your organization -- contact your Strata account team or [Strata support](https://strataidentity.my.site.com/support/s/) to enable it.
The Orchestrator exports all telemetry via OTLP. If you use Prometheus, configure your OpenTelemetry Collector to receive OTLP and export to Prometheus using the `prometheusremotewrite` exporter.
The Orchestrator emits structured logs in JSON format -- making them easy to parse, search, and aggregate in any log management system. Structured logs include consistent fields like timestamp, log level, request ID, and component name, so you can filter and correlate events across your deployment.
Production logging best practices:
* **Log level** -- Use `info` for normal production operation. Switch to `debug` only when actively troubleshooting -- debug logging is verbose and can impact performance.
* **Output format** -- JSON format (`jsonOutput: true`) is recommended for production. It integrates cleanly with log aggregation systems like Elasticsearch, Loki, and Splunk.
* **Output destination** -- Stdout is the standard approach for containerized deployments (Docker and Kubernetes capture stdout automatically). For bare-metal deployments, you can configure file-based output with rotation.
* **Request ID correlation** -- Each request gets a unique ID that appears in every log entry for that request. Use this to trace a single user's authentication flow across log entries.
**Console UI documentation is coming soon.** This section will walk you
through configuring this component using the Maverics Console's visual
interface, including step-by-step screenshots and field descriptions.
Configure the logger for production:
```yaml maverics.yaml theme={null}
logger:
level: "info"
jsonOutput: true
timeFormat: "RFC3339Nano"
logSessionID: false
fieldOrdering:
enabled: true
```
| Field | Default | Description |
| ------------------------------ | --------------- | ------------------------------------------------------- |
| `logger.level` | `"info"` | Log verbosity: `"debug"`, `"info"`, `"warn"`, `"error"` |
| `logger.jsonOutput` | `false` | Output logs in JSON format for structured logging |
| `logger.timeFormat` | `"RFC3339Nano"` | Time format string for log timestamps |
| `logger.logSessionID` | `false` | Include the session ID in log entries for correlation |
| `logger.fieldOrdering.enabled` | `false` | Order log fields consistently across entries |
The `-verbose` CLI flag or `MAVERICS_DEBUG_MODE=true` environment variable overrides `logger.level` to `"debug"` at startup.
You can also configure HTTP access logging separately:
```yaml maverics.yaml theme={null}
http:
accessLog:
disabled: false
level: "info"
```
The Orchestrator exposes a configurable health endpoint that load balancers and orchestration platforms use to verify operational status. The health endpoint returns a JSON response, and a periodic heartbeat logs system metrics.
**Console UI documentation is coming soon.** This section will walk you
through configuring this component using the Maverics Console's visual
interface, including step-by-step screenshots and field descriptions.
Configure the health endpoint and heartbeat:
```yaml maverics.yaml theme={null}
health:
location: "/status"
heartbeat:
disabled: false
logLevel: "info"
interval: "60s"
```
| Field | Default | Description |
| --------------------------- | ----------- | --------------------------------------- |
| `health.location` | `"/status"` | HTTP path for the health check endpoint |
| `health.heartbeat.disabled` | `false` | Disable periodic heartbeat logging |
| `health.heartbeat.logLevel` | `"info"` | Heartbeat log level |
| `health.heartbeat.interval` | `"60s"` | Heartbeat interval (duration string) |
Verify the health endpoint:
```bash theme={null}
curl -s https://localhost:9443/status | jq .
```
```json theme={null}
{
"status": "up"
}
```
The periodic heartbeat log entry includes: `orchestrator_version`, `config_version`, `cpu_count`, `cpu_usage`, `total_memory`, `memory_usage`, and `active_goroutines`.
Every log entry (including heartbeat entries) includes a [`soid`](/introduction/glossary#soid-secure-orchestrator-id) field for identifying and correlating logs by Orchestrator instance. See [Logging — Deployment Correlation](/reference/orchestrator/telemetry/logging#deployment-correlation) for details.
Metrics and logs are useful for investigation, but alerts are what tell you something needs attention right now. Configure alerts for the conditions that indicate real problems -- not just noise.
Recommended alerts for a production Orchestrator deployment:
* **High error rate** -- Alert when the 5xx error rate exceeds a threshold (for example, more than 1% of requests returning 500-series errors over a 5-minute window). This catches upstream failures, misconfigurations, and application errors.
* **Authentication failure spike** -- Alert when authentication failures increase significantly above the baseline. A sudden spike could indicate an IdP outage, expired credentials, or a misconfigured connector.
* **Health check failure** -- Alert when the health endpoint reports an unhealthy status for more than 2 consecutive checks. This catches connector failures and startup issues.
* **High latency** -- Alert when the p95 request latency exceeds your SLA threshold. High latency often indicates network issues, slow upstream services, or resource contention.
**Console UI documentation is coming soon.** This section will walk you
through configuring this component using the Maverics Console's visual
interface, including step-by-step screenshots and field descriptions.
Alerting is configured in your monitoring platform (Prometheus, Grafana, Datadog, etc.), not in the Orchestrator YAML. The Orchestrator exports the metrics that your alerting rules evaluate.
**Example Prometheus alert rules** for an Orchestrator deployment:
```yaml theme={null}
# prometheus-alerts.yaml
groups:
- name: maverics
rules:
- alert: MavericsHealthCheckFailed
expr: up{job="maverics"} == 0
for: 2m
labels:
severity: critical
annotations:
summary: "Orchestrator instance is down"
- alert: MavericsHighErrorRate
expr: rate(http_server_requests_total{status=~"5.."}[5m]) > 0.01
for: 5m
labels:
severity: warning
annotations:
summary: "Orchestrator error rate above 1%"
```
**Prometheus scrape configuration** for the Orchestrator's OTLP metrics (after your OpenTelemetry Collector translates to Prometheus format):
```yaml theme={null}
# prometheus.yaml scrape config
scrape_configs:
- job_name: "maverics"
scrape_interval: 15s
static_configs:
- targets: ["otelcol.example.com:8889"]
```
Start with a small number of high-signal alerts and add more as you learn your deployment's baseline behavior. Too many alerts leads to alert fatigue -- where important signals get lost in the noise.
With telemetry, logging, and alerting configured, verify that data is flowing correctly through your entire observability pipeline.
```bash theme={null}
# Verify status endpoint
curl -s https://your-orchestrator-host:9443/status | jq .
```
Walk through a complete verification:
1. **Check your OTLP collector** -- Confirm the collector is receiving metrics and traces from the Orchestrator
2. **Check dashboards** -- If you have Grafana dashboards, verify that charts are rendering with real data
3. **Check logs** -- Trigger a few requests and confirm the structured log entries appear in your log aggregation system with the correct JSON format and fields
4. **Test an alert** -- If possible, trigger one of your alert conditions (for example, temporarily set a very low threshold) and confirm the alert fires and notifications are delivered
**Success!** Your Orchestrator deployment is fully instrumented. Metrics and
traces are being exported via OTLP, structured logs are flowing to your
aggregation system, and alerts are configured for key operational events.
## Troubleshooting
Verify that the OTLP endpoint URL in your `telemetry` configuration is correct
and reachable from the Orchestrator. Check that the collector is running and
listening on the expected port. If the collector uses TLS, set `insecure: false`
and ensure the Orchestrator can verify the collector's certificate. Check
firewall rules and network policies between the Orchestrator and collector.
If your log aggregation system is not parsing the Orchestrator's logs correctly,
check that you are using a JSON parser (not a regex-based parser for plain text
logs). The Orchestrator outputs JSON-formatted logs when `jsonOutput: true` is
set.
If you see raw JSON strings instead of parsed fields, your log shipper (Filebeat,
Fluentd, Vector) may need a JSON parsing filter configured. Check the log
shipper's documentation for JSON input configuration.
If alerts are not firing when expected, check these common causes:
* **Threshold too high** -- Your alert threshold may be higher than the actual
metric values. Check the raw metric values in your monitoring platform to set realistic thresholds.
* **Wrong metric name** -- Verify the exact metric name matches what
your alert rule references. Metric names are case-sensitive.
* **Evaluation interval** -- Alert rules only evaluate at configured intervals. If
your evaluation interval is 5 minutes, the alert will not fire until the next
evaluation window after the condition is met.
* **Notification channel** -- The alert rule may be firing but the notification
is not reaching you. Check your alerting tool's notification configuration
(email, Slack, PagerDuty).
## Related Pages
Back to the Operations guides hub
Complete configuration reference for logger, telemetry, access logs, and health check settings
Set up your production deployment before configuring monitoring
# Overview
Source: https://docs.strata.io/guides/operations/overview
The Operations guides cover the full lifecycle of running the Maverics Orchestrator in production. The Orchestrator is small and lightweight -- it deploys almost anywhere, whether that is a Docker container, a Kubernetes cluster, or a bare-metal server. Once running, it provides a health endpoint, OpenTelemetry-based metrics and traces, and structured JSON logging so you always know what is happening.
These guides take you from a working development setup to a production deployment -- covering how to deploy safely, monitor effectively, scale horizontally, and troubleshoot when things do not go as expected. Each guide stands on its own, so you can jump directly to the topic you need.
## Guides
Deploy with CLI flags, Docker or systemd, secret provider configuration, health probes, and environment-specific YAML
Configure OpenTelemetry metrics and traces via OTLP export, structured JSON logging, and Prometheus alerting rules
Scale horizontally with sticky sessions, local session storage, and mode-appropriate Redis caching
Diagnose and resolve common startup failures, authentication errors, configuration problems, and connectivity issues
## Related Pages
Full reference for installation methods, system requirements, and platform support
Complete configuration reference for metrics, logging, and health check settings
TLS configuration, certificate management, and security hardening for production deployments
New to Maverics? Start here for installation, first configuration, and your first protected application
Set up automatic IdP failover and cascading high availability to eliminate identity provider single points of failure
# Scale for Production
Source: https://docs.strata.io/guides/operations/scale
By the end of this guide, you will have a horizontally scaled Maverics deployment with multiple Orchestrator instances, sticky sessions, local session storage, and mode-appropriate Redis caching.
A single Orchestrator instance can handle a significant amount of traffic -- the Orchestrator is small, lightweight, and efficient. But production workloads often require multiple instances for high availability (if one instance goes down, the others continue serving traffic) and for handling peak loads that exceed a single instance's capacity. Scaling the Orchestrator horizontally requires sticky sessions (cookie-based session affinity) on your load balancer so that each user's requests consistently reach the same Orchestrator instance, plus Redis caching when your mode requires cross-instance data sharing.
**Console terminology:** In the Maverics Console, Orchestrator instances and
configuration delivery are managed through **Deployments**. When working directly
with YAML, configuration is managed as files delivered via the `-config` flag or
`MAVERICS_CONFIG` environment variable.
## Prerequisites
* **A running Orchestrator deployment** -- If you have not deployed to production yet, follow the [Deploy to Production guide](/guides/operations/deploy) first.
* **A load balancer that supports cookie-based session affinity (sticky sessions)** -- Any HTTP load balancer that supports health check-based routing and cookie-based affinity (NGINX Plus, HAProxy, AWS ALB, F5 BIG-IP, GCP Load Balancer, etc.).
* **A Redis instance** -- Required for OIDC Provider mode; recommended for SAML Provider mode; not needed for other modes. See the [Redis Cache reference](/reference/orchestrator/caches/redis) for setup.
## Scale Your Deployment
Sessions are stored locally on each Orchestrator instance. Sticky sessions (session affinity) ensure that each user's requests consistently reach the same instance, so the Orchestrator can find the user's session on every request.
Configure your load balancer to use **cookie-based affinity** targeting the `maverics_session` cookie (or your custom `session.cookie.name` value). Cookie-based affinity is more reliable than IP-based affinity because it works correctly when multiple users share the same IP address (e.g., behind a corporate NAT) or when a user's IP changes mid-session (e.g., switching networks on a mobile device).
**Console UI documentation is coming soon.** This section will walk you
through configuring this component using the Maverics Console's visual
interface, including step-by-step screenshots and field descriptions.
Configure local session storage on each Orchestrator instance. The load balancer handles routing -- the Orchestrator configuration is the same as a single-node deployment:
```yaml maverics.yaml theme={null}
session:
cookie:
name: "maverics_session"
domain: ".example.com"
lifetime:
maxTimeout: "12h"
idleTimeout: "30m"
store:
type: "local"
local:
capacity: 50000
```
See [Sessions Reference](/reference/orchestrator/sessions) for all session configuration fields.
If an Orchestrator node goes down, sessions on that node are lost. Users are transparently re-authenticated via their upstream IdP session -- they experience a brief redirect but are not prompted to log in again.
Redis is a **cache** for connector tokens and provider data -- not a session store. In multi-node deployments, Redis ensures that provider-specific data (authorization codes, SAML request data, connector tokens) is accessible from any Orchestrator instance, even though each user's requests are routed to the same instance via sticky sessions.
The need for Redis depends on which Orchestrator mode you are using:
* **OIDC Provider:** Redis cache is **required** for multi-node deployments. The OIDC Provider stores authorization codes, token state, and provider data in the cache. Without Redis, an authorization code issued by one instance cannot be redeemed by another -- and even with sticky sessions, the token endpoint request may arrive from the application server rather than the user's browser, bypassing session affinity.
* **SAML Provider:** Redis cache is **recommended**. The SAML Provider caches SAML request data (AuthnRequest and LogoutRequest form parameters) so that after a user authenticates upstream, any Orchestrator instance can restore the original request context and generate the SAML response. Without Redis, if the authentication callback arrives at a different instance than the one that received the original AuthnRequest, the SAML response flow will fail because the request data is only in local memory.
* **HTTP Proxy:** Redis cache is **not needed**. Each instance manages its own connector tokens independently.
* **LDAP Provider:** A shared cache is **not typically needed** for standalone LDAP Provider deployments -- the LDAP Provider uses per-connection bind state. However, in **facade (sandwich) deployments** where HTTP Proxy and LDAP Provider run as separate Orchestrator instances, a shared cache **is required** so that one-time credentials generated by the proxy can be validated by the LDAP Provider. When both modes run on a single Orchestrator, the local cache is sufficient. See [LDAP Provider -- Pairing with HTTP Proxy](/reference/modes/ldap-provider#pairing-with-http-proxy) and the [Caches reference](/reference/orchestrator/caches).
* **AI Identity Gateway:** A cache is **not typically needed**. AI Identity Gateway uses token-based state tied to the upstream OAuth authorization server.
**Console UI documentation is coming soon.** This section will walk you
through configuring this component using the Maverics Console's visual
interface, including step-by-step screenshots and field descriptions.
Define a Redis cache and reference it from your provider configuration:
```yaml maverics.yaml theme={null}
caches:
- name: "my-redis"
type: "redis"
redis:
addresses:
- "redis.example.com:6379"
password:
tls: "redis-tls"
# Reference the cache from your provider:
oidcProvider:
cache: "my-redis"
# ... other oidcProvider config
samlProvider:
cache: "my-redis"
# ... other samlProvider config
```
See [Redis Cache Reference](/reference/orchestrator/caches/redis) for all Redis cache fields including encryption and hashing options.
A load balancer distributes incoming requests across your Orchestrator instances. Configure it to use health check-based routing so that traffic only goes to healthy instances, and cookie-based sticky sessions so that each user's requests reach the same instance.
Key load balancer configuration:
* **Health check endpoint** -- Point the load balancer's health check at the Orchestrator's `/status` endpoint. Remove instances from the pool when they return an unhealthy status.
* **Sticky sessions** -- Configure cookie-based session affinity using the `maverics_session` cookie (or your custom `session.cookie.name` value). This ensures each user's requests consistently reach the same Orchestrator instance.
* **Connection draining** -- When an instance is removed from the pool (during a rolling update or failure), allow existing connections to complete before terminating the instance. This prevents request failures during deployments.
* **TLS termination** -- Decide whether TLS terminates at the load balancer or at the Orchestrator. Terminating at the load balancer is simpler to manage when running multiple instances.
Load balancers are external to the Orchestrator -- they are configured in your infrastructure layer, not in `maverics.yaml`. Select your load balancer below for configuration examples:
```nginx theme={null}
upstream maverics {
server 10.0.1.10:9443;
server 10.0.1.11:9443;
server 10.0.1.12:9443;
# Use the Orchestrator's session cookie for affinity.
# If you customized session.cookie.name, use that value instead.
sticky cookie maverics_session;
}
server {
listen 443 ssl;
server_name app.example.com;
location / {
proxy_pass https://maverics;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
location /status {
proxy_pass https://maverics/status;
}
}
```
```haproxy theme={null}
frontend maverics_fe
bind *:443 ssl crt /etc/haproxy/certs/app.pem
default_backend maverics_be
backend maverics_be
cookie maverics_session insert indirect nocache
server orch1 10.0.1.10:9443 ssl check cookie orch1
server orch2 10.0.1.11:9443 ssl check cookie orch2
server orch3 10.0.1.12:9443 ssl check cookie orch3
option httpchk GET /status
```
HAProxy's `cookie` directive in the backend inserts a cookie to track which server handles each session. The `insert indirect nocache` options tell HAProxy to manage the affinity cookie transparently.
Enable application cookie-based stickiness on the ALB target group:
```bash theme={null}
aws elbv2 modify-target-group-attributes \
--target-group-arn arn:aws:elasticloadbalancing:REGION:ACCOUNT:targetgroup/maverics/XXXXX \
--attributes \
Key=stickiness.enabled,Value=true \
Key=stickiness.type,Value=app_cookie \
Key=stickiness.app_cookie.cookie_name,Value=maverics_session \
Key=stickiness.app_cookie.duration_seconds,Value=86400
```
In the AWS Console: navigate to **EC2 > Target Groups > your target group > Attributes > Stickiness**, enable stickiness, select **Application-based cookie**, and set the cookie name to `maverics_session`.
Use an iRule or a persistence profile with cookie-based persistence targeting the `maverics_session` cookie. Consult your load balancer's documentation for cookie-based affinity configuration.
Enable cookie-based affinity on the backend settings. Azure Application Gateway uses its own affinity cookie by default, but can be configured for application-managed affinity. Consult the Azure documentation for cookie-based affinity configuration.
Use a backend service with `GENERATED_COOKIE` or `HTTP_COOKIE` session affinity and specify the `maverics_session` cookie name. Consult the GCP documentation for cookie-based affinity configuration.
Use the sticky sessions configuration in the load balancer service definition with a cookie name of `maverics_session`. Consult the Traefik documentation for sticky session configuration.
Always use **cookie-based affinity** rather than IP-based affinity. Cookie-based affinity works correctly when users share IPs (corporate NAT) or change networks mid-session (mobile devices). Each user's requests will consistently reach the same Orchestrator instance based on their session cookie.
With multiple instances behind a load balancer and sticky sessions configured, verify that your deployment is truly highly available by testing failover.
```bash theme={null}
# Verify all instances are healthy via the load balancer
curl -s https://your-load-balancer:9443/status | jq .
# Authenticate through the load balancer and verify your session works
# Make several requests to confirm sticky sessions are routing correctly
```
Test a failover scenario:
1. **Authenticate through the load balancer** -- Establish a session
2. **Stop one Orchestrator instance** -- Simulate a failure
3. **Make another request** -- If the stopped instance was handling your session, the load balancer routes you to a healthy instance. The Orchestrator redirects you to your upstream IdP, which recognizes your existing IdP session and completes authentication silently -- you experience a brief redirect but are not prompted to log in again.
4. **Restart the stopped instance** -- It should rejoin the pool automatically once the health check passes
**Success!** Your Orchestrator deployment is horizontally scaled with high
availability. Each instance stores sessions locally, the load balancer uses
cookie-based sticky sessions to route users consistently, and failover
triggers transparent re-authentication via the upstream IdP.
## Troubleshooting
If users are being asked to re-authenticate unexpectedly, sticky sessions
may be misconfigured:
* Verify the load balancer has cookie-based session affinity configured on the session cookie (`maverics_session` by default, or your custom `session.cookie.name` value).
* Verify all instances use `store.type: "local"`.
* Check load balancer logs to confirm requests from the same user consistently reach the same instance.
* If using IP-based affinity instead of cookie-based, switch to cookie-based affinity. IP-based affinity breaks when multiple users share the same IP (corporate NAT) or when a user's IP changes mid-session.
If a new or restarted Orchestrator instance is not receiving traffic, check
that:
* The instance's health endpoint is returning a healthy status
* The load balancer's health check is configured to poll the correct port and
path
* The health check interval and threshold are set appropriately -- some load
balancers require multiple consecutive healthy responses before adding an
instance to the pool
* Network rules allow the load balancer to reach the instance on both the
application port and the health check port
## Related Pages
Back to the Operations guides hub
Scale the two-tier AI Identity Gateway architecture with MCP-specific load balancing and token exchange tuning
Set up your production deployment before scaling horizontally
Session store types and session configuration
Redis cache configuration for connector tokens and provider data
# Troubleshoot Common Issues
Source: https://docs.strata.io/guides/operations/troubleshoot
By the end of this guide, you will have a systematic approach to diagnosing Maverics Orchestrator issues -- with clear steps for identifying root causes and resolving the most common problems.
Troubleshooting is easier when you have a systematic approach. This guide organizes the most common Orchestrator issues by category -- startup, authentication, configuration, and connectivity -- so you can quickly find the problem that matches your symptoms and follow the resolution steps. Each section covers the likely causes, diagnostic commands, and fixes.
**Console terminology:** In the Maverics Console, Orchestrator instances and
configuration delivery are managed through **Deployments**. When working directly
with YAML, configuration is managed as files delivered via the `-config` flag or
`MAVERICS_CONFIG` environment variable.
Before diving into a specific issue, check the Orchestrator's logs first. The
Orchestrator emits structured JSON logs that include error details, request IDs,
and component names. Most issues are diagnosable from the log output alone. See
the [Monitor and Observe guide](/guides/operations/monitor) for log configuration.
## Startup Issues
These issues prevent the Orchestrator from starting or completing its initialization.
The Orchestrator validates its configuration on startup and exits with an error
if anything is invalid. Check the error output for the specific cause.
**Common causes:**
* **Invalid YAML syntax** -- Indentation errors, missing colons, unclosed quotes,
or tabs instead of spaces. Run your config file through a YAML validator to
catch syntax errors.
* **Missing required fields** -- The Orchestrator logs which required fields are
missing. Check the [configuration reference](/reference/orchestrator/configuration)
for the minimum required configuration.
* **Permission denied** -- The Orchestrator process does not have permission to
read the config file, bind to the configured port, or access TLS certificates.
Check file permissions and ensure the process runs with appropriate privileges.
**Diagnostic steps:**
```bash theme={null}
# Check the Orchestrator's error output
maverics -config /etc/maverics/config.yaml 2>&1 | head -20
# Validate YAML syntax
python3 -c "import yaml; yaml.safe_load(open('/etc/maverics/config.yaml'))"
# Check file permissions
ls -la /etc/maverics/config.yaml
```
The Orchestrator cannot locate the configuration file at the specified path.
**Common causes:**
* **Wrong path** -- The `-config` flag points to a path that does not exist.
Double-check the path, including case sensitivity on Linux.
* **Mount not available** -- In Docker or Kubernetes, the volume mount may not be
configured correctly. Verify the mount path inside the container matches the
config flag.
* **Environment variable not set** -- If you use an environment variable for the
config path, confirm it is set in the Orchestrator's runtime environment.
**Diagnostic steps:**
```bash theme={null}
# Check if the file exists at the expected path
ls -la /etc/maverics/config.yaml
# In Docker, check the mount
docker inspect | jq '.[0].Mounts'
# In Kubernetes, check the ConfigMap mount
kubectl exec -- ls -la /etc/maverics/
```
The Orchestrator cannot bind to its configured listening port because another
process is already using it.
**Common causes:**
* **Previous instance still running** -- A previous Orchestrator process did not
shut down cleanly. Find and stop it before starting a new one.
* **Another service** -- A different application is using the same port.
* **Port below 1024** -- Ports below 1024 require root privileges on most systems.
**Diagnostic steps:**
```bash theme={null}
# Find what is using the port (Linux/macOS)
lsof -i :8080
# Kill the previous process if needed
kill
# Or change the port in your configuration
```
## Authentication Issues
These issues affect user login flows, token validation, and SSO behavior.
When users visit a protected URL, they should be redirected to the identity
provider's login page. If the redirect is not happening, the issue is usually
in the application route or connector configuration.
**Common causes:**
* **Route not matched** -- The request URL does not match any configured
application route. Check that the route's URL pattern matches the URL the
user is visiting.
* **Connector not assigned** -- The application route does not have an identity
connector assigned, so the Orchestrator does not know where to redirect for
authentication.
* **Connector misconfigured** -- The identity connector's authorization endpoint
URL is wrong or unreachable.
**Diagnostic steps:**
* Check the Orchestrator's logs for the incoming request -- the log entry shows
which route (if any) matched and whether a connector was invoked
* Verify the redirect URL in the browser's developer tools (Network tab) to see
if the Orchestrator is issuing a redirect at all
* Test the IdP's authorization endpoint directly with `curl` to confirm it is
reachable
The user authenticates successfully, but the upstream application rejects
the request or shows an unauthorized error.
**Common causes:**
* **Missing headers** -- The Orchestrator is not injecting the identity headers
that the upstream application expects. Check your header injection
configuration.
* **Wrong header format** -- The upstream application expects headers in a
specific format (for example, a Bearer token in the Authorization header) but
the Orchestrator is sending a different format.
* **Clock skew** -- Token validation failures can occur when the Orchestrator's
clock and the upstream application's clock are out of sync. Ensure both systems
use NTP.
**Diagnostic steps:**
* Use `curl -v` to inspect the exact headers the Orchestrator sends to the
upstream
* Check the upstream application's logs for the specific rejection reason
* Compare the expected header format with what the Orchestrator sends
The user gets stuck in an infinite loop between the Orchestrator and the
identity provider -- redirecting back and forth without ever landing on the
application.
**Common causes:**
* **Callback URL mismatch** -- The callback URL registered in the identity
provider does not match the Orchestrator's expected redirect URI. Both sides
must match exactly (including protocol, host, port, and path).
* **Session not persisting** -- The session cookie is not being set or read
correctly. Check cookie domain and path settings, and ensure the browser is
not blocking third-party cookies.
* **Application behind the Orchestrator redirecting again** -- The upstream
application has its own authentication that triggers another redirect.
Disable the upstream app's authentication since the Orchestrator handles it.
**Diagnostic steps:**
* Open the browser's developer tools and watch the Network tab to see the
exact redirect sequence
* Check that the callback URL in your IdP configuration matches the
Orchestrator's redirect URI exactly
* Look for `Set-Cookie` headers in the Orchestrator's responses to confirm
the session cookie is being set
## Configuration Issues
These issues affect how the Orchestrator reads and applies its configuration.
You updated the configuration file but the Orchestrator's behavior has not
changed.
**Common causes:**
* **Orchestrator not restarted** -- The Orchestrator reads its configuration at
startup. Changes to the config file require a restart to take effect.
* **Wrong config file** -- You may have edited a different config file than the
one the Orchestrator is using. Check the `-config` flag or environment
variable to confirm the path.
* **Listen address change** -- Changes to `http.address` (or LDAP listen
address) are not applied by a config reload. A change to the listening
address requires a full process restart (not just a reload), because the
listening socket is inherited from process startup and cannot be re-bound
in place.
* **Cached config** -- If using an external [config source](/reference/orchestrator/configuration/config-sources),
the config may be cached. Check the config source's cache TTL and refresh
settings.
**Diagnostic steps:**
```bash theme={null}
# Check which config file the Orchestrator is using
ps aux | grep maverics
# Restart the Orchestrator to pick up changes
systemctl restart maverics
# or in Docker
docker restart
```
You used an environment variable reference in your configuration file but the
Orchestrator is using the literal string instead of the variable's value.
**Common causes:**
* **Variable not set** -- The environment variable is not set in the
Orchestrator's runtime environment. Variables set in your local shell are not
automatically available to services started by systemd, Docker, or Kubernetes.
* **Wrong syntax** -- The Orchestrator uses `{{ env.VAR_NAME }}` syntax (double
curly braces with spaces) for environment variable references in YAML. See the
[configuration reference](/reference/orchestrator/configuration) for details.
* **Variable set after startup** -- Environment variables are read at process
startup. If you set a variable after the Orchestrator started, restart it.
**Diagnostic steps:**
```bash theme={null}
# Check if the variable is set in the Orchestrator's environment
# For systemd
systemctl show maverics -p Environment
# For Docker
docker inspect | jq '.[0].Config.Env'
# For Kubernetes
kubectl exec -- env | grep YOUR_VAR
```
A secret referenced in the configuration is not loading from the external
[secret provider](/reference/orchestrator/configuration/secret-providers).
**Common causes:**
* **Authentication failure** -- The Orchestrator cannot authenticate to the
secret provider. Check the secret provider's credentials and IAM permissions.
* **Wrong secret path** -- The secret path or key does not match what exists in
the secret provider. Paths are case-sensitive and must match exactly. In YAML,
secrets are referenced with `` syntax (angle brackets).
* **Network access** -- The Orchestrator cannot reach the secret provider's
endpoint. Check network policies, firewall rules, and DNS resolution.
**Diagnostic steps:**
* Enable `debug` logging to see the exact secret provider requests and responses
* Test the secret provider connection independently using its CLI tool (for
example, `vault read secret/data/maverics` for HashiCorp Vault)
* Verify IAM roles and policies grant read access to the specific secret path
The Orchestrator performs a config reload when `MAVERICS_RELOAD_CONFIG=true`
is set and the config changes. If reloads appear to have no effect, the
likely cause is one of three missing requirements -- each with a distinct
symptom and log signal.
**Common causes:**
| Requirement | Symptom | Log signal |
| --------------------------------------------- | ------------------------------------------------------------------------- | ------------------------------------- |
| `MAVERICS_RELOAD_CONFIG=true` env var not set | Config changes silently ignored; pod restart required to apply | *(no log -- reload never starts)* |
| Writable temp directory not mounted | Reload is a silent no-op; old config keeps serving | `failed to create handoff listener` |
| Stable `/etc/machine-id` not projected | Reload applies new config, but in-flight state (sessions, caches) is lost | `failed to connect to handoff socket` |
**Diagnostic steps:**
```bash theme={null}
# Kubernetes: check logs for the two error strings
kubectl logs | grep -E "failed to create handoff listener|failed to connect to handoff socket"
# Docker: same check
docker logs 2>&1 | grep -E "failed to create handoff listener|failed to connect to handoff socket"
# Confirm the env var is set
kubectl exec -- env | grep MAVERICS_RELOAD
```
If `failed to create handoff listener` appears: add a writable `emptyDir`
mount and set `TMPDIR` to point to it.
If `failed to connect to handoff socket` appears: project a stable
`/etc/machine-id` via the Downward API.
**Fix:** See the
[Kubernetes](/reference/orchestrator/installation/kubernetes#in-place-config-reload)
and [Docker](/reference/orchestrator/installation/docker#in-place-config-reload)
installation pages for the complete configuration.
On macOS, `os.TempDir()` returns a long path under `/var/folders/.../T/`
(typically 50-70 characters). The handoff socket path
(`/maverics-handoff-.sock`) can exceed macOS's 104-byte Unix
socket path limit, causing socket creation to fail.
**Symptom:** Config reload is enabled but changes are not applied. The logs
contain `failed to create handoff listener`.
**Diagnostic:**
```bash theme={null}
# Check the current TMPDIR length
echo -n "$TMPDIR/maverics-handoff-12345.sock" | wc -c
# If this exceeds 104, the socket will fail to create
```
**Fix:** Set `TMPDIR=/tmp` to use a shorter path:
```bash theme={null}
TMPDIR=/tmp ./maverics -config /path/to/config.yaml
```
For persistent background operation via launchd, set `TMPDIR=/tmp` in the
`EnvironmentVariables` key of your launch daemon plist.
## Connectivity Issues
These issues affect the Orchestrator's ability to communicate with external services.
The Orchestrator returns a 502 Bad Gateway error because it cannot connect to
the upstream application.
**Common causes:**
* **Upstream not running** -- The upstream application is down or not listening
on the expected port.
* **Wrong upstream URL** -- The upstream URL in the route configuration is
incorrect (wrong host, port, or protocol).
* **Network isolation** -- Firewall rules, security groups, or Kubernetes
NetworkPolicies are blocking traffic from the Orchestrator to the upstream.
* **DNS resolution** -- The Orchestrator cannot resolve the upstream hostname.
**Diagnostic steps:**
```bash theme={null}
# Test connectivity from the Orchestrator's host
curl -v http://upstream-host:8080/
# Check DNS resolution
nslookup upstream-host
# In Kubernetes, check network policies
kubectl get networkpolicies -n
```
The Orchestrator times out when trying to reach the identity provider during
authentication flows.
**Common causes:**
* **IdP endpoint unreachable** -- The identity provider's endpoints are not
reachable from the Orchestrator's network. This is common in air-gapped
environments or when network egress is restricted.
* **DNS issues** -- The Orchestrator cannot resolve the IdP's hostname.
* **TLS handshake failure** -- The Orchestrator cannot complete a TLS handshake
with the IdP, often because of a missing CA certificate or certificate
verification failure.
* **Proxy required** -- Your network requires an HTTP proxy for outbound
connections, and the Orchestrator is not configured to use it.
**Diagnostic steps:**
* Test the IdP's OIDC discovery endpoint directly from the Orchestrator's host:
`curl -v https://your-idp.example.com/.well-known/openid-configuration`
* Check for proxy requirements and set `HTTP_PROXY` / `HTTPS_PROXY` environment
variables if needed
* Verify the IdP's TLS certificate chain is trusted by the Orchestrator's CA
bundle
The health endpoint (`/status`) returns `{"status": "up"}` when the
Orchestrator is operational. If your load balancer intermittently removes and
re-adds the instance, the Orchestrator may be unresponsive during those
periods.
**Common causes:**
* **Resource pressure** -- The Orchestrator is running low on memory or CPU,
causing slow health check responses that the load balancer interprets as
timeouts.
* **Network instability** -- Intermittent network issues between the load
balancer and the Orchestrator instance.
* **Process restarts** -- The Orchestrator is restarting due to configuration
reloads or OOM kills, causing brief unavailability windows.
**Diagnostic steps:**
```bash theme={null}
# Verify the health endpoint responds
curl -s https://localhost:9443/status
# Expected response: {"status": "up"}
```
* Monitor the Orchestrator's resource usage (CPU, memory) during failure periods
* Check system logs (`journalctl -u maverics` or `docker logs`) for restarts
* Increase the load balancer's health check timeout and failure threshold to
tolerate brief interruptions without removing the instance from the pool
## Getting Help
If you have worked through the troubleshooting steps above and are still stuck, here is how to get additional help.
**Collect diagnostic information** before reaching out to support. This makes it much faster to identify and resolve your issue:
* **Orchestrator version** -- Run the Orchestrator with a `-version` flag or check the startup logs
* **Deployment identifier** -- Every log entry includes a [`soid`](/introduction/glossary#soid-secure-orchestrator-id) field that identifies the Orchestrator instance. Include this value so support can correlate your logs to the specific instance
* **Configuration file** -- A sanitized copy of your config file (remove secrets and credentials)
* **Logs** -- The relevant log entries around the time the issue occurred. Include the full error message and any stack traces. Enable `debug` logging temporarily for more detail
* **Environment details** -- Operating system, container runtime version, Kubernetes version, cloud provider, and any relevant network configuration
**Support channels:**
* **Strata Identity support** -- Contact the Strata support team for production issues. Include the diagnostic information above.
* **Documentation** -- The [Orchestrator Configuration Reference](/reference/orchestrator/configuration) pages often have the specific detail you need for configuration questions.
## Related Pages
Back to the Operations guides hub
Full reference for configuration file structure, environment variables, and runtime settings
Complete configuration reference for telemetry, logging, and health check settings
Configuration for HashiCorp Vault, AWS, Azure, and other secret providers
# Compliance and Audit
Source: https://docs.strata.io/guides/security/compliance
By the end of this guide, you will have a Maverics Orchestrator with comprehensive audit logging -- capturing authentication events, authorization decisions, configuration changes, and administrative actions for compliance reporting.
**Console terminology:** In the Maverics Console, Orchestrator instances and
configuration delivery are managed through **Deployments**. When working directly
with YAML, configuration is managed as files delivered via the `-config` flag or
`MAVERICS_CONFIG` environment variable.
Compliance configurations use features documented across multiple reference pages. Each section below links to the detailed guide and reference for the specific feature being configured.
## What Is Compliance and Audit Logging?
Compliance means demonstrating that your identity system operates according to your organization's policies and applicable regulations. Audit logging is how you produce the evidence. Every time a user authenticates, every time a policy allows or denies access, and every time an administrator changes the configuration -- these events form an audit trail that tells the story of who did what, when, and whether the system allowed it.
The Maverics Orchestrator generates detailed audit events for every significant action it processes. A SIEM (Security Information and Event Management) system -- such as Splunk, Datadog, or Elastic -- collects and analyzes these events, giving your security team a centralized view of identity activity across your infrastructure. Compliance frameworks like SOC2 (Service Organization Control 2, a standard for service providers), HIPAA (Health Insurance Portability and Accountability Act, for healthcare data), and GDPR (General Data Protection Regulation, for EU personal data) each require specific types of audit evidence, and the Orchestrator's logging covers the identity-related requirements for all of them.
## FIPS 140-3 Compliance
FIPS 140-3 builds are an experimental feature. See [FIPS 140-3 Builds](/reference/orchestrator/experimental/fips) for who needs FIPS, current validation status, feature parity details, and contact information.
## Prerequisites
* **A running Maverics Orchestrator** -- If you have not installed it yet, follow the [Quick Start guide](/guides/getting-started/quick-start) first.
* **A log aggregation system** -- You need somewhere to send audit logs for analysis and long-term retention. This can be a SIEM like Splunk, Datadog, or Elastic, a cloud logging service like AWS CloudWatch or Azure Monitor, or even a file-based log management system for smaller deployments.
## Configure Security Features for Compliance
TLS encryption is a baseline requirement for all compliance frameworks. It ensures that authentication tokens, user credentials, and personal data are encrypted in transit.
**Console UI documentation is coming soon.** This section will walk you
through configuring this component using the Maverics Console's visual
interface, including step-by-step screenshots and field descriptions.
Define a TLS profile and bind it to the HTTP listener:
```yaml maverics.yaml theme={null}
tls:
"default":
certFile: "/etc/maverics/certs/server.pem"
keyFile: "/etc/maverics/certs/server-key.pem"
minVersion: "1.2"
http:
address: "0.0.0.0:9443"
tls: "default"
```
For compliance, set `minVersion: "1.2"` to disable older, vulnerable TLS versions. For the highest security, use `"1.3"`.
See the [Configure TLS guide](/guides/security/tls) for complete setup instructions and the [Transport Layer Security (TLS) Reference](/reference/orchestrator/tls-security) for all profile fields.
Compliance frameworks require that secrets (API keys, credentials, certificates) are stored securely with access controls and audit trails. External secret providers satisfy these requirements by centralizing secret storage with rotation, access logging, and fine-grained policies.
**Console UI documentation is coming soon.** This section will walk you
through configuring this component using the Maverics Console's visual
interface, including step-by-step screenshots and field descriptions.
Configure a secret provider via environment variable (not YAML):
```bash theme={null}
export MAVERICS_SECRET_PROVIDER="hashivault://vault.example.com:8200/secret/data/maverics?token="
```
Then reference secrets in YAML using angle bracket syntax:
```yaml maverics.yaml theme={null}
connectors:
- name: my-idp
type: oidc
oauthClientSecret:
```
This ensures no plaintext secrets appear in configuration files -- a common audit finding and compliance requirement.
See the [Manage Secrets guide](/guides/security/secrets-management) for setup instructions and the [Secret Providers Reference](/reference/orchestrator/configuration/secret-providers) for all 7 provider types.
Authorization policies provide the access control evidence that compliance auditors look for. Every policy evaluation is logged, creating an audit trail of who was allowed or denied access to each resource.
**Console UI documentation is coming soon.** This section will walk you
through configuring this component using the Maverics Console's visual
interface, including step-by-step screenshots and field descriptions.
Define authorization policies on your apps:
```yaml maverics.yaml theme={null}
apps:
- name: my-app
type: proxy
upstream: https://backend.example.com
routePatterns:
- "app.example.com"
policies:
- location: "/"
authentication:
idps: ["my-idp"]
authorization:
rules:
- and:
- contains: ["{{ my-idp.groups }}", "authorized-users"]
```
Each policy evaluation generates a log entry recording the user, resource, decision (allow/deny), and the policy rule that was evaluated. These entries form the authorization audit trail required by SOC2, HIPAA, and GDPR.
See the [Authorization Policies guide](/guides/security/policies) for access control configuration -- RBAC, ABAC, PBAC, and external PDP integration, and the [Applications Reference](/reference/orchestrator/applications) for rule syntax.
The Orchestrator captures authentication and authorization events through its structured logging system. Configure the logger for production audit logging and export logs to your SIEM for centralized analysis and long-term retention.
**Console UI documentation is coming soon.** This section will walk you
through configuring this component using the Maverics Console's visual
interface, including step-by-step screenshots and field descriptions.
Configure structured logging with session correlation for audit trails:
```yaml maverics.yaml theme={null}
logger:
level: "info"
jsonOutput: true
logSessionID: true
http:
accessLog:
disabled: false
level: "info"
```
Key settings for compliance logging:
* `jsonOutput: true` -- Structured JSON logs for SIEM ingestion
* `logSessionID: true` -- Correlate events across a user's session for complete audit trails
* `accessLog.disabled: false` -- Record every HTTP request for access auditing
The Orchestrator's structured logs capture authentication events (login, logout, failures), authorization decisions (policy allow/deny), and request metadata. Events are viewable in the Maverics Console and can be exported to external SIEM systems via your log shipper.
See the [Monitor and Observe guide](/guides/operations/monitor) for complete observability setup and the [Telemetry Reference](/reference/orchestrator/telemetry) for all logging fields.
Start by enabling all event categories. You can always reduce the logging
level later if the volume is too high, but it is much harder to
retroactively generate events that were not captured. For compliance, it
is better to log too much than too little.
Session security settings control cookie protection and session lifetimes. Compliance frameworks require that sessions are protected against hijacking and have appropriate timeout policies.
**Console UI documentation is coming soon.** This section will walk you
through configuring this component using the Maverics Console's visual
interface, including step-by-step screenshots and field descriptions.
Configure session cookies and lifetimes for compliance:
```yaml maverics.yaml theme={null}
session:
cookie:
name: "maverics_session"
domain: ".example.com"
disableHTTPOnly: false
disableSecure: false
lifetime:
maxTimeout: "8h"
idleTimeout: "30m"
```
Key security settings:
* `disableHTTPOnly: false` -- Keeps HTTPOnly flag enabled, preventing client-side script access to the session cookie
* `disableSecure: false` -- Keeps Secure flag enabled, ensuring cookies are only sent over HTTPS
* `maxTimeout` -- Maximum session duration before forced re-authentication
* `idleTimeout` -- Inactivity timeout before session expires
See the [Sessions Reference](/reference/orchestrator/sessions) for all session configuration fields.
With TLS, secret management, authorization policies, audit logging, and session security configured, map the Orchestrator's security features to your compliance framework requirements.
**SOC2** -- Requires evidence of access controls, change management, and system monitoring. The Orchestrator provides: authentication/authorization policy enforcement (access controls), structured audit logs (system monitoring), and configuration-as-code with secret management (change management).
**HIPAA** -- Requires audit trails for access to systems handling protected health information (PHI). The Orchestrator provides: per-request authentication and authorization logging, session ID correlation across events, and policy enforcement logs showing access decisions for PHI-containing applications.
**GDPR** -- Requires records of data processing activities and access to personal data. The Orchestrator provides: authentication event logs (tracking access to personal data), session management with appropriate timeouts, and TLS encryption for data in transit.
**Success!** Your Orchestrator is configured with comprehensive security
features for compliance. TLS encrypts all connections, secrets are
managed externally, authorization policies control access, structured
audit logs capture every significant event, and session security
prevents hijacking.
## Troubleshooting
If expected events are not appearing in the Orchestrator's logs, verify that
the log level is set to `"info"` or lower. Events at the `"info"` level
include authentication and authorization decisions. If you need more detail,
temporarily set the level to `"debug"` to see all internal events. Also confirm
that `jsonOutput: true` is set so your SIEM can parse the structured log format.
If audit logs are generated locally but not appearing in your SIEM, check
the log shipper configuration between the Orchestrator and your SIEM. Common
issues include incorrect endpoint URLs, authentication failures with the
SIEM's ingestion API, network connectivity issues (firewalls blocking the
export traffic), and format mismatches (the SIEM expects JSON but receives
plain text). Test the log path independently to isolate the issue.
If your compliance reports show gaps -- periods where no events were
recorded -- investigate whether the Orchestrator was running during those
periods and whether the log export was functioning. Gaps can also occur if
the SIEM dropped events due to ingestion rate limits or storage capacity.
For critical compliance requirements, configure redundant log export
destinations so that a single export failure does not create gaps in your
audit trail.
## Related Pages
Return to the Security guides hub for TLS, secrets, policies, and compliance
Complete configuration reference for logging, monitoring, and observability
Define the access control policies whose enforcement is captured in audit logs
Monitor and operate the Orchestrator in production -- including log management
# Overview
Source: https://docs.strata.io/guides/security/overview
The Maverics Orchestrator sits at the center of your identity infrastructure -- handling authentication tokens, user attributes, client secrets, and session data on every request. That makes it a critical piece of your security posture. These guides walk you through the four pillars of securing your Maverics deployment so that sensitive data stays protected in transit, at rest, and under audit.
The four pillars are: **TLS** for encrypting connections between clients, the Orchestrator, and your upstream applications; **secrets management** for keeping credentials out of config files by integrating with external vaults; **authorization policies** for controlling who can access what through multiple access control models -- roles, attributes, policies, and external policy decision points; and **compliance** for audit logging and regulatory reporting. Work through them in any order -- each guide stands on its own.
## Guides
Define named TLS profiles, bind them to the HTTP listener with http.tls, and configure backend TLS for upstream connections
Configure secret providers via environment variables and CLI flags -- HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, and more with namespace.key references
Define authentication policies with idps, nested and/or authorization rules, and OPA policies for flexible access control across RBAC, ABAC, PBAC, and external PDP models
Configure security features for SOC2, HIPAA, and GDPR compliance -- TLS, secrets, policies, logging, and session management checklist
## Related Pages
Complete configuration reference for TLS certificates, HTTPS listeners, and security settings
Detailed configuration for each supported secret provider -- Vault, AWS, Azure, Delinea, and environment variables
Deploy, monitor, and scale the Orchestrator in production environments
Configure SSO, SAML federation, and identity provider migration
# Configure Authorization Policies
Source: https://docs.strata.io/guides/security/policies
By the end of this guide, you will have a Maverics Orchestrator enforcing authorization policies on every request -- evaluating user attributes, roles, and context to determine whether access is allowed.
## Authentication vs. Authorization
Before diving in, it helps to understand the distinction between these two concepts because they are often confused. **Authentication** answers the question "Who is this user?" -- it verifies identity through credentials like passwords, OIDC tokens, or SAML assertions. **Authorization** answers the question "What is this user allowed to do?" -- it checks whether an authenticated user has permission to access a specific resource or perform a specific action.
The Maverics Orchestrator handles both. Your [authentication configuration](/guides/authentication/overview) verifies user identity. The authorization policies in this guide control what those authenticated users can access. Authentication always happens first -- you cannot authorize a user you have not identified.
## Prerequisites
* **A running Maverics Orchestrator** -- If you have not installed it yet, follow the [Quick Start guide](/guides/getting-started/quick-start) first.
* **An identity provider connected** -- Your Orchestrator should be authenticating users against an identity provider. The Quick Start or [SSO guides](/guides/authentication/overview) cover this.
* **Users authenticating successfully** -- Before adding authorization, confirm that users can log in and access your applications without policy restrictions.
## Configure Policies
### Choose your authorization approach
The Orchestrator provides different authorization mechanisms depending on the mode you are running. Choose the approach that matches your deployment:
* **HTTP Proxy** -- Uses location-based policies with declarative `and`/`or` rules per URL path. Each policy binds to a route and evaluates user attributes against conditions you define. See [HTTP Proxy authorization](#http-proxy) below.
* **OIDC Provider and SAML Provider** -- Uses app-level authorization with declarative rules. OIDC Provider also supports OPA token minting policies. Authorization is configured on the app itself rather than per-location. See [OIDC and SAML Provider authorization](#oidc-and-saml-provider) below.
* **MCP Bridge and MCP Proxy** (AI Identity Gateway) -- Uses OPA-based inbound authorization exclusively. Policies written in Rego evaluate per-tool invocations with access to MCP-specific context. See [OPA Authorization (AI Identity Gateway)](#opa-authorization-ai-identity-gateway) below.
* **LDAP Provider** -- Handles authorization entirely through Service Extensions. There are no declarative authorization rules. See the [Service Extensions reference](/reference/orchestrator/service-extensions) for the `authenticateSE` and `searchSE` hooks.
Not sure which mode applies? See [Choosing a Mode](/guides/authentication/choosing-a-mode).
### HTTP Proxy
In HTTP Proxy mode, authorization is configured per-location within the `policies` array on each app. Each policy specifies a URL path, the identity providers that handle authentication, and optionally the authorization rules that control access after authentication.
Before configuring authorization rules, you need a policy that binds your identity provider connectors to application routes.
**Console UI documentation is coming soon.** This section will walk you
through configuring this component using the Maverics Console's visual
interface, including step-by-step screenshots and field descriptions.
Define policies on your app with authentication connector bindings:
```yaml maverics.yaml theme={null}
apps:
- name: my-app
type: proxy
upstream: https://backend.example.com
routePatterns:
- "app.example.com"
policies:
- location: "/"
authentication:
idps: ["azure", "ldap"]
```
| Field | Description |
| ------------------------------------------------ | ---------------------------------------------------------------------------- |
| `policies[].location` | URL path this policy applies to (must be unique per app) |
| `policies[].authentication.idps` | Connector names for authentication -- must match `connectors[].name` entries |
| `policies[].authentication.allowUnauthenticated` | Allow unauthenticated access to this location (default: `false`) |
| `policies[].decision.lifetime` | Authorization decision cache TTL (duration string, e.g., `"5m"`) |
The `idps` array references connectors by name. The Orchestrator will redirect unauthenticated users to the first listed identity provider for login.
Authorization rules determine whether an authenticated user is allowed to access a resource. Rules support nested `and`/`or` conditions with four comparison operators: `equals`, `notEquals`, `contains`, and `notContains`.
The Orchestrator supports multiple access control models, and you can combine them:
**RBAC (Role-Based Access Control)** assigns permissions based on roles. A user has one or more roles (like "admin," "editor," or "viewer"), and each role grants access to specific resources. RBAC is straightforward and works well when your access patterns align with job functions.
**ABAC (Attribute-Based Access Control)** makes decisions based on attributes -- properties of the user, the resource, or the request context. Attributes can include things like department, location, or any claim from the identity provider.
**PBAC (Policy-Based Access Control)** makes decisions based on centralized policies evaluated against request context, user attributes, and environmental conditions. PBAC generalizes RBAC and ABAC by expressing access rules as policies that can incorporate any combination of roles, attributes, and contextual factors.
**External PDP (Policy Decision Point)** integration delegates authorization decisions to an external policy engine -- such as OPA, Cedar, or a custom PDP -- for organizations that maintain centralized policy engines across multiple systems.
**Console UI documentation is coming soon.** This section will walk you
through configuring this component using the Maverics Console's visual
interface, including step-by-step screenshots and field descriptions.
**Allow all authenticated users** (simplest authorization):
```yaml maverics.yaml theme={null}
policies:
- location: "/"
authentication:
idps: ["azure"]
authorization:
allowAll: true
```
**Simple role-based rule:**
```yaml maverics.yaml theme={null}
policies:
- location: "/admin"
authentication:
idps: ["azure"]
authorization:
rules:
- and:
- contains: ["{{ azure.groups }}", "admin-group"]
```
**Nested and/or rules** for complex access control:
```yaml maverics.yaml theme={null}
policies:
- location: "/"
authentication:
idps: ["azure", "ldap"]
authorization:
rules:
- and:
- equals: ["{{ ldap.role }}", "admin"]
- contains: ["{{ ldap.memberOf }}", "cn=managers"]
- or:
- equals: ["{{ http.request.method }}", "GET"]
- notContains: ["{{ ldap.department }}", "restricted"]
rulesAggregationMethod: "and"
```
In this example: the first rule requires the user to be an admin AND a member of the managers group. The second rule allows GET requests OR users not in the restricted department. Both rules must pass (`rulesAggregationMethod: "and"`).
**Operators:**
| Operator | Description | Operands |
| ------------- | ----------------------------- | ---------- |
| `equals` | Exact string match | 2 operands |
| `notEquals` | Inverse exact match | 2 operands |
| `contains` | Substring or membership check | 2 operands |
| `notContains` | Inverse substring/membership | 2 operands |
**Operand formats:**
* `{{ connector.attribute }}` -- claim from a named connector (e.g., `{{ azure.groups }}`)
* `{{ http.request.method }}` -- HTTP request method
* `"literal"` -- static comparison value
See [Authorization Reference](/reference/orchestrator/authorization) for the complete rule syntax and per-mode comparison.
Start with broad policies and refine as needed. A common pattern is to
require authentication on all routes first, then add access control
restrictions to specific paths. You can always tighten access later
without disrupting users who already have the right permissions.
For authorization logic that goes beyond declarative rules, HTTP Proxy mode supports two Service Extension hooks:
* **`isAuthorizedSE`** runs after declarative rule evaluation and can override or supplement the result. This lets you implement dynamic authorization checks -- for example, querying an external system, checking time-of-day restrictions, or applying business logic that cannot be expressed as `and`/`or` rules. Configure at `policies[].authorization.isAuthorizedSE`. See [Service Extensions](/reference/orchestrator/service-extensions).
* **`handleUnauthorizedSE`** customizes the response when authorization is denied. Instead of the default 403 Forbidden page, you can render a custom error page, redirect to a request-access workflow, or log additional context. Configure at `apps[].handleUnauthorizedSE`. This hook is mutually exclusive with the `unauthorizedPage` setting. See [Service Extensions](/reference/orchestrator/service-extensions).
### OIDC and SAML Provider
In OIDC Provider and SAML Provider modes, authorization is configured at the app level (`apps[].authorization`) rather than per-location. The same declarative rule syntax is available -- `allowAll`, `rules`, and `rulesAggregationMethod` -- but the configuration lives directly on the app instead of inside a `policies[]` block.
**Console UI documentation is coming soon.** This section will walk you
through configuring this component using the Maverics Console's visual
interface, including step-by-step screenshots and field descriptions.
**Allow all authenticated users:**
```yaml maverics.yaml theme={null}
apps:
- name: my-oidc-app
type: oidc
authorization:
allowAll: true
```
**Role-based rule at the app level:**
```yaml maverics.yaml theme={null}
apps:
- name: my-oidc-app
type: oidc
authorization:
rules:
- and:
- contains: ["{{ azure.groups }}", "app-users"]
rulesAggregationMethod: "and"
```
The rule syntax (`and`, `or`, operators, operand formats) is the same as HTTP Proxy. The only difference is the config location: `apps[].authorization` instead of `apps[].policies[].authorization`.
OIDC Provider mode supports OPA policies for token minting authorization. This provides a governance layer over which tokens the Orchestrator issues -- you can enforce policies on token exchange based on user attributes, client identity, or environmental conditions. This does not apply to SAML Provider mode, which issues assertions rather than tokens.
```yaml maverics.yaml theme={null}
apps:
- name: my-oidc-app
type: oidc
authorization:
tokenMinting:
accessToken:
policies:
- name: token-governance
rego: |
package orchestrator
default result := {"allowed": true}
# Deny tokens requested with the client_credentials grant type
result := {"allowed": false, "internal_message": "client_credentials not permitted"} {
input.request.oauth.grant_type == "client_credentials"
}
```
OPA token minting policies must define a `result` object containing an `allowed` field. The Orchestrator denies token issuance if `allowed` is `false`. You can optionally include `internal_message` (logged server-side) and `external_message` (returned to the client) fields. See [OPA Policy Output Schema](#opa-policy-output-schema) for the full output format.
#### OIDC app input schema
The following JSON shows the complete data available under `input` when evaluating an OIDC token minting policy. Values are demonstrative.
```json theme={null}
{
"source": {
"ip": "192.168.1.100"
},
"request": {
"http": {
"host": "idp.example.com",
"method": "POST",
"path": "/token",
"headers": {
"Content-Type": "application/x-www-form-urlencoded",
"User-Agent": "Go-http-client/1.1"
}
},
"oauth": {
"client_id": "325859cf-5bbe-492f-b9e7-929f2bed1230",
"scope": "read:users write:settings",
"grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
"subject_token": {
"claims": {
"scope": "api:read api:write"
}
},
"actor_token": {
"claims": {
"scope": "openid"
}
},
"response": {
"access_token": {
"claims": {
"scope": "read:users write:settings",
"aud": "https://api.example.com",
"client_id": "325859cf-5bbe-492f-b9e7-929f2bed1230"
}
},
"scope": "read:users write:settings",
"expires_in": 3600
}
}
}
}
```
#### OIDC app example: enforce scope reduction on token exchange
The following policy ensures that scopes are only reduced during token exchange flows. The requested scopes in the token exchange request must be a subset of the scopes in the `subject_token`. All other grant types are allowed without restriction.
```rego policy.rego theme={null}
package orchestrator
default result["allowed"] := false
# Allow all non-token-exchange grant types.
result["allowed"] if {
input.request.oauth.grant_type != "urn:ietf:params:oauth:grant-type:token-exchange"
}
# Parse scopes from space-separated strings into sets.
requested_scopes := {s | some s in split(input.request.oauth.scope, " "); s != ""}
subject_scopes := {s | some s in split(input.request.oauth.subject_token.claims.scope, " "); s != ""}
# For token exchange grants, allow if requested scopes are a subset of subject token scopes.
result["allowed"] if {
input.request.oauth.grant_type == "urn:ietf:params:oauth:grant-type:token-exchange"
print("requested_scopes:", requested_scopes)
print("subject_scopes:", subject_scopes)
count(requested_scopes - subject_scopes) == 0
}
result["internal_message"] := "requested scopes exceed subject_token scopes" if {
not result.allowed
}
result["external_message"] := "invalid_scope" if {
not result.allowed
}
```
The `isAuthorizedSE` Service Extension hook is also available in OIDC Provider and SAML Provider modes. Configure at `apps[].authorization.isAuthorizedSE`. See [Service Extensions](/reference/orchestrator/service-extensions).
### AI Identity Gateway (OPA Authorization)
In MCP Bridge and MCP Proxy modes (AI Identity Gateway), OPA is the only authorization mechanism. There are no declarative `and`/`or` rules. All authorization is handled through Rego policies that evaluate per-tool invocations with access to MCP-specific context such as tool name and arguments.
Configure OPA via `authorization.inbound.opa` with a policy `name` and either `file` (path to a `.rego` file) or inline `rego`.
**Console UI documentation is coming soon.** This section will walk you
through configuring this component using the Maverics Console's visual
interface, including step-by-step screenshots and field descriptions.
**Inline OPA policy:**
```yaml maverics.yaml theme={null}
authorization:
inbound:
type: opa
opa:
name: my-auth-policy
rego: |
package orchestrator
default result := {"allowed": false}
# Allow the listUsers tool
result := {"allowed": true} {
input.request.mcp.type == "tool"
input.request.mcp.tool.params.name == "listUsers"
}
# Allow the getUser tool
result := {"allowed": true} {
input.request.mcp.type == "tool"
input.request.mcp.tool.params.name == "getUser"
}
```
**File-based OPA policy:**
```yaml maverics.yaml theme={null}
authorization:
inbound:
type: opa
opa:
name: my-auth-policy
file: /etc/maverics/policies/auth.rego
```
For tool filtering configuration -- controlling which tools are exposed to MCP clients during `tools/list` -- see the [MCP Proxy App reference](/reference/orchestrator/applications/mcp-proxy#tool-filtering-opa).
For the complete per-mode authorization comparison, see the [Authorization Reference](/reference/orchestrator/authorization#per-mode-authorization-differences).
OPA policies must define a `result` object containing an `allowed` field. The Orchestrator denies the request if `allowed` is `false`. You can optionally include `internal_message` (logged server-side) and `external_message` (returned to the client) fields. See [OPA Policy Output Schema](#opa-policy-output-schema) for the full output format.
#### MCP app input schema
The input schema varies by policy type. Connection policies receive only the HTTP request context; inbound and listing policies additionally receive `input.request.mcp` with the request type in `mcp.type`.
**Connection admission** — evaluated by the `connection` policy when the proxy establishes a new upstream session. No `mcp` context is present because no tool has been invoked yet:
```json theme={null}
{
"source": {
"ip": "192.168.1.100"
},
"request": {
"http": {
"host": "mcp.example.com",
"method": "POST",
"path": "/mcp",
"headers": {
"Authorization": "Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"Content-Type": "application/json",
"User-Agent": "MCP-Client/1.0"
}
}
}
}
```
**Tool call** (`mcp.type: "tool"`) — evaluated by the `inbound` policy on every tool invocation:
```json theme={null}
{
"source": {
"ip": "192.168.1.100"
},
"request": {
"http": {
"host": "mcp.example.com",
"method": "POST",
"path": "/mcp",
"headers": {
"Authorization": "Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"Content-Type": "application/json",
"User-Agent": "MCP-Client/1.0"
}
},
"mcp": {
"type": "tool",
"tool": {
"params": {
"name": "listUsers",
"arguments": {
"exampleBodyKeyAlpha": 10,
"exampleBodyKeyBeta": true
}
}
}
}
}
}
```
**Tool listing** (`mcp.type: "tools_list"`) — evaluated by the `listing` policy once per tool during a `tools/list` request. The policy runs for each tool individually; tools the policy denies are removed before the response reaches the MCP client:
```json theme={null}
{
"source": {
"ip": "192.168.1.100"
},
"request": {
"http": {
"host": "mcp.example.com",
"method": "POST",
"path": "/mcp",
"headers": {
"Authorization": "Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"Content-Type": "application/json",
"User-Agent": "MCP-Client/1.0"
}
},
"mcp": {
"type": "tools_list",
"response": {
"tools_list": {
"name": "listUsers"
}
}
}
}
}
```
#### MCP app example: JWT-based tool authorization
The following policy grants access to the `get_ticket_price` tool only if the `Authorization` header contains a JWT with the `tickets:read` scope. All other tools and requests are denied by default.
```rego policy.rego theme={null}
package orchestrator
# Default deny policy - all requests are denied unless explicitly allowed
default result["allowed"] := false
# Decode the bearer token's claims. jwt.parse_bearer strips the "Bearer "
# prefix and returns the payload, or undefined if the header is absent or
# does not carry a JWT -- in which case every rule below fails and the
# default deny applies.
jwt_payload := jwt.parse_bearer(input.request.http.headers.Authorization)
# Allows access to the get_ticket_price tool if the token contains
# the tickets:read scope. Logs the tool name, client ID, and subject
# for audit purposes.
result["allowed"] if {
print("request made to tool: ", input.request.mcp.tool.params.name)
input.request.mcp.tool.params.name == "get_ticket_price"
print("request made with client of: ", jwt_payload.client_id)
contains(jwt_payload.scope, "tickets:read")
print("access granted to subject:", jwt_payload.sub)
}
result["internal_message"] := "access is only permitted to the 'get_ticket_price' tool with tickets:read scope" if {
not result.allowed
}
result["external_message"] := "unauthorized, contact support@example.com" if {
not result.allowed
}
```
#### Connection admission example: check permitted MCP servers claim
The following policy gates upstream session establishment to bearers whose JWT contains a custom `permitted_mcp_servers` claim that includes the target server name. An IdP stamps this claim with the list of MCP servers the agent is authorized to reach; the policy checks membership before the session is opened. Because the admission decision is sticky for the lifetime of the session, this check runs once at connect time rather than on every tool call.
```rego connection.rego theme={null}
package orchestrator
default result["allowed"] := false
jwt_payload := jwt.parse_bearer(input.request.http.headers.Authorization)
result["allowed"] if {
"mission-control" in jwt_payload.permitted_mcp_servers
}
result["internal_message"] := "bearer token does not permit access to this MCP server" if {
not result["allowed"]
}
result["external_message"] := "unauthorized: MCP server access not granted" if {
not result["allowed"]
}
```
#### Tool Filtering example: allowlist tools exposed to the MCP client
The following policy exposes only the tools in the permitted set. The MCP client receives only these tools in its `tools/list` response -- everything else is hidden, reducing the capabilities available to the AI agent.
```rego listing.rego theme={null}
package orchestrator
default result["allowed"] := false
# Tools visible to downstream MCP clients
allowed_tools := {"listUsers", "getUser", "searchUsers"}
result["allowed"] if {
input.request.mcp.type == "tools_list"
input.request.mcp.response.tools_list.name in allowed_tools
}
result["internal_message"] := "tool is not in the allowed set" if {
not result["allowed"]
}
```
#### Tool Filtering example: scope-based tool exposure
The following policy exposes a different set of tools depending on the agent's JWT scopes. `ticketService:write` is a superset of `ticketService:read`: agents with only `ticketService:read` see read-only tools; agents with `ticketService:write` see both read and write tools. This narrows each agent's attack surface to exactly what it needs.
```rego listing.rego theme={null}
package orchestrator
default result["allowed"] := false
jwt_payload := jwt.parse_bearer(input.request.http.headers.Authorization)
# Read-only tools available to agents with ticketService:read or ticketService:write
read_tools := {"listTickets", "getTicket", "searchTickets"}
# Write tools restricted to agents with the ticketService:write scope
write_tools := {"createTicket", "updateTicket", "closeTicket"}
result["allowed"] if {
input.request.mcp.type == "tools_list"
input.request.mcp.response.tools_list.name in read_tools
some s in ["ticketService:read", "ticketService:write"]
contains(jwt_payload.scope, s)
}
result["allowed"] if {
input.request.mcp.type == "tools_list"
input.request.mcp.response.tools_list.name in write_tools
contains(jwt_payload.scope, "ticketService:write")
}
result["internal_message"] := "tool not permitted for this agent's scope" if {
not result["allowed"]
}
```
### Rego Built-in Functions
In addition to the standard [OPA built-in functions](https://www.openpolicyagent.org/docs/policy-reference#built-in-functions), the Orchestrator registers its own built-ins. These are available in every OPA policy the Orchestrator evaluates -- OIDC token minting, MCP connection, MCP inbound, and MCP tool filtering.
#### `jwt.parse_bearer`
Decodes the claims from a bearer token in a single call, replacing the `startswith` / `substring` / `io.jwt.decode` sequence that policies would otherwise need to extract a JWT from an `Authorization` header.
```rego theme={null}
jwt.parse_bearer(header_value)
```
| Parameter | Type | Description |
| -------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------ |
| `header_value` | String | The full `Authorization` header value, including the `Bearer ` scheme -- typically `input.request.http.headers.Authorization`. |
Returns an object containing the token's payload claims.
The auth-scheme is matched case-insensitively, per [RFC 6750 section 2.1](https://datatracker.ietf.org/doc/html/rfc6750#section-2.1), so `Bearer`, `bearer`, and `BEARER` are all accepted. The credentials that follow are decoded exactly as sent.
**Usage:**
```rego policy.rego theme={null}
package orchestrator
default result["allowed"] := false
claims := jwt.parse_bearer(input.request.http.headers.Authorization)
result["allowed"] if {
contains(claims.scope, "tickets:read")
}
```
**Undefined results**
The function returns undefined -- rather than an error -- when it cannot produce claims. This happens when:
* The `Authorization` header is missing or empty.
* The header does not use the `Bearer` auth-scheme (for example, `Basic`).
* The value after the scheme is not a well-formed signed JWT.
* The JWT payload is not a JSON object.
Because an undefined value makes any rule referencing it fail, a policy with a `default result["allowed"] := false` rule denies the request in all of these cases. This is the recommended pattern -- write the default deny and let undefined claims fall through to it.
`jwt.parse_bearer` decodes the token payload **without verifying its signature**, its expiry, or any other claim. It is a parsing helper, not a validation step -- a policy that trusts its output alone will accept a forged token.
Token trust is established elsewhere. Configure `mcpProvider.authorization.oauth` with `servers[].tokenValidation` so the Orchestrator validates the bearer token before the request reaches your policy. That OAuth block is optional -- if it is absent, no token validation happens and a policy reading these claims is trusting unverified input. If you need to verify a signature inside the policy itself, use OPA's `io.jwt.decode_verify` instead.
### OPA Policy Output Schema
All OPA policies -- whether for OIDC token minting or MCP inbound authorization -- must return a `result` object with the following structure:
```json theme={null}
{
"result": {
"allowed": true,
"internal_message": "user does not have necessary group membership: missing admin membership",
"external_message": "unauthorized"
}
}
```
| Field | Required | Description |
| ------------------------- | -------- | ----------------------------------------------------------------------------------- |
| `result.allowed` | Yes | Whether access should be granted (`true`) or denied (`false`) |
| `result.internal_message` | No | Details about the decision for server-side logs only. Not returned to clients. |
| `result.external_message` | No | Details returned to the client and also logged. Use for user-facing error messages. |
Use `print()` statements in your Rego policies to emit debug output to Orchestrator logs. This is useful for tracing which rules matched and inspecting input values during policy development.
### Test policy enforcement
With policies defined and applied, test that they work as expected by making requests as users with different roles and attributes. Testing both the "allowed" and "denied" paths confirms that your policies are enforced correctly.
Start (or restart) the Orchestrator to load your policy configuration:
```bash theme={null}
maverics -config /etc/maverics/maverics.yaml
```
Test with a user who should have access:
1. **Log in** as a user whose roles or attributes satisfy the policy conditions
2. **Navigate** to the protected resource -- you should see the application content
3. **Verify** the request reached your upstream application (check application logs)
Test with a user who should be denied:
1. **Log in** as a user who does not meet the policy conditions
2. **Navigate** to the same resource -- you should receive a 403 Forbidden response
3. **Verify** the request did not reach your upstream application
**Success!** Your Orchestrator is enforcing authorization policies.
Requests from authorized users proceed to your applications, and
unauthorized requests are blocked before they ever reach your
upstream services.
## Troubleshooting
If a policy does not seem to take effect, verify that it is attached to the
correct application route. A defined but unattached policy is inert -- it
exists in the configuration but does not affect any traffic. Also check
that the route path pattern matches the URLs you are testing. The
Orchestrator logs which policies are evaluated on each request when
debug logging is enabled.
If a user is denied access when you expect them to be allowed, check the
user's claims from the identity provider. The most common cause is a
mismatch between the role or attribute name in your policy and the actual
claim value from the IdP. For example, your policy may check for a role
called "admin" but the IdP sends "Admin" (case matters). Enable debug
logging to see the exact claims the Orchestrator receives and the policy
evaluation result.
If a policy references an attribute that the identity provider does not
include in its token or assertion, the policy evaluation fails because the
attribute is missing. Verify that your identity provider is configured to
include the needed claims (roles, groups, department, or custom attributes)
in the token it sends to the Orchestrator. Check the
[Identity Fabric reference](/reference/orchestrator/identity-fabric)
for details on claim mapping for your specific provider.
## Related Pages
Return to the Security guides hub for TLS, secrets, policies, and compliance
Per-mode authorization differences, enforcement behavior, and OPA policy patterns
Complete configuration reference for authorization rules, operators, and policy syntax
Configure SSO, SAML federation, and identity provider connections that policies build on
Custom authorization logic via isAuthorizedSE, handleUnauthorizedSE, and other SE hooks
Log policy decisions and authorization events for compliance reporting
# Manage Secrets
Source: https://docs.strata.io/guides/security/secrets-management
By the end of this guide, you will have a Maverics Orchestrator that retrieves all sensitive configuration values -- API keys, client secrets, certificates -- from your organization's secret management system rather than from files or environment variables.
**Console terminology:** In the Maverics Console, Orchestrator instances and
configuration delivery are managed through **Deployments**. When working directly
with YAML, configuration is managed as files delivered via the `-config` flag or
`MAVERICS_CONFIG` environment variable.
## Why External Secret Providers?
Secrets are sensitive values that your Orchestrator needs to function -- things like identity provider client secrets, API keys for upstream services, TLS private keys, and database passwords. Storing these directly in configuration files or environment variables creates risk: anyone with access to the file system or process environment can read them, and they are easy to accidentally commit to version control.
External secret providers solve this problem by storing secrets in a dedicated, access-controlled system. The Orchestrator fetches secrets at runtime using authenticated API calls, which means the actual secret values never appear in your config files. Providers like HashiCorp Vault, AWS Secrets Manager, and Azure Key Vault also offer features like automatic rotation, audit logging, and fine-grained access policies -- giving you centralized control over who and what can access each secret.
## Prerequisites
* **A running Maverics Orchestrator** -- If you have not installed it yet, follow the [Quick Start guide](/guides/getting-started/quick-start) first.
* **Access to a secret provider** -- You need an account and appropriate permissions on one of the supported providers: [HashiCorp Vault](/reference/orchestrator/configuration/secret-providers/hashicorp-vault), [AWS Secrets Manager](/reference/orchestrator/configuration/secret-providers/aws-secrets-manager), [Azure Key Vault](/reference/orchestrator/configuration/secret-providers/azure-key-vault), [Delinea Secret Server](/reference/orchestrator/configuration/secret-providers/delinea), [CyberArk Conjur](/reference/orchestrator/configuration/secret-providers/conjur), [CyberArk CCP](/reference/orchestrator/configuration/secret-providers/cyberark-ccp), or a [Secret File](/reference/orchestrator/configuration/secret-providers/environment) for development.
## Integrate a Secret Provider
The Maverics Orchestrator supports 7 secret provider types, each suited to different environments and organizational requirements.
**Console UI documentation is coming soon.** This section will walk you
through configuring this component using the Maverics Console's visual
interface, including step-by-step screenshots and field descriptions.
Secret providers are not configured in YAML. They are configured via the `MAVERICS_SECRET_PROVIDER` environment variable or the `-secretProvider` CLI flag. The table below lists all supported providers.
| Provider | URL Scheme | Best For |
| ------------------------------------------------------------------------------------------------- | ----------------------------------- | ------------------------------------------------------------------- |
| [HashiCorp Vault](/reference/orchestrator/configuration/secret-providers/hashicorp-vault) | `hashivault://` or `hashivaults://` | Multi-cloud, on-premises -- dynamic secrets, automatic rotation |
| [AWS Secrets Manager](/reference/orchestrator/configuration/secret-providers/aws-secrets-manager) | `awssecretsmanager://` | AWS-native deployments -- IAM integration, cross-region replication |
| [Azure Key Vault](/reference/orchestrator/configuration/secret-providers/azure-key-vault) | `azurekeyvault://` | Azure-native deployments -- managed identity, HSM backing |
| [Delinea Secret Server](/reference/orchestrator/configuration/secret-providers/delinea) | `delinea://` | Enterprise PAM -- session recording, approval workflows |
| [CyberArk Conjur](/reference/orchestrator/configuration/secret-providers/conjur) | `conjur://` | DevOps-oriented secrets for CI/CD and containers |
| [CyberArk CCP](/reference/orchestrator/configuration/secret-providers/cyberark-ccp) | `cyberarkccp://` | CyberArk Central Credential Provider |
| [Secret File](/reference/orchestrator/configuration/secret-providers/environment) | `secretfile://` | Development and testing -- local file-based secrets |
For most production deployments, choose the provider that matches your cloud platform or existing secret management infrastructure.
See [Secret Providers Reference](/reference/orchestrator/configuration/secret-providers) for detailed configuration documentation for each provider.
Secret providers are configured via the `MAVERICS_SECRET_PROVIDER` environment variable or the `-secretProvider` CLI flag -- not in YAML configuration. Only one secret provider may be active at a time.
The Orchestrator authenticates to the secret provider at startup and maintains the connection for the lifetime of the process. If the connection drops, the Orchestrator retries automatically.
**Console UI documentation is coming soon.** This section will walk you
through configuring this component using the Maverics Console's visual
interface, including step-by-step screenshots and field descriptions.
Secret providers are configured via environment variable or CLI flag, not in YAML. The examples below show shell commands for the three most common providers.
**HashiCorp Vault:**
```bash theme={null}
export MAVERICS_SECRET_PROVIDER="hashivault://vault.example.com:8200/secret/data/maverics?token="
```
**AWS Secrets Manager:**
```bash theme={null}
export MAVERICS_SECRET_PROVIDER="awssecretsmanager://us-east-1"
```
**Azure Key Vault:**
```bash theme={null}
export MAVERICS_SECRET_PROVIDER="azurekeyvault://my-vault.vault.azure.net"
```
You can also pass the provider via the CLI flag instead of an environment variable:
```bash theme={null}
maverics \
-config /etc/maverics/maverics.yaml \
-secretProvider "hashivault://vault.example.com:8200/secret/data/maverics?token="
```
See [Secret Providers Reference](/reference/orchestrator/configuration/secret-providers) for provider-specific URL parameters and authentication options.
The credentials used to connect to the secret provider itself (like a
Vault token or Azure service principal) should have the minimum
permissions needed -- typically read-only access to the specific secrets
the Orchestrator uses. Follow the principle of least privilege.
Once the secret provider is configured, replace hardcoded secret values in your Orchestrator configuration with secret references. A secret reference uses angle bracket syntax: ``. The Orchestrator resolves these references at startup by fetching the value from the configured provider.
**Console UI documentation is coming soon.** This section will walk you
through configuring this component using the Maverics Console's visual
interface, including step-by-step screenshots and field descriptions.
Use `` syntax to reference secrets anywhere a sensitive value is needed:
```yaml maverics.yaml theme={null}
connectors:
- name: my-idp
type: oidc
oauthClientID: "my-client-id"
oauthClientSecret:
oidcWellKnownURL: "https://idp.example.com/.well-known/openid-configuration"
caches:
- name: "shared-redis"
type: "redis"
redis:
addresses:
- "redis.example.com:6379"
password:
tls:
"default":
certFile: "/etc/maverics/certs/server.pem"
keyFile: "/etc/maverics/certs/server-key.pem"
```
In this example:
* `` -- The `maverics` namespace and `oidc-client-secret` key map to the secret path in your provider
* `` -- Same namespace, different key for the Redis password
The Orchestrator resolves all `` references during startup. The rest of the system works exactly the same -- the only difference is where the value comes from.
Secret references work in any string field in the YAML configuration. Use them for client secrets, passwords, API keys, encryption keys, and any other sensitive value.
After configuring secret references, restart the Orchestrator and verify that it successfully retrieves all secrets from the provider. The Orchestrator resolves secret references during startup, so any issues will appear in the startup logs.
Start (or restart) the Orchestrator:
```bash theme={null}
maverics -config /etc/maverics/maverics.yaml
```
Check the logs for successful secret resolution. The Orchestrator logs when it connects to the secret provider and when it resolves each secret reference. Look for confirmation that all secrets were retrieved without errors.
Verify the health endpoint to confirm the Orchestrator started successfully with resolved secrets:
```bash theme={null}
curl -s https://localhost:9443/status | jq .
```
If the health endpoint returns `{"status": "up"}`, your secrets are resolving correctly -- the Orchestrator was able to use the retrieved credentials to connect to your identity providers and other services.
**Success!** Your Orchestrator is retrieving secrets from your external
provider at runtime. No sensitive values are stored in configuration files,
and your secrets benefit from the provider's rotation, access control, and
audit logging features.
## Troubleshooting
The Orchestrator logs an error if it cannot find a secret at the referenced
path in the provider. Verify that the secret path in your configuration
exactly matches the path in your provider -- paths are case-sensitive and
must include the full hierarchy (for Vault, this includes the mount path
and secret path). Also check that the secret has been created in the
provider before the Orchestrator tries to read it.
If the Orchestrator cannot authenticate to your secret provider, check that
the connection credentials are correct and have not expired. For Vault,
verify the token has not been revoked. For AWS, verify the IAM role or
access keys have the correct permissions. For Azure, verify the service
principal credentials and that the Key Vault access policy grants the
necessary permissions. The Orchestrator logs the specific authentication
error during startup.
By default, the Orchestrator resolves secrets at startup. If your provider
rotates a secret while the Orchestrator is running, the Orchestrator
continues using the previously fetched value until it is restarted. For
production deployments that require seamless rotation, check whether your
secret provider supports a notification mechanism or configure the
Orchestrator's secret refresh interval to periodically re-fetch values.
## Related Pages
Return to the Security guides hub for TLS, secrets, policies, and compliance
Detailed configuration for each supported provider -- Vault, AWS, Azure, Delinea, CyberArk Conjur, CyberArk CCP, and Secret File
Store TLS certificates and private keys as secrets for secure certificate management
Deploy and monitor the Orchestrator in production -- including secret management best practices
# Configure TLS
Source: https://docs.strata.io/guides/security/tls
By the end of this guide, you will have a Maverics Orchestrator with TLS encryption on all connections -- HTTPS for client-facing traffic and optionally TLS for backend connections to upstream applications.
**Console terminology:** In the Maverics Console, Orchestrator instances and
configuration delivery are managed through **Deployments**. When working directly
with YAML, configuration is managed as files delivered via the `-config` flag or
`MAVERICS_CONFIG` environment variable.
## What Is TLS?
TLS (Transport Layer Security) is the protocol that encrypts data as it travels between two systems over a network. When you see "HTTPS" in a browser URL, that is HTTP running over TLS -- meaning the connection between the browser and the server is encrypted so that no one in between can read or tamper with the data.
For the Maverics Orchestrator, TLS matters in two places. First, the connection between your users' browsers and the Orchestrator -- this is called **TLS termination** because the Orchestrator accepts the encrypted HTTPS connection and decrypts it. Second, the connection between the Orchestrator and your upstream applications -- this is called **backend TLS** and is optional but recommended in production environments where the Orchestrator and your apps are on different networks.
## Prerequisites
* **A running Maverics Orchestrator** -- If you have not installed it yet, follow the [Quick Start guide](/guides/getting-started/quick-start) first.
* **A TLS certificate and private key** -- You can use a certificate from a certificate authority (CA) like Let's Encrypt, your organization's internal CA, or a self-signed certificate for testing. The certificate should be in PEM format.
## Configure TLS
The Orchestrator uses **named TLS profiles** to manage certificates and encryption settings in one place. Each profile is a named entry under the `tls` top-level key. Once defined, a profile can be referenced by the HTTP listener, identity connectors, and [external cache](/reference/orchestrator/caches) connections -- so you configure your certificate paths and TLS constraints once and reuse them wherever encrypted connections are needed.
A TLS certificate is a file that proves your server's identity to clients. It comes in a pair: a **certificate file** (the public part, often ending in `.crt` or `.pem`) and a **private key file** (the secret part, often ending in `.key`). The certificate authority that issued your certificate vouches that it belongs to your domain.
For production deployments, use a certificate from a trusted certificate authority. [Let's Encrypt](https://letsencrypt.org/) provides free certificates that are trusted by all major browsers. Your organization may also have an internal CA that issues certificates for internal services.
**Console UI documentation is coming soon.** This section will walk you
through configuring this component using the Maverics Console's visual
interface, including step-by-step screenshots and field descriptions.
Define one or more named TLS profiles under the `tls` top-level key:
```yaml maverics.yaml theme={null}
tls:
"default":
certFile: "/etc/maverics/certs/server.pem"
keyFile: "/etc/maverics/certs/server-key.pem"
minVersion: "1.2"
"upstream-idp":
caFile: "/etc/maverics/certs/idp-ca.pem"
insecureSkipVerify: false
```
The key fields are `certFile` and `keyFile` for the certificate pair, `minVersion` to set the minimum TLS version (defaults to `"1.2"`), and `caFile` when connecting to upstream servers with custom CA certificates. You can also set `maxVersion` to cap the TLS version -- for example, setting both `minVersion` and `maxVersion` to `"1.2"` restricts the profile to TLS 1.2 only.
See the [TLS Reference](/reference/orchestrator/tls-security#profile-fields) for the complete list of profile fields including mTLS, OCSP, CRL, and cipher suite options.
Store your private key securely. If you are managing multiple secrets, consider using a [secret provider](/guides/security/secrets-management) to keep the private key out of the filesystem and retrieve it at runtime from HashiCorp Vault, AWS Secrets Manager, or another provider.
With your TLS profile defined, bind it to the Orchestrator's HTTP listener. This is where **TLS termination** happens -- the Orchestrator accepts encrypted connections from clients and decrypts them internally.
Set `http.tls` to the name of the TLS profile you defined in the previous step. This is the critical wiring step that connects your certificate to the HTTP server.
**Console UI documentation is coming soon.** This section will walk you
through configuring this component using the Maverics Console's visual
interface, including step-by-step screenshots and field descriptions.
Reference the named TLS profile from the `http` configuration:
```yaml maverics.yaml theme={null}
http:
address: "0.0.0.0:9443"
tls: "default"
tls:
"default":
certFile: "/etc/maverics/certs/server.pem"
keyFile: "/etc/maverics/certs/server-key.pem"
minVersion: "1.2"
```
The `http.tls` field takes the name of a profile defined under the `tls` key -- in this case, `"default"`. The Orchestrator uses this profile for all incoming HTTPS connections.
If you need to serve multiple domains with different certificates, use `http.hosts` instead of `http.tls` for SNI-based certificate selection:
```yaml maverics.yaml theme={null}
http:
address: "0.0.0.0:443"
hosts:
- serverName: "app.example.com"
tls: "app-cert"
- serverName: "api.example.com"
tls: "api-cert"
```
`http.tls` and `http.hosts` are mutually exclusive. Use `http.tls` for a single TLS profile on all connections, or `http.hosts` for SNI-based virtual hosting with different TLS profiles per server name.
See the [TLS Reference](/reference/orchestrator/tls-security) for the complete set of TLS configuration options -- including cipher suite selection, minimum TLS version, and client certificate authentication.
Backend TLS secures the connection between the Orchestrator and your upstream applications. This step is optional -- if the Orchestrator and your apps run on the same host or in a trusted private network, you may not need it. But if traffic crosses network boundaries or your compliance requirements mandate encryption everywhere, backend TLS ensures data stays encrypted for the entire journey.
When you enable backend TLS, the Orchestrator connects to your upstream application over HTTPS instead of HTTP. If your upstream uses a self-signed certificate or an internal CA, you will need to provide the CA certificate so the Orchestrator can verify the connection.
**Console UI documentation is coming soon.** This section will walk you
through configuring this component using the Maverics Console's visual
interface, including step-by-step screenshots and field descriptions.
Create a TLS profile for upstream connections and reference it in your app configuration:
```yaml maverics.yaml theme={null}
tls:
"default":
certFile: "/etc/maverics/certs/server.pem"
keyFile: "/etc/maverics/certs/server-key.pem"
minVersion: "1.2"
"upstream":
caFile: "/etc/maverics/certs/upstream-ca.pem"
insecureSkipVerify: false
http:
address: "0.0.0.0:9443"
tls: "default"
apps:
- name: my-app
type: proxy
upstream: https://backend.example.com
tls: "upstream"
routePatterns:
- "app.example.com"
```
The proxy app's `tls` field references a named TLS profile used for the connection to the upstream backend. The `caFile` in the profile lets the Orchestrator verify the upstream server's certificate.
For mutual TLS (mTLS) with the upstream, include `certFile` and `keyFile` in the upstream profile to present a client certificate.
Never set `insecureSkipVerify: true` in production. This disables certificate verification, making the connection vulnerable to man-in-the-middle attacks. Use it only for local development with self-signed certificates.
Some compliance frameworks and legacy integrations require specific TLS version constraints. The `minVersion` and `maxVersion` fields let you control exactly which TLS versions the Orchestrator accepts.
Three common patterns:
**Production default (TLS 1.2+)** -- Accept TLS 1.2 and above. This is the default when only `minVersion` is set:
```yaml maverics.yaml theme={null}
tls:
"default":
certFile: "/etc/maverics/certs/server.pem"
keyFile: "/etc/maverics/certs/server-key.pem"
minVersion: "1.2"
```
**TLS 1.3 only** -- Require the latest protocol version. Clients that do not support TLS 1.3 will be rejected:
```yaml maverics.yaml theme={null}
tls:
"tls13-only":
certFile: "/etc/maverics/certs/server.pem"
keyFile: "/etc/maverics/certs/server-key.pem"
minVersion: "1.3"
```
**TLS 1.2 only** -- Pin to TLS 1.2 for systems that require it. Setting both `minVersion` and `maxVersion` to `"1.2"` prevents TLS 1.3 negotiation:
```yaml maverics.yaml theme={null}
tls:
"tls12-only":
certFile: "/etc/maverics/certs/server.pem"
keyFile: "/etc/maverics/certs/server-key.pem"
minVersion: "1.2"
maxVersion: "1.2"
```
`maxVersion` requires Orchestrator v2026.02.3 or later. Earlier versions only support `minVersion`.
With TLS configured, restart the Orchestrator and verify that HTTPS connections are working correctly. A simple test confirms that the certificate is being served and the connection is encrypted.
Start (or restart) the Orchestrator to pick up your TLS configuration:
```bash theme={null}
maverics -config /etc/maverics/maverics.yaml
```
Test the HTTPS endpoint with curl:
```bash theme={null}
curl -v https://your-orchestrator-domain:9443/status
```
The `-v` (verbose) flag shows the TLS handshake details. Look for lines showing the certificate subject, issuer, and that the handshake completed successfully. If you are using a self-signed certificate for testing, add the `-k` flag to skip certificate verification:
```bash theme={null}
curl -vk https://localhost:9443/status
```
To verify the negotiated TLS version specifically, use `openssl`:
```bash theme={null}
openssl s_client -connect localhost:9443 < /dev/null 2>/dev/null | grep "Protocol"
```
This outputs the protocol version (e.g., `TLSv1.2` or `TLSv1.3`), confirming your version constraints are in effect.
You can also verify the full certificate details:
```bash theme={null}
openssl s_client -connect localhost:9443 -showcerts < /dev/null
```
**Success!** Your Orchestrator is serving traffic over HTTPS with TLS
encryption. Client connections are encrypted, and if you configured
backend TLS, the connection to your upstream applications is encrypted
too.
## Troubleshooting
The Orchestrator logs an error at startup if it cannot find the certificate
or key file at the configured path. Verify that the file paths in your
configuration are absolute paths (not relative) and that the files are
readable by the user running the Orchestrator. Common causes include typos
in the file path, incorrect file permissions, or the certificate being
stored in a different directory than expected.
A TLS handshake failure means the client and server could not agree on how
to encrypt the connection. This can happen when the certificate does not
match the domain the client is connecting to (a hostname mismatch), when
the certificate has expired, or when the client and server do not support
any common TLS versions or cipher suites. Check the Orchestrator logs for
the specific handshake error and verify that your certificate's Common Name
(CN) or Subject Alternative Name (SAN) matches the domain you are
connecting to.
Browsers and clients need the full certificate chain -- your certificate
plus any intermediate certificates from the CA -- to verify trust. If
clients see a "certificate not trusted" error even though your certificate
is valid, you may be missing intermediate certificates. Concatenate your
certificate and the intermediate certificate(s) into a single PEM file,
with your certificate first and the intermediates following in order.
If clients receive "protocol version" or "no protocols available" errors,
the client and server do not share a supported TLS version. Check your
profile's `minVersion` and `maxVersion` settings against what the client
supports. For example, if `minVersion` is `"1.3"` but the client only
supports TLS 1.2, the handshake will fail. Use `openssl s_client -connect
host:port` to see which protocol version is negotiated, or test with a
specific version using `openssl s_client -tls1_2` or `-tls1_3`.
If the Orchestrator and client cannot agree on a cipher suite, the
connection fails with a "no cipher suites in common" error. This typically
happens when `enabledCiphers` is set to a restrictive list that does not
overlap with the client's supported ciphers. Verify your cipher list
against the client's capabilities. Remember that `enabledCiphers` only
affects TLS 1.2 -- TLS 1.3 cipher suites are fixed by the protocol and
cannot be restricted.
## Related Pages
Return to the Security guides hub for TLS, secrets, policies, and compliance
Complete configuration reference for TLS profiles, cipher suites, mTLS, OCSP, and CRL settings
Production deployment guide including TLS best practices and high availability
Store TLS private keys and other credentials in an external secret provider
# Architecture
Source: https://docs.strata.io/introduction/architecture
Maverics has two core components -- the **Orchestrator**, a lightweight, self-hosted runtime that handles identity workflows, and the **Console**, a cloud SaaS platform for configuration and deployment management. The Orchestrator operates in five modes, each addressing a different identity protocol or deployment pattern.
```mermaid theme={null}
flowchart TB
Console["Maverics Console (Cloud SaaS)"]
Console -->|"Publishes signed config bundles"| Orch
Orch["Orchestrator (Self-hosted)"]
Orch --> OIDC["OIDC Provider"]
Orch --> SAML["SAML Provider"]
Orch --> Proxy["HTTP Proxy"]
Orch --> LDAP["LDAP Provider"]
Orch --> AI["AI Identity Gateway"]
```
## The Orchestrator
The Orchestrator is a lightweight, self-hosted runtime deployed alongside your applications. It coordinates identity workflows -- authentication, authorization, and protocol translation -- without requiring changes to application code.
The Orchestrator is stateless by design. It pulls its configuration from the Console (as signed bundles) or from local YAML files, making it easy to scale horizontally and deploy in any environment.
A single Orchestrator instance can operate in one or more of five modes simultaneously -- OIDC Provider, SAML Provider, HTTP Proxy, LDAP Provider, and AI Identity Gateway. Each mode addresses a specific identity protocol or deployment pattern.
## The Console
The Console is Strata Identity's cloud SaaS management platform, available at [maverics.strata.io](https://maverics.strata.io). It provides a visual interface for configuring Orchestrators, managing deployments, and monitoring identity workflows.
The Console is multi-tenant and multi-region. It publishes signed configuration bundles to Orchestrators -- ensuring that runtime configuration is cryptographically verified and tamper-resistant.
Key capabilities include visual point-and-click configuration, deployment management across environments, and audit logging for compliance and troubleshooting.
## Deployment Modes
The Orchestrator runs in one or more modes simultaneously on a single instance. Each mode is purpose-built for a specific identity protocol or pattern:
* **OIDC Provider** -- Modern web and mobile SSO with OpenID Connect, including claim enrichment and IdP failover
* **SAML Provider** -- Legacy enterprise federation with SAML 2.0 protocol translation
* **HTTP Proxy** -- Protect applications without code modification by intercepting HTTP traffic
* **LDAP Provider** -- Virtual directory for LDAP-dependent applications migrating to modern identity
* **AI Identity Gateway** -- AI agent identity via MCP Bridge and MCP Proxy
## How They Work Together
The Console publishes configuration, and the Orchestrator consumes it at runtime. This separation of control plane (Console) and data plane (Orchestrator) means your identity traffic never leaves your infrastructure -- only configuration flows through the cloud.
You can configure the Orchestrator through the Console UI or YAML files. Both interfaces manage the same underlying Orchestrator, so you can choose the workflow that fits your team. The Orchestrator runs wherever your applications run -- cloud, on-premises, or hybrid environments.
## What's Next
Explore core concepts in detail -- modes, interfaces, and deployment models.
Detailed Orchestrator installation, configuration, and operational reference.
# Concepts
Source: https://docs.strata.io/introduction/concepts
This page covers the foundational concepts behind Maverics -- modes, interfaces, and deployment models. Each concept links to detailed reference documentation for deeper exploration.
## Modes
The Orchestrator operates in five modes, each addressing a different identity protocol or deployment pattern.
| Mode | Protocol | Use Case |
| ----------------------- | -------------- | ---------------------------------------------------------------- |
| **OIDC Provider** | OpenID Connect | Modern web and mobile SSO with claim enrichment and IdP failover |
| **SAML Provider** | SAML 2.0 | Legacy enterprise federation with protocol translation |
| **HTTP Proxy** | HTTP | Protect applications without code modification |
| **LDAP Provider** | LDAP | Virtual directory for LDAP-dependent applications |
| **AI Identity Gateway** | MCP | AI agent identity via MCP Bridge and MCP Proxy |
Modes can run simultaneously on a single Orchestrator instance -- deploy one binary that handles OIDC, SAML, and LDAP at the same time.
## Interfaces
Two interfaces configure the same Orchestrator -- choose the one that fits your workflow.
| Interface | Best For | Description |
| ------------------------ | ------------------------- | --------------------------------------------------------------------------------------------------------- |
| **Console UI** | Visual configuration | Web-based management at maverics.strata.io -- point-and-click setup, deployment management, audit logging |
| **Configuration (YAML)** | Declarative configuration | Local configuration files checked into version control -- ideal for GitOps workflows |
Both interfaces configure the same underlying Orchestrator -- changes made in one are reflected in the other.
## Deployment Models
The Orchestrator is designed to run wherever your applications run. Three deployment models cover the most common environments:
* **Cloud** -- Orchestrator runs in cloud infrastructure (AWS, Azure, GCP) alongside cloud-native applications. Ideal for teams with fully cloud-based identity stacks.
* **On-premises** -- Orchestrator runs in data centers alongside legacy applications. Critical for enterprises with mainframe, LDAP, or on-prem web applications that cannot migrate to the cloud.
* **Hybrid** -- A mix of cloud and on-premises Orchestrators managed from a single Console. This is the most common model for enterprises modernizing incrementally.
The Console is always cloud-hosted (SaaS) regardless of where Orchestrators are deployed.
## What's Next
Deploy your first Orchestrator and route an authentication request in minutes.
Detailed reference documentation for each Orchestrator mode.
# FAQ
Source: https://docs.strata.io/introduction/faq
Common questions about the Maverics platform organized by topic. Can't find your answer? [Contact support](https://strataidentity.my.site.com/support/s/).
## General
Maverics is an identity orchestration platform from Strata Identity. It consists of two components: the Orchestrator (a lightweight identity abstraction layer deployed in your infrastructure) and the Console (a cloud-hosted management interface). Together they let you route, translate, and manage authentication across any combination of identity providers, protocols, and applications.
The Orchestrator supports OIDC, SAML 2.0, LDAP, HTTP header-based authentication, and the Model Context Protocol (MCP) for AI identity. It can translate between these protocols, so a SAML application can authenticate against an OIDC provider (or vice versa) without application changes.
The Identity Fabric is an architectural pattern where a lightweight abstraction layer (the Orchestrator) sits between applications and identity providers. It decouples applications from specific identity vendors, enabling incremental migration, protocol translation, and policy-based routing without modifying application code.
No. Maverics is a commercial product. Contact [Strata Identity sales](https://strataidentity.my.site.com/support/s/) for licensing information.
## Getting Started
The Orchestrator is distributed as a single binary and can run on Linux, in Docker containers, or on Kubernetes. Download it from the Console, deploy it to your environment, and point it at your configuration. See the [Quick Start guide](/guides/getting-started/quick-start) for step-by-step instructions.
The Console is the recommended way to use Maverics. It provides visual configuration, centralized deployment management, audit logging, and config bundle publishing with cryptographic signing. While the Orchestrator can technically run standalone with local YAML files, the Console streamlines operations significantly and is how most customers manage their deployments.
The Orchestrator is lightweight and runs on Linux (x86\_64 and ARM64), in Docker containers, or on Kubernetes. Specific resource requirements depend on traffic volume and the number of configured applications.
## Architecture
The Orchestrator runs in your infrastructure -- on-premises, in the cloud (AWS, Azure, GCP), or both. It deploys as a lightweight binary alongside your applications. The Console is always cloud-hosted (SaaS).
Yes. You can deploy multiple Orchestrator instances for high availability, geographic distribution, or workload isolation. All instances are managed from a single Console.
Configuration is managed through the Console UI (visual, point-and-click) or YAML files (declarative, version-controlled). Both interfaces configure the same Orchestrator, so changes made in one are reflected in the other.
A Config Bundle is a cryptographically signed package of configuration that the Console publishes to Orchestrators. Bundles are signed with ECDSA P-256 and verified by the Orchestrator before deployment, ensuring configuration integrity.
## Security
Maverics integrates with external secret providers (HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, CyberArk, Conjur, and Delinea). Secrets are never stored in configuration files -- the Orchestrator fetches them at runtime from your chosen provider.
Yes. All communication between the Console and Orchestrators uses TLS. Config Bundles are additionally signed (ECDSA P-256) so the Orchestrator can verify they have not been tampered with.
Visit the [Strata Trust Center](https://trust.strata.io) for current certifications, security practices, and compliance documentation.
## Licensing
Contact [Strata Identity](https://strataidentity.my.site.com/support/s/) for licensing details. Licensing terms depend on deployment scale and use case.
Contact [Strata Identity sales](https://strataidentity.my.site.com/support/s/) to discuss trial options.
# Getting Started
Source: https://docs.strata.io/introduction/getting-started
New to Maverics? Start here. This page walks you through getting access to the Console and setting up your organization -- the foundation for everything else you'll do with Maverics.
## Step 1: Get Access to the Console
The [Maverics Console](https://maverics.strata.io) is the management hub for your Maverics deployments. To get started:
1. **Request access** -- Contact your Strata account team or visit [Strata support](https://strataidentity.my.site.com/support/s/) to request a Console account for your organization
2. **Accept your invitation** -- You'll receive an email invitation to join your organization
3. **Log in** -- Sign in to the Console at [maverics.strata.io](https://maverics.strata.io)
## Step 2: Set Up Your Organization
Once you're logged in, orient yourself with the Console:
* **Organization settings** -- Review your organization name and member list under **Settings**
* **Invite team members** -- Add colleagues who will help manage deployments and configurations
* **Review audit logging** -- Every action in the Console is captured in the [audit log](/reference/console/audit-logs) for compliance and troubleshooting
## Step 3: Explore the Console
With your organization set up, take a moment to explore the Console:
* **Deployments** -- View and manage your Orchestrator deployments, each pairing a configuration with one or more running nodes
* **Configuration** -- Browse the visual configuration editor where you define apps, routes, connectors, and policies
* **Audit logs** -- Review a complete record of every action taken in your organization for compliance and troubleshooting
## Next Steps
Your Console organization is set up and ready to go. Follow the hands-on guides to install the Orchestrator and configure your first identity workflow:
Install the Orchestrator, connect an identity provider, and protect your first route
Build a complete deployment with SSO, session management, and header-based identity propagation
Understand how the Orchestrator, Console, and identity connectors work together
Learn the key concepts -- modes, connectors, apps, routes, and policies
# Glossary
Source: https://docs.strata.io/introduction/glossary
Key terms used throughout the Maverics documentation. Terms are listed alphabetically.
### App
A configuration unit in the Orchestrator that represents a workload. Apps have a type that determines their behavior: HTTP Proxy, OIDC, SAML, MCP Bridge, or MCP Proxy. Some app types (such as HTTP Proxy) define Routes for path-based request handling, while others (such as OIDC or MCP Bridge) operate at the app level without routes.
***
### Audit Log
A record of actions and events captured by the Console and Orchestrator. Console audit logs track API-level administrative actions (configuration changes, deployments, user management) while the Orchestrator emits structured logs for runtime authentication and authorization events as part of its telemetry output. See [Console Audit Logs](/reference/console/audit-logs) and [Orchestrator Telemetry](/reference/orchestrator/telemetry).
***
### Break-Glass
Emergency procedures for making Orchestrator configuration changes outside the normal Console workflow when Console access is unavailable. Break-glass trades some security guarantees for operational continuity. See [Break-Glass procedures](/reference/console/break-glass).
***
### Cache
A storage backend used by the Orchestrator for temporary data such as session state, tokens, and IdP metadata. Supported cache backends include Redis. See [Caches reference](/reference/orchestrator/caches).
***
### Claim
A user identity attribute -- such as email, name, roles, or group membership -- passed from identity providers to applications inside tokens or assertions. The Orchestrator can enrich claims by pulling additional attributes from LDAP directories, databases, or APIs, and map them into the format each application expects.
***
### Config Bundle
A compiled package of Orchestrator configuration published from the Console. Config bundles are cryptographically signed (ECDSA P-256) before deployment, and the Orchestrator verifies the signature as part of its validation before applying the new configuration. See [Config Publishing](/reference/console/config-publishing).
***
### Config Source
The location from which the Orchestrator loads its configuration. Supported sources include local files, environment variables, the Console, S3, Azure Blob Storage, GCS, GitHub, and GitLab. See [Config Sources reference](/reference/orchestrator/configuration/config-sources).
***
### Connector
An integration that connects the Orchestrator to an external identity provider (IdP). Connectors abstract the protocol details (OIDC, SAML, LDAP) so the Orchestrator can work with any provider through a uniform interface. See [Identity Fabric reference](/reference/orchestrator/identity-fabric).
***
### Console
The cloud-hosted (SaaS) management interface for Maverics. Provides visual configuration, deployment management, and audit logging at [maverics.strata.io](https://maverics.strata.io). See [Console reference](/reference/console/overview).
***
### Custom API
An HTTP endpoint defined directly in the Orchestrator configuration using service extensions. Custom APIs receive the full Orchestrator interface -- sessions, caches, secrets, and connectors -- for building health endpoints, webhooks, or custom integration logic. Custom APIs are configured as part of the Orchestrator's service extensions.
***
### Deployment
A managed Orchestrator instance in the Console that pairs configuration with one or more running Orchestrator nodes. Deployments are typically named by purpose (e.g., "Auth Provider", "AI Identity Gateway", "xyz-app-proxy"). An environment may contain multiple deployments, and Console organizations can be used to separate environments.
***
### Failover
Automatic fallback from a primary identity provider to one or more backup providers when the primary becomes unavailable. The Orchestrator tries connectors in configured order, routing authentication to the next available provider without requiring application changes. See [Concepts](/introduction/concepts).
***
### Feature Flag
A configuration toggle that enables experimental or gated features in the Orchestrator. Feature flags prevent accidental use of alpha or beta capabilities in production. Feature flags are set under the `features` key in the Orchestrator configuration.
***
### Identity Fabric
The collection of identity providers, directories, and authentication systems an organization uses to manage access -- Entra ID, Active Directory, Okta, LDAP directories, and others. The Maverics Orchestrator connects to this fabric through connectors, abstracting protocol differences and enabling protocol translation, incremental migration, and policy-based routing without modifying applications. See [Identity Fabric reference](/reference/orchestrator/identity-fabric).
***
### MCP (Model Context Protocol)
An open standard protocol for AI agent-to-tool communication. MCP enables AI agents to discover and invoke tools through a structured interface. The Orchestrator supports MCP through its AI Identity Gateway mode. See [AI Identity Gateway](/reference/modes/ai-identity-gateway).
***
### MCP Bridge
An AI Identity Gateway capability that translates REST APIs into MCP tools. The Orchestrator reads OpenAPI specifications and automatically generates MCP tool definitions, allowing AI agents to discover and call REST APIs through the MCP protocol without any API changes. See [MCP Bridge reference](/reference/orchestrator/applications/mcp-bridge).
***
### MCP Proxy
An AI Identity Gateway capability that proxies connections to existing MCP servers while injecting identity context and enforcing authorization on every tool invocation. Used when MCP servers already exist but need identity awareness. See [MCP Proxy reference](/reference/orchestrator/applications/mcp-proxy).
***
### MRN (Maverics Record Number)
A unique identifier assigned to every resource managed by the Maverics platform. MRNs follow a colon-delimited format that encodes region, organization, resource type, and resource ID: `maverics::::`. For example: `maverics:us-east:05951629-da9a-41e6-8364-5b0dc4b95884:deployments:2a476eb8-03b5-43d2-afc8-8c44c5a8a304`.
***
### Mode
The operating mode of the Orchestrator, which determines what identity protocol it handles. Available modes: OIDC Provider, SAML Provider, HTTP Proxy, LDAP Provider, and AI Identity Gateway. A single Orchestrator can run multiple modes simultaneously. See [Concepts](/introduction/concepts).
***
### OPA (Open Policy Agent)
A policy engine that evaluates authorization decisions using the Rego policy language. Used by the Orchestrator for fine-grained access control on API endpoints, MCP tool invocations, and advanced authorization scenarios. See [Authorization Policies guide](/guides/security/policies).
***
### Orchestrator
The core runtime component of Maverics. A lightweight binary deployed in your infrastructure (on-premises, cloud, or hybrid) that intercepts, routes, and translates authentication requests between applications and identity providers. See [Orchestrator reference](/reference/orchestrator/overview).
***
### Policy
A rule that determines whether an authenticated user or agent can access a specific resource. Policies evaluate user attributes, roles, and request context to make authorization decisions. The Orchestrator supports rule-based policies (role checks, attribute matching) and code-based policies (OPA/Rego). See [Authorization Policies guide](/guides/security/policies).
***
### Protocol Translation
The Orchestrator's ability to convert between identity protocols -- OIDC, SAML, LDAP, and HTTP headers -- transparently. For example, a SAML-only application can authenticate users from an OIDC identity provider, or an LDAP-dependent application can authenticate against a cloud IdP, without modifying either side.
***
### Provider
An Orchestrator operating mode where it acts as an identity provider. In OIDC Provider mode, the Orchestrator issues OpenID Connect tokens. In SAML Provider mode, it issues SAML assertions. Applications connect to the Orchestrator as their IdP, and the Orchestrator handles upstream authentication, protocol translation, and claim enrichment behind the scenes.
***
### Route
A path-based rule within an App that determines how the Orchestrator handles requests matching a specific URL pattern. Routes define authentication requirements, upstream targets, and policy enforcement.
***
### Secret Provider
An external secrets management service that the Orchestrator integrates with to retrieve sensitive values (API keys, certificates, passwords) at runtime. Supported providers include HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, CyberArk, Conjur, and Delinea. See [Secret Providers reference](/reference/orchestrator/configuration/secret-providers).
***
### Service Extension
Custom logic that extends the Orchestrator's behavior at specific points in the request processing pipeline. Service Extensions allow developers to add custom authentication, authorization, or transformation logic.
***
### Session
Server-side state maintained by the Orchestrator for authenticated users. Sessions track authentication status, tokens, and user attributes across requests. See [Sessions reference](/reference/orchestrator/sessions).
***
### SOID (Secure Orchestrator ID)
A stable identifier that uniquely identifies each Orchestrator instance in a deployment. The SOID is automatically derived at startup -- no manual setup is required. It remains stable across restarts on the same machine as long as the Orchestrator points to the same deployment in the Console (or the same local config file path when not using the Console). A 10-character prefix of the SOID appears as the `soid` field in every log entry, enabling log correlation across restarts and instance filtering in multi-node deployments. Available starting in **v2026.03.3**. See [Logging — Deployment Correlation](/reference/orchestrator/telemetry/logging#deployment-correlation).
***
### TLS Profile
A named TLS configuration in the Orchestrator that specifies certificates, cipher suites, and minimum protocol versions for encrypted connections. See [TLS reference](/guides/security/tls).
***
### Token Exchange
The process of exchanging one security token for another, following RFC 8693. Used for delegation (preserving both agent and user identity) or impersonation (acting on behalf of a user) scenarios. Common in AI Identity Gateway mode where agent tokens are exchanged for service-specific scoped tokens.
# Welcome to Maverics
Source: https://docs.strata.io/introduction/overview
Maverics is Strata Identity's orchestration platform for modern, legacy, and AI identity. The **Orchestrator** -- a lightweight identity abstraction layer -- routes authentication and authorization between your applications and any identity provider, while the **Maverics Console** provides a visual interface for managing connectors, policies, and configurations.
### Why Maverics
* **Extend identity to AI** -- Connect enterprise identity to MCP servers and AI-powered applications through the AI Identity Gateway without rebuilding your identity infrastructure from scratch.
* **Vendor independence** -- Work with any identity provider, any protocol. Maverics translates bidirectionally between SAML, OIDC, LDAP, and header-based auth so you're never locked into a single vendor's ecosystem.
* **Identity Continuity** -- Maverics monitors IdP health and automatically fails over to a backup when an outage is detected. Multi-tier resilience options range from basic failover to [tactical edge deployments](/guides/identity-continuity/reducing-spofs) that operate autonomously when cloud connectivity is severed.
* **Modernize apps without code changes** -- Add SSO, MFA, and authorization policies to applications that don't natively support them. Maverics acts as an identity-aware reverse proxy so applications need zero modification.
* **Data stays in your environment** -- Maverics is self-hosted inside your infrastructure. Authentication traffic -- tokens, credentials, user attributes -- never leaves your environment. Only configuration flows through the cloud.
* **Zero-downtime migration** -- Migrate between identity providers incrementally. Maverics routes authentication between old and new providers simultaneously so you can move users at your own pace with no rip-and-replace.
* **Programmable at every layer** -- [Service extensions](/reference/orchestrator/service-extensions) give you 30+ hook points across the authentication and authorization lifecycle with an embedded Go runtime. Customize request handling, build custom API endpoints, or integrate with any external system.
## What You Can Do
Maverics handles the identity complexity so you can focus on your applications.
Move users from one identity provider to another incrementally, with zero downtime and no application changes.
Add SAML or OIDC single sign-on to legacy applications that only support header-based or forms-based authentication, without modifying application code.
Enforce fine-grained authorization policies on API endpoints using OAuth 2.0 token validation, claim-based routing, and policy evaluation.
Extend enterprise identity and authorization to MCP servers and AI-powered applications through the AI Identity Gateway.
Unify identity across AWS, Azure, GCP, and on-premises environments through a single orchestration layer.
## Who Is Maverics For
Tired of risky, all-or-nothing identity migrations? Use Maverics to migrate users between identity providers incrementally, configure SSO federation across protocols, and manage authentication policies -- all without custom code or application changes.
Struggling with identity sprawl across environments? Deploy the Orchestrator as a lightweight identity abstraction layer, manage configuration with YAML and GitOps, and integrate with your existing secrets and caching infrastructure.
Need identity in your applications without becoming an IAM expert? Maverics simplifies application design with an extensible identity layer, built-in AI identity support, and standard protocol handling -- so you can focus on features, not auth plumbing.
## Security & Compliance
Deploy in your own infrastructure with full control over secrets, certificates, and network policies. Nothing leaves your environment unless you choose it.
Configuration bundles are cryptographically signed and verified before every deployment, ensuring only authorized changes reach your Orchestrators.
Every authentication event, configuration change, and administrative action is logged for compliance reporting and forensic analysis.
Certifications, security practices, penetration testing results, and compliance documentation.
## Explore the Docs
The documentation is organized by what you're trying to accomplish.
Deploy your first Orchestrator and route an authentication request in minutes.
Understand how the Orchestrator, Console, and identity providers fit together.
Step-by-step walkthroughs for authentication, AI identity, operations, and security.
Operating modes, configuration, route handling, and runtime behavior.
Identity providers, config sources, secret providers, caches, and sessions.
Complete configuration reference for apps, connectors, policies, and service extensions.
Watch video walkthroughs covering setup, configuration, and common workflows.
# The Identity Heroes Podcast
Source: https://docs.strata.io/introduction/videos/identity-heroes
The Identity Heroes brings real stories from the frontlines of identity to life. Hear from architects, CISOs, and practitioners as they share authentic insights and tactical lessons. Curious, smart, and a little rebellious, this series celebrates the people solving today's toughest identity challenges.
Follow The Identity Heroes playlist for new episodes
## Latest Episode
**Episode 9** -- Ian Glazer explores how decades of identity work are being reshaped by new paradigms, what's changing in the standards landscape, and why the old playbooks no longer apply.
## All Episodes
# API Clients
Source: https://docs.strata.io/reference/console/api-clients
API clients are [confidential OAuth 2.0 clients](https://datatracker.ietf.org/doc/html/rfc6749#section-2.1) that use the [client credentials grant](https://datatracker.ietf.org/doc/html/rfc6749#section-4.4) to automate the Maverics platform via its public APIs. API clients are passwordless. Authentication is done via [JWT client assertions](https://datatracker.ietf.org/doc/html/rfc7523) signed with a private key.
## Prerequisites
* **Organization owner role** -- Required to create, edit, or revoke API clients and their key pairs.
* **HTTPS client** -- e.g., `curl` or any HTTP library.
## Create an API Client
Click your profile in the upper-right corner of the Console, then click **Organizations**. Select the organization you want to manage. Locate the **API Clients** section on the organization page.
Click **Create**. Enter a **Name** (required) and an optional **Description** (e.g., "CI deploy bot"). Click **Create** to save.
With the API client settings open, click **Add Key Pair**. The Console generates a key pair on the server, displays the fingerprint, and prompts you to download the private key as a PEM file.
Click **Download Private Key**, then click **Done** to close the modal. Store the file securely -- treat it like any other production secret.
The private key is delivered to your browser only at creation time and is not stored by Strata. If the file is lost, revoke the key pair and add a new one.
You can attach multiple key pairs to a single client to support rotation. Revoke an individual key pair from the API client settings without affecting others.
## Obtain an Access Token
API clients authenticate to the token endpoint using the OAuth 2.0 client credentials grant ([RFC 6749 §4.4](https://datatracker.ietf.org/doc/html/rfc6749#section-4.4)) with a JWT client assertion ([RFC 7523](https://datatracker.ietf.org/doc/html/rfc7523)). The assertion proves possession of the client's private key without transmitting it.
### Discover the Token Endpoint
The auth endpoint is region-specific. Discover it from the OpenID Connect discovery document for your environment:
| Environment | Discovery document |
| ----------- | ------------------------------------------------------------------- |
| US | `https://auth.us-east-2.strata.io/.well-known/openid-configuration` |
| UK | `https://auth.eu-west-2.strata.io/.well-known/openid-configuration` |
Read the `token_endpoint` field from the discovery response and use its value as the destination for all token requests. Always take the endpoint from discovery rather than hardcoding the path, as it is the authoritative source.
### Build the Client Assertion
Construct a JWT signed with your client's private key using the `ES256` algorithm.
**JWS header:**
| Field | Value |
| ----- | ------- |
| `alg` | `ES256` |
| `typ` | `JWT` |
**JWT claims:**
| Claim | Description |
| ----- | -------------------------------------------------------------- |
| `iss` | Your API client ID (e.g., `client_`). |
| `sub` | Your API client ID. Must equal `iss`. |
| `aud` | The token endpoint URL from discovery. |
| `exp` | Expiry timestamp (seconds since epoch). Must be in the future. |
Inspect an [example assertion on jwt.io](https://jwt.io/#token=eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJodHRwczovL2F1dGgudXMtZWFzdC0yLnN0cmF0YS5pby9vYXV0aDIvdG9rZW4iLCJleHAiOjE3NzkyMTA3MzUsImlhdCI6MTc3OTIxMDQzNSwiaXNzIjoiY2xpZW50XzAwMDAwMDAwLTAwMDAtMDAwMC0wMDAwLTAwMDAwMDAwMDAwMCIsInN1YiI6ImNsaWVudF8wMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDAifQ.ASt3TuaKS_IjicOhfuC4hEle8oBFr-SFJSksCkqvN8maH8ZbnEe3ayuNKRq9fxMzxvtxkZVvOpUjMNA_dI4n3g) with the placeholder header and claims pre-populated.
### Send the Token Request
POST the assertion to the token endpoint with form-encoded parameters:
```bash theme={null}
curl -X POST https://auth..strata.io/oauth2/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer" \
-d "client_assertion="
```
A successful response returns an opaque bearer token:
```json theme={null}
{
"access_token": "eyJhbGciOi...",
"token_type": "Bearer",
"expires_in": 3600
}
```
Include the token in the `Authorization` header for subsequent API calls:
```
Authorization: Bearer
```
## Example code
Each tab builds a client assertion and exchanges it for an access token. Replace the placeholders with your client ID, private key path, and token endpoint.
```go theme={null}
// Run:
// go get github.com/go-jose/go-jose/v4
// CLIENT_ID= \
// KEY_PATH=client.pem \
// TOKEN_URL=https://auth..strata.io/oauth2/token \
// go run main.go
package main
import (
"crypto/ecdsa"
"crypto/x509"
"encoding/pem"
"fmt"
"io"
"net/http"
"net/url"
"os"
"strings"
"time"
"github.com/go-jose/go-jose/v4"
josejwt "github.com/go-jose/go-jose/v4/jwt"
)
func main() {
clientID := os.Getenv("CLIENT_ID")
keyPath := os.Getenv("KEY_PATH")
tokenURL := os.Getenv("TOKEN_URL")
pemBytes, _ := os.ReadFile(keyPath)
block, _ := pem.Decode(pemBytes)
raw, _ := x509.ParsePKCS8PrivateKey(block.Bytes)
key := raw.(*ecdsa.PrivateKey)
signer, _ := jose.NewSigner(
jose.SigningKey{Algorithm: jose.ES256, Key: key},
(&jose.SignerOptions{}).WithType("JWT"),
)
now := time.Now()
claims := josejwt.Claims{
Issuer: clientID,
Subject: clientID,
Audience: josejwt.Audience{tokenURL},
IssuedAt: josejwt.NewNumericDate(now),
Expiry: josejwt.NewNumericDate(now.Add(5 * time.Minute)),
}
assertion, _ := josejwt.Signed(signer).Claims(claims).Serialize()
form := url.Values{
"grant_type": {"client_credentials"},
"client_assertion_type": {"urn:ietf:params:oauth:client-assertion-type:jwt-bearer"},
"client_assertion": {assertion},
}
resp, _ := http.Post(tokenURL, "application/x-www-form-urlencoded", strings.NewReader(form.Encode()))
defer resp.Body.Close()
// The response body contains the access token (JSON: access_token, token_type, expires_in).
body, _ := io.ReadAll(resp.Body)
fmt.Println("status:", resp.Status)
fmt.Println(string(body))
}
```
```python theme={null}
# Run:
# pip install "PyJWT[crypto]" requests
# CLIENT_ID= \
# KEY_PATH=client.pem \
# TOKEN_URL=https://auth..strata.io/oauth2/token \
# python main.py
import os
import time
import jwt
import requests
CLIENT_ID = os.environ["CLIENT_ID"]
KEY_PATH = os.environ["KEY_PATH"]
TOKEN_URL = os.environ["TOKEN_URL"]
with open(KEY_PATH, "rb") as f:
private_key = f.read()
now = int(time.time())
claims = {
"iss": CLIENT_ID,
"sub": CLIENT_ID,
"aud": TOKEN_URL,
"iat": now,
"exp": now + 300,
}
assertion = jwt.encode(claims, private_key, algorithm="ES256")
resp = requests.post(
TOKEN_URL,
data={
"grant_type": "client_credentials",
"client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
"client_assertion": assertion,
},
)
print(resp.status_code, resp.json())
```
```typescript theme={null}
// Run:
// npm install jose
// CLIENT_ID= \
// KEY_PATH=client.pem \
// TOKEN_URL=https://auth..strata.io/oauth2/token \
// npx tsx main.ts
import { readFile } from "node:fs/promises";
import { SignJWT, importPKCS8 } from "jose";
const CLIENT_ID = process.env.CLIENT_ID!;
const KEY_PATH = process.env.KEY_PATH!;
const TOKEN_URL = process.env.TOKEN_URL!;
interface TokenResponse {
access_token: string;
token_type: string;
expires_in: number;
}
const pem = await readFile(KEY_PATH, "utf8");
const key = await importPKCS8(pem, "ES256");
const assertion = await new SignJWT({})
.setProtectedHeader({ alg: "ES256", typ: "JWT" })
.setIssuer(CLIENT_ID)
.setSubject(CLIENT_ID)
.setAudience(TOKEN_URL)
.setIssuedAt()
.setExpirationTime("5m")
.sign(key);
const resp = await fetch(TOKEN_URL, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
grant_type: "client_credentials",
client_assertion_type:
"urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
client_assertion: assertion,
}),
});
const data = (await resp.json()) as TokenResponse;
console.log(resp.status, data);
```
```rust theme={null}
// Run:
// Cargo.toml dependencies:
// jsonwebtoken = "9"
// reqwest = { version = "0.12", features = ["rustls-tls"] }
// serde = { version = "1", features = ["derive"] }
// tokio = { version = "1", features = ["full"] }
// CLIENT_ID= \
// KEY_PATH=client.pem \
// TOKEN_URL=https://auth..strata.io/oauth2/token \
// cargo run --release
use std::env;
use std::fs;
use std::time::{SystemTime, UNIX_EPOCH};
use jsonwebtoken::{encode, Algorithm, EncodingKey, Header};
use serde::Serialize;
#[derive(Serialize)]
struct Claims {
iss: String,
sub: String,
aud: String,
iat: u64,
exp: u64,
}
#[tokio::main]
async fn main() -> Result<(), Box> {
let client_id = env::var("CLIENT_ID")?;
let key_path = env::var("KEY_PATH")?;
let token_url = env::var("TOKEN_URL")?;
let pem = fs::read(&key_path)?;
let key = EncodingKey::from_ec_pem(&pem)?;
let now = SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs();
let claims = Claims {
iss: client_id.clone(),
sub: client_id,
aud: token_url.clone(),
iat: now,
exp: now + 300,
};
let mut header = Header::new(Algorithm::ES256);
header.typ = Some("JWT".into());
let assertion = encode(&header, &claims, &key)?;
let resp = reqwest::Client::new()
.post(&token_url)
.form(&[
("grant_type", "client_credentials"),
(
"client_assertion_type",
"urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
),
("client_assertion", &assertion),
])
.send()
.await?;
println!("{} {}", resp.status(), resp.text().await?);
Ok(())
}
```
## Common Errors
| Status | Error | Likely Cause |
| ------ | ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| 400 | `invalid_client` -- `invalid client` | The `sub` claim does not match a registered API client in the requested region. |
| 400 | `invalid_client` -- `invalid JWT signature` | The signature does not verify against any registered public key for this client. Confirm you are signing with the matching private key. |
| 400 | `invalid_client` -- `failed to parse JWT` | The assertion is malformed. Verify it is a compact-serialized JWS with three base64url-encoded segments. |
| 400 | `invalid_request` | Missing or malformed form parameter. Confirm `grant_type`, `client_assertion_type`, and `client_assertion` are all present and well-formed. |
## Rotate or Revoke
* **Rotate** -- Add a new key pair while the existing one is still active, switch your client to the new private key, then revoke the old key pair.
* **Revoke a key pair** -- Open the client drawer and click the revoke icon next to the key pair. Tokens issued before revocation remain valid until they expire.
* **Delete the client** -- Removes the client and all of its key pairs. The platform will begin rejecting new token requests for the deleted client.
## Related Pages
* [User Management](/reference/console/user-management) -- Organization roles required to administer API clients.
* [Audit Logs](/reference/console/audit-logs) -- API client lifecycle events appear in the audit log.
# Audit Logs
Source: https://docs.strata.io/reference/console/audit-logs
Audit Logs is a beta feature. This feature is functional and supported, but is still undergoing regular changes. Audit logging requires enablement for your organization -- contact your Strata account team or [Strata support](https://strataidentity.my.site.com/support/s/) to enable it.
Console audit logs give you a complete record of every administrative action taken in your Maverics Console. Whether you need to investigate a misconfigured deployment, demonstrate compliance to an auditor, or simply answer "who changed that?" -- audit logs provide the evidence.
## What Are Console Audit Logs?
Every action that administrators perform in the Console is recorded as a log entry -- who performed the action, what resource was affected, when it happened, and whether it succeeded or failed. Publishing a config bundle, inviting a team member, updating a deployment, uploading a TLS certificate -- each of these actions produces a structured audit record.
Audit logs matter for three reasons:
* **Compliance evidence** -- Audit logs provide the admin-action audit trail required by frameworks like SOC 2, HIPAA, and GDPR. They prove who made configuration changes, when, and whether those changes were authorized.
* **Security investigations** -- When something goes wrong -- a misconfigured policy, an unauthorized deployment publish -- audit logs let you trace the exact sequence of actions that led to the issue, including the actor, IP address, and timestamp.
* **Operational accountability** -- In multi-admin environments, audit logs establish clear ownership of every change. You can answer "who published that config?" or "who removed that team member?" without guessing.
### Console Logs vs. Orchestrator Logs
Console audit logs capture **management plane** actions: configuration changes, bundle publishing, team membership, organization settings -- everything administrators do in the Console UI. The Orchestrator, by contrast, captures **data plane** actions: user authentication events, authorization decisions, token issuance, and proxy requests -- everything that happens at runtime when end users interact with protected applications.
Together, Console audit logs and Orchestrator logs provide complete audit coverage across both administrative and runtime operations. For Orchestrator-side logging, see the [Compliance and Audit guide](/guides/security/compliance) and the [Telemetry Reference](/reference/orchestrator/telemetry).
### Accessing Audit Logs
Audit logs are accessible through the Console UI. You can filter by time range, event category, and specific event type to find relevant entries. JSON/CSV export and SIEM streaming are on the roadmap -- see [Export and Integration](#export-and-integration) below.
## Schema (v1.0)
Every audit log entry follows the v1.0 schema. The top-level structure contains identifying information, the event classification, and nested objects describing the actor, target, source, context, and request.
### Top-Level Fields
| Field | Type | Description |
| ----------- | ----------------- | ----------------------------------------------------------- |
| `id` | string (MRN) | Maverics Resource Notation identifier for the audit event |
| `version` | string | Schema version (currently `"1.0"`) |
| `timestamp` | string (RFC 3339) | When the event occurred |
| `eventType` | string | Specific event identifier (e.g., `deployment.publish`) |
| `category` | string | Event category (e.g., `deployment_management`) |
| `outcome` | object | Result of the action -- see [Outcome](#outcome) |
| `actor` | object | Who performed the action -- see [Actor](#actor) |
| `target` | object | What was acted upon -- see [Target](#target) |
| `source` | object | Where the request came from -- see [Source](#source) |
| `context` | object | Tracing and service information -- see [Context](#context) |
| `request` | object | HTTP request details -- see [Request](#request) |
| `metadata` | object | Additional event-specific data -- see [Metadata](#metadata) |
**MRN format:** The `id` field and `target.id` use Maverics Resource Notation (MRN), a structured identifier with the format:
```
maverics:{region}:{organization_id}:{resource_type}:{resource_id}
```
For example: `maverics:us-west-2:550e8400-e29b-41d4-a716-446655440000:audit-log:7c9e6679-7425-40de-944b-e07fc1f90ae7`
### Outcome
The outcome object records the result of the action.
| Field | Type | Description |
| ------------ | ------- | ----------------------------------------- |
| `status` | string | Outcome status (see values below) |
| `statusCode` | integer | HTTP status code of the response |
| `errorMsg` | string | Detailed error message for debugging |
| `reason` | string | Human-readable explanation of the outcome |
**Status values:**
| Value | Description |
| --------- | -------------------------------------------------------------------- |
| `success` | Action completed successfully |
| `failure` | Action failed due to validation or business logic |
| `partial` | Action partially completed (e.g., bulk operation with some failures) |
| `denied` | Action blocked by authorization policy |
| `error` | System error prevented action completion |
### Actor
The actor object identifies who performed the action.
| Field | Type | Description |
| ------------------ | ------ | -------------------------------------------------------- |
| `type` | string | Actor type (see values below) |
| `id` | string | Unique identifier (user ID, API key ID, or service name) |
| `email` | string | Actor's email address (for user and admin\_user actors) |
| `displayName` | string | Human-readable name |
| `organizationID` | string | Organization context for the action |
| `organizationName` | string | Organization name for readability |
**Actor types:**
| Value | Description |
| ------------ | ------------------------------------------------------ |
| `user` | Human user authenticated via UI or API |
| `admin_user` | Platform administrator authenticated via admin console |
| `api_key` | Programmatic access via API key |
| `system` | Automated system process (e.g., scheduled jobs) |
| `service` | Internal service-to-service calls |
### Target
The target object identifies what was acted upon.
| Field | Type | Description |
| ---------------- | ------ | ------------------------------------------------------------------- |
| `type` | string | Resource type (see values below) |
| `id` | string | MRN (Maverics Resource Notation) identifier for the target resource |
| `name` | string | Human-readable resource name |
| `organizationID` | string | Owning organization |
**Resource types:**
| Value | Description |
| --------------------- | ---------------------------------------- |
| `organization` | Organization/account |
| `organization_unit` | Organizational unit |
| `user` | User account |
| `membership` | Organization membership |
| `invitation` | User invitation |
| `deployment` | Deployment/environment |
| `deployment_revision` | Deployment revision/version |
| `identity_fabric` | Identity Fabric configuration |
| `application` | Application registration |
| `service` | Provider service (OIDC, SAML, LDAP, MCP) |
| `tls_config` | TLS configuration |
| `cache` | Deployment cache |
| `api_key` | API key |
| `service_extension` | Custom service extension |
| `orchestrator` | Orchestrator instance |
| `feature_flag` | Feature flag (global or account-level) |
| `sso_domain` | SSO domain configuration |
| `admin_user` | Platform administrator user |
| `database_migration` | Database migration job |
### Source
The source object records where the request originated.
| Field | Type | Description |
| ------------ | ------ | ------------------------------ |
| `ipAddress` | string | Client IP address |
| `userAgent` | string | Raw User-Agent header |
| `clientType` | string | Client type (see values below) |
**Client types:** `browser`, `api_client`, `sdk`, `service`, `unknown`
### Context
The context object provides tracing and service metadata for correlating events across services.
| Field | Type | Description |
| ---------------- | ------ | -------------------------------------- |
| `region` | string | Region where the request was processed |
| `service` | string | Service that handled the request |
| `serviceVersion` | string | Version of the service |
| `traceID` | string | Distributed trace identifier |
| `spanID` | string | Span identifier within the trace |
### Request
The request object captures HTTP-level details about the API call.
| Field | Type | Description |
| --------------- | ------- | ----------------------------------------------------------- |
| `method` | string | HTTP method (e.g., `GET`, `POST`, `PUT`, `DELETE`, `PATCH`) |
| `path` | string | Request URL path |
| `queryParams` | string | Query string parameters |
| `referrer` | string | HTTP Referer header value |
| `contentLength` | integer | Size of the request body in bytes |
| `contentType` | string | Content-Type header value |
The API uses camelCase JSON serialization for all fields (e.g., `eventType`, `statusCode`, `displayName`, `ipAddress`, `clientType`, `userAgent`, `traceID`, `spanID`, `queryParams`, `contentLength`, `contentType`).
### Metadata
The metadata object is a flexible key-value store for domain-specific context that doesn't fit the standard schema fields. The keys present in metadata vary by event type, providing additional detail relevant to the specific action.
#### Reserved Metadata Keys
The following keys have a defined meaning across all event types:
| Key | Type | Description |
| ---------------- | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `bulk_operation` | string (`"true"`) | Present when the audit log entry is part of a bulk action (e.g., deleting multiple applications in a single request). Each item in the bulk action gets its own audit log entry with this key set. Use `context.traceID` to correlate all entries from the same bulk request. |
#### Common Metadata Keys by Event Category
| Key | Type | Description |
| --------------- | ------ | --------------------------------------------- |
| `auth_method` | string | Authentication method used (e.g., `"sso"`) |
| `auth_provider` | string | Identity provider type (e.g., `"azure_oidc"`) |
| Key | Type | Description |
| -------------------------- | ------- | ------------------------------------------------------- |
| `deployment_is_production` | boolean | Whether the deployment targets a production environment |
| `revision_number` | integer | Revision number of the published config bundle |
| `bundle_hash` | string | SHA-256 hash of the published config bundle |
| Key | Type | Description |
| -------------- | ----- | --------------------------------------------------------------- |
| `invitedUsers` | array | List of users being invited, each containing `role` and `email` |
Example:
```json theme={null}
{
"invitedUsers": [
{
"role": "member",
"email": "user@example.com"
}
]
}
```
| Key | Type | Description |
| ----------------- | ------ | ------------------------------------------------------------------------------------ |
| `policy_action` | string | The policy action being evaluated (e.g., `"deployDeployment"`, `"deleteDeployment"`) |
| `policy_resource` | string | MRN of the resource the policy applies to |
| `required_roles` | array | Roles required to perform the denied action |
| Key | Type | Description |
| ---------------------- | ------ | ------------------------------------------------ |
| `identity_fabric_type` | string | Type of identity provider (e.g., `"azure_oidc"`) |
| Key | Type | Description |
| ----------------------- | ----------------- | ---------------------------------------------------------------- |
| `feature_name` | string | Name of the feature flag (e.g., `"orchestrator_telemetry"`) |
| `operation_scope` | string | Scope of the operation (e.g., `"global"`, `"account"`) |
| `confirmation_required` | boolean | Whether the action required explicit confirmation |
| `grace_period_hours` | integer | Hours before a deletion takes effect (e.g., `24`) |
| `can_cancel_until` | string (RFC 3339) | Deadline to cancel a pending deletion |
| `role_granted` | string | Role granted to a user (e.g., `"DSO"`) |
| `privilege_level` | string | Level of privilege associated with the role (e.g., `"elevated"`) |
Metadata keys are not guaranteed to be present on every event. They appear only when relevant to the specific action being recorded.
## Event Categories and Types
The Console captures over 65 distinct event types organized into 7 categories. Each event type represents a specific API action.
All operations related to creating, configuring, publishing, and managing Orchestrator deployments.
| Event Type | Description |
| -------------------------------- | -------------------------------------------------- |
| `deployment.list` | List all deployments |
| `deployment.create` | Create a new deployment |
| `deployment.update` | Update deployment settings |
| `deployment.view` | View deployment details |
| `deployment.delete` | Delete a deployment |
| `deployment.purge` | Permanently remove a deleted deployment |
| `deployment.publish` | Publish a config bundle to the deployment provider |
| `deployment.restore` | Restore a previously deleted deployment |
| `deployment.download` | Download the deployment's config bundle |
| `deployment.config.view` | View deployment configuration |
| `deployment.config.update` | Update deployment configuration |
| `deployment.config.download` | Download deployment configuration |
| `deployment.settings.update` | Update deployment-level settings |
| `deployment.storage.update` | Update the deployment's storage provider |
| `deployment.key.download` | Download the deployment's public key |
| `deployment.service.create` | Create a service extension |
| `deployment.service.view` | View a service extension |
| `deployment.service.update` | Update a service extension |
| `deployment.service.delete` | Delete a service extension |
| `deployment.service.jwks.create` | Create a JWKS entry for a service |
| `deployment.service.jwks.list` | List JWKS entries for a service |
| `deployment.service.jwks.delete` | Delete a JWKS entry for a service |
| `deployment.application.attach` | Attach an application to a deployment |
| `deployment.application.detach` | Detach an application from a deployment |
| `deployment.cache.create` | Create a cache configuration |
| `deployment.cache.list` | List cache configurations |
| `deployment.cache.delete` | Delete a cache configuration |
| `deployment.cache.update` | Update a cache configuration |
| `deployment.cache.view` | View a cache configuration |
| `deployment.tls.create` | Create a TLS certificate |
| `deployment.tls.list` | List TLS certificates |
| `deployment.tls.update` | Update a TLS certificate |
| `deployment.orchestrator.view` | View Orchestrator instance details |
| `deployment.revision.list` | List deployment revisions |
| `deployment.revision.view` | View a specific deployment revision |
Operations for managing organization settings and configuration.
| Event Type | Description |
| --------------------- | ---------------------------- |
| `organization.view` | View organization details |
| `organization.update` | Update organization settings |
| `organization.delete` | Delete an organization |
Operations for invitations, roles, team membership, and organizational units.
| Event Type | Description |
| -------------------------- | --------------------------------------- |
| `member.list` | List organization members |
| `member.invite` | Invite a new member to the organization |
| `member.remove` | Remove a member from the organization |
| `member.join` | A member accepts an invitation |
| `member.decline` | A member declines an invitation |
| `member.invitation.cancel` | Cancel a pending invitation |
| `member.role.update` | Update a member's role |
| `ownership.transfer` | Transfer organization ownership |
| `organization_unit.create` | Create an organizational unit |
| `organization_unit.update` | Update an organizational unit |
| `organization_unit.list` | List organizational units |
| `organization_unit.view` | View an organizational unit |
CRUD operations for applications managed through the Console.
| Event Type | Description |
| -------------------- | ------------------------ |
| `application.list` | List applications |
| `application.view` | View application details |
| `application.create` | Create a new application |
| `application.update` | Update an application |
| `application.delete` | Delete an application |
Operations for managing identity fabrics and service extensions.
| Event Type | Description |
| ------------------------ | ---------------------------- |
| `identity_fabric.list` | List identity fabrics |
| `identity_fabric.create` | Create an identity fabric |
| `identity_fabric.view` | View identity fabric details |
| `identity_fabric.update` | Update an identity fabric |
| `identity_fabric.delete` | Delete an identity fabric |
| `service_extension.list` | List service extensions |
TLS certificate management operations.
| Event Type | Description |
| ------------ | ---------------------------------- |
| `tls.list` | List TLS certificates |
| `tls.view` | View TLS certificate details |
| `tls.create` | Upload or create a TLS certificate |
| `tls.update` | Update a TLS certificate |
| `tls.delete` | Delete a TLS certificate |
User account operations.
| Event Type | Description |
| ------------- | --------------------- |
| `user.delete` | Delete a user account |
## Storage and Retention
Audit log storage is automatic when audit logging is enabled for your organization. There is no additional configuration required.
Logs are currently retained indefinitely and are accessible through the Console UI. A formal retention policy, including default retention periods, will be defined in a future release as export and SIEM streaming capabilities become available.
## Export and Integration
The following export capabilities are on the Strata product roadmap and are not yet available. Contact your Strata account team for the latest availability.
Planned export and integration capabilities for audit logs include:
* **JSON export** -- Download audit log data as JSON files for offline analysis and archival
* **CSV export** -- Export audit logs in CSV format for spreadsheet analysis and reporting
* **SIEM streaming** -- Stream audit log events to your cloud-based SIEM solution for centralized security monitoring and alerting
## Related Pages
Security and compliance best practices for Maverics deployments
Logger, telemetry, and health check configuration for the Orchestrator
Console administration overview and capabilities
# Break-Glass Procedures
Source: https://docs.strata.io/reference/console/break-glass
This page documents emergency procedures for making Orchestrator configuration changes when you need to work outside the normal Console workflow. These procedures trade security guarantees (bundle signing, audit trails) for operational continuity.
Break-glass procedures bypass normal security controls. Use them only when Console-managed changes are not possible or practical and configuration changes are urgently needed. Follow the [Recovery Checklist](#recovery-checklist) after returning to Console-managed operations to re-establish normal workflows.
## When to Use These Procedures
These procedures apply when you need to make Orchestrator configuration changes outside the normal Console workflow:
* **Console is unreachable** -- Network issues, DNS problems, regional connectivity disruption, or service interruption.
* **Account access issues** -- Your account is locked out, permissions have been revoked, or your SSO identity provider is down.
* **Team availability** -- The team member with Console access is unavailable during an emergency.
## Understanding the Constraint
The key constraint when working without Console access is **bundle signing**. The deployment's private signing key is stored only in the Console -- there is no API endpoint to export or download the private key. This means you cannot create new validly-signed bundles without Console access.
The Orchestrator verifies the ECDSA P-256 signature and SHA-256 hash of every file in the bundle before applying configuration. To apply configuration changes without Console access, you must switch to a local file configuration (Options 2 or 3 below), which uses a code path that does not perform signature verification.
The Orchestrator's tar.gz bundler always runs signature verification when loading a bundle -- there is no code path that skips verification based on an empty or missing public key. If `MAVERICS_BUNDLE_PUBLIC_KEY_FILE` is unset, the empty key causes a PEM decode failure rather than bypassing verification. This means you cannot load an unsigned tar.gz bundle by simply removing the signature and unsetting the key. The only way to bypass verification is to switch to a local file configuration, which uses a different bundler that does not perform signature checks.
## Immediate Impact: Working Without Console Access
When working without Console access:
* **No immediate disruption** -- The Orchestrator continues running with its last-known-good configuration.
* **No new publishes** -- Configuration cannot be published through the Console UI.
* **No new revisions** -- No diff previews, revision history, or audit log access.
* **Polling continues** -- The Orchestrator continues polling for new bundles but finds no changes.
If no configuration changes are needed, no action is required. The Orchestrator operates normally with its current configuration.
## Recovery Options
### Option 1: Continue with Current Configuration (No Action Needed)
The Orchestrator continues operating with the last successfully applied configuration. No intervention is required.
**How it works:**
* The Orchestrator keeps its current configuration in memory and continues serving traffic.
* If the Orchestrator restarts, it re-downloads and re-verifies the last bundle from the deployment provider.
* The signed bundle in the deployment provider's storage remains valid and available.
**When to use this option:**
* No configuration changes are needed while working without Console access.
* The current configuration is working correctly.
**Limitations:**
* No way to make any configuration changes until Console access is available.
***
### Option 2: Extract Configuration from Bundle and Switch to Local File
Download the current bundle from the deployment provider, extract the configuration file, and switch the Orchestrator to load it as a local file. This approach lets you make targeted changes to your existing configuration without needing to write a config from scratch.
**Steps:**
Download `maverics.tar.gz` from your deployment provider's storage location (S3 bucket, Azure Blob container, GCS bucket, or Git repository).
```bash theme={null}
# Example: AWS S3
aws s3 cp s3://your-bucket/path/maverics.tar.gz ./maverics.tar.gz
# Example: Azure Blob
az storage blob download --container-name your-container --name maverics.tar.gz --file ./maverics.tar.gz
# Example: GCS
gsutil cp gs://your-bucket/path/maverics.tar.gz ./maverics.tar.gz
```
```bash theme={null}
mkdir bundle && cd bundle
tar -xzf ../maverics.tar.gz
```
Edit `maverics.json` with the needed configuration changes.
```bash theme={null}
# Edit the configuration
vi maverics.json
```
```bash theme={null}
# Copy the extracted config to the Orchestrator host
scp maverics.json orchestrator-host:/etc/maverics/maverics.json
```
Point the Orchestrator to the local config file instead of the cloud/Git provider. Remote config source environment variables (`MAVERICS_AWS_CONFIG`, `MAVERICS_AZURE_CONFIG`, `MAVERICS_GCP_CONFIG`, `MAVERICS_GITHUB_CONFIG`, `MAVERICS_GITLAB_CONFIG`) take priority over `MAVERICS_CONFIG`. You **must** unset the remote provider variable for your deployment before setting `MAVERICS_CONFIG`, otherwise the Orchestrator will ignore the local file.
```bash theme={null}
# Unset the remote config source for your provider (pick the one matching your deployment)
# unset MAVERICS_AWS_CONFIG
# unset MAVERICS_AZURE_CONFIG
# unset MAVERICS_GCP_CONFIG
# unset MAVERICS_GITHUB_CONFIG
# unset MAVERICS_GITLAB_CONFIG
export MAVERICS_CONFIG=/etc/maverics/maverics.json
unset MAVERICS_BUNDLE_PUBLIC_KEY_FILE
sudo systemctl restart maverics
```
The Orchestrator now loads configuration from the local file instead of polling the deployment provider.
```bash theme={null}
sudo systemctl status maverics
```
This approach is functionally equivalent to Option 3 but starts from your existing bundle configuration rather than a new YAML file. The extracted `maverics.json` file uses JSON format, which the Orchestrator accepts alongside YAML.
**When to use this option:**
* You need to make targeted changes to the existing configuration.
* You want to preserve your current Console-managed configuration as a starting point.
**Limitations:**
* **Manual changes overwritten** -- When returning to Console-managed operations, re-publish from Console and switch the Orchestrator back to its deployment provider by unsetting `MAVERICS_CONFIG` and restoring `MAVERICS_BUNDLE_PUBLIC_KEY_FILE`.
* **Configuration is managed as a local file** -- No audit trail, revision history, or Console-managed features.
***
### Option 3: Switch to Local File Configuration
Replace the bundle-based configuration with a local YAML file. This is the simplest break-glass path for making urgent configuration changes.
**Steps:**
Create a configuration file for the Orchestrator. You can extract the `maverics.json` configuration from the current bundle (see [Option 2](#option-2-extract-configuration-from-bundle-and-switch-to-local-file) for extraction steps) and use it directly -- the Orchestrator accepts both YAML and JSON formats.
```bash theme={null}
# Example: point to a local config file
export MAVERICS_CONFIG=/etc/maverics/maverics.yaml
```
Unset the bundle public key variable so the Orchestrator does not attempt to verify a bundle signature:
```bash theme={null}
unset MAVERICS_BUNDLE_PUBLIC_KEY_FILE
```
Restart the Orchestrator so it picks up the local configuration file instead of polling for bundles.
```bash theme={null}
# systemd
sudo systemctl restart maverics
# Docker
docker restart maverics
```
**When to use this option:**
* Urgent configuration changes are needed and you have a working YAML configuration.
* You prefer a clean, simple approach over modifying bundles.
**Limitations:**
* Manual configuration management -- no Console-managed objects, no diff previews.
* No audit trail for configuration changes made while working outside the Console.
* No revision history or rollback capability.
* You must switch back to bundle-based configuration when returning to Console-managed operations.
***
### Option 4: Direct Provider Modification (Git-Based Providers)
For GitHub and GitLab deployment providers, you can extract the configuration from the bundle and use Git for version tracking during the emergency.
Pushing a modified tar.gz bundle to a Git repository has the same signature verification constraint described in [Understanding the Constraint](#understanding-the-constraint). You cannot load an unsigned tar.gz bundle by removing the signature file. Instead, follow these steps to extract the configuration and switch to a local file, using Git for version tracking.
**Steps:**
```bash theme={null}
git clone https://github.com/your-org/your-deployment-repo.git
cd your-deployment-repo
```
Extract `maverics.json` from the tar.gz bundle in the repository.
```bash theme={null}
mkdir extracted && cd extracted
tar -xzf ../maverics.tar.gz
```
Edit `maverics.json` with the needed configuration changes.
```bash theme={null}
vi maverics.json
```
Commit the extracted config file (not the tar.gz) for auditability.
```bash theme={null}
cp maverics.json ../
cd ..
git add maverics.json
git commit -m "break-glass: emergency config change - [describe change]"
git push
```
Copy `maverics.json` to the Orchestrator and point it to the local config file, following the same approach as Options 2 and 3. You must unset the Git provider variable first -- remote config source variables take priority over `MAVERICS_CONFIG`.
```bash theme={null}
scp maverics.json orchestrator-host:/etc/maverics/maverics.json
# Unset the Git provider config source (pick the one matching your deployment)
# unset MAVERICS_GITHUB_CONFIG
# unset MAVERICS_GITLAB_CONFIG
export MAVERICS_CONFIG=/etc/maverics/maverics.json
unset MAVERICS_BUNDLE_PUBLIC_KEY_FILE
sudo systemctl restart maverics
```
**When to use this option:**
* Your deployment uses a GitHub or GitLab provider and you want Git history to provide auditability during the emergency.
**Limitations:**
* **The Orchestrator loads from a local file, not from the Git repository directly** -- Git provides change tracking only.
* **Same limitations as Options 2 and 3** -- No Console-managed features during the emergency period.
## Recovery Checklist
After returning to Console-managed operations, follow this checklist to re-establish normal workflows.
Confirm that the Console is accessible and your organization's data is intact.
Publish a new revision from the Console to overwrite any manual changes with a properly signed bundle. This ensures all Orchestrator instances are running Console-managed, signed configuration.
On every Orchestrator instance where verification was disabled, restore the `MAVERICS_BUNDLE_PUBLIC_KEY_FILE` environment variable to the public key path and restart the Orchestrator. Also unset `MAVERICS_CONFIG` if it was set during the emergency, so the Orchestrator returns to its deployment provider.
```bash theme={null}
unset MAVERICS_CONFIG
export MAVERICS_BUNDLE_PUBLIC_KEY_FILE=/etc/maverics/public_key.pem
sudo systemctl restart maverics
```
Check the Console audit logs for events that occurred while working outside the Console. There will be a gap in Console-side events during that period -- document this gap.
Record what configuration changes were made manually while working outside the Console, why they were needed, and which recovery option was used. This documentation supports compliance requirements.
## Preparation: Maintaining Fallback Options
Prepare fallback options so you can respond quickly when Console access is unavailable.
* **Periodically download signed bundles** -- Download and archive signed bundles from the Console as backups. A valid signed bundle can be re-deployed without Console access (no signature verification bypass needed).
* **Document provider credentials separately** -- Store your deployment provider credentials (S3 access keys, Azure tokens, Git tokens) in a location accessible independently of the Console.
* **Record your public key path** -- Know where `MAVERICS_BUNDLE_PUBLIC_KEY_FILE` points and how to unset it on each Orchestrator instance.
* **Understand config source priority** -- Remote config source environment variables (`MAVERICS_AWS_CONFIG`, `MAVERICS_AZURE_CONFIG`, etc.) take priority over `MAVERICS_CONFIG`. When switching to local file mode, you must unset the active remote provider variable first, otherwise the Orchestrator will continue using the remote source.
## Related Pages
Bundle format, signing, deployment providers, and revision history
Load Orchestrator configuration from a local YAML file
Production deployment guide for the Orchestrator
Console administration overview and capabilities
# Overview
Source: https://docs.strata.io/reference/console/config-publishing
The Maverics Console compiles Orchestrator configuration into cryptographically signed bundles and deploys them to storage providers. Orchestrator instances poll their configured storage provider for updated bundles, verify the signature, and apply the new configuration automatically.
## Bundle Format
The config bundle is a gzip-compressed tar archive named `maverics.tar.gz`. It contains everything the Orchestrator needs to run with the published configuration.
| File | Description |
| ------------------------------ | ------------------------------------------------------------------------------------------------------ |
| `maverics.json` | The compiled Orchestrator configuration in JSON format |
| Service extension source files | Source files for any service extensions attached to the deployment |
| Asset files | Files referenced by applications (HTML templates, static assets, etc.) |
| `signature.jwt` | Cryptographic signature for tamper detection -- see [Bundle Signing](#bundle-signing-and-verification) |
## Bundle Signing and Verification
Every config bundle is cryptographically signed to prevent tampering. The signing process uses ECDSA P-256 keys with SHA-256 hashes.
### Key Generation
When a deployment is created, the Console generates an ECDSA P-256 key pair:
* **Private key** -- Stored in the Console. Used to sign bundles at publish time. The private key is never exported or exposed through any API endpoint.
* **Public key** -- Provided to the Orchestrator via `MAVERICS_BUNDLE_PUBLIC_KEY_FILE`. Used to verify bundle signatures before applying configuration. The public key can be downloaded from the Console as a `.pem` file.
### Signing Process (Console)
When a bundle is published, the Console signs it using the following process:
Compute a SHA-256 hash of every file in the bundle (`maverics.json`, service extension source files, asset files).
Package the file hashes into a hash list containing the filename, hex-encoded SHA-256 hash, and hash algorithm for each file.
Sign the hash list as JWT claims using ECDSA P-256 with the deployment's private key.
Include the signed JWT as `signature.jwt` in the tar archive.
### Verification Process (Orchestrator)
When the Orchestrator downloads a new bundle, it verifies the signature before applying the configuration:
Extract the JWT from `signature.jwt` in the bundle.
Verify the ECDSA P-256 signature using the deployment's public key (provided via `MAVERICS_BUNDLE_PUBLIC_KEY_FILE`).
Confirm that the number of files listed in the JWT matches the number of files in the bundle.
For each file listed in the JWT, verify that the file exists in the bundle and its SHA-256 hash matches the hash in the JWT.
If signature verification fails at any step, the Orchestrator rejects the bundle and continues running with its current configuration. This ensures that tampered or corrupted bundles are never applied.
## Deployment Lifecycle
Publishing a config bundle follows a 5-step lifecycle.
The Console compiles the full Orchestrator configuration from all managed objects: applications and their policies, headers, and connector bindings, custom APIs, identity fabrics (connectors), providers (OIDC, SAML, MCP, LDAP), TLS certificates, caches, session configuration, service extensions, startup/environment configuration, and custom override configuration.
The compiled configuration is stored as a numbered revision in the Console. Each revision captures the complete configuration state at the time of publish.
The Console assembles the gzip-compressed tar bundle: serializes the configuration as `maverics.json`, includes service extension source files and asset files, and signs the bundle with the deployment's ECDSA private key.
The signed bundle is uploaded to the deployment's configured storage provider (S3, Azure Blob, GCS, GitHub, GitLab, or download-only).
The Orchestrator detects the new bundle on its next poll cycle, downloads it, verifies the signature, and applies the updated configuration.
## Deployment Providers
The Console supports 6 deployment providers. Each provider determines where the signed bundle is stored and how the Orchestrator retrieves it.
| Provider | Description |
| --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **No Cloud Storage Service Configured** | No-op deploy. The bundle is available for manual download from the Console UI only. Best for air-gapped environments where bundles are transferred manually. |
| **Amazon S3 Bucket** | Customer's S3 bucket with cross-account IAM role access. |
| **Microsoft Azure Blob Storage** | Customer's Azure Blob container with SAS token authentication. |
| **Google Cloud Storage Bucket** | Customer's GCS bucket with service account key authentication. |
| **GitHub** | Customer's GitHub repository with personal access token. |
| **GitLab** | Customer's GitLab repository with personal access token. |
All providers deploy the bundle as `maverics.tar.gz` to the specified `configurationFilePath` within the storage location.
## Storage Configuration
Each deployment provider requires specific configuration fields. Select your provider below for setup instructions, required fields, and IAM/access configuration.
Bucket name, IAM role, cross-account setup
Storage account, container, SAS token
Bucket name, service account key
Repository owner, token
Namespace, repository, branch, token
The **No Cloud Storage Service Configured** provider requires no configuration.
## Publish Preview and Validation
At the bottom of each deployment's Settings page, a sticky footer bar provides publishing controls:
* **Publish Preview** -- Opens the Deployment Manager dialog to review and publish changes.
* **Version selector** -- Switch between the latest and older revisions.
* **Download Deployment** -- Download the deployment bundle without publishing.
### Deployment Manager
Clicking **Publish Preview** opens the **Deployment Manager** dialog, which contains:
* **Simulation Settings** -- Configure a "Simulate Continuity Strategy" toggle and a "Start After Time" field for testing deployment behavior.
* **Revisions** -- Select an existing revision or create a new one. Add a note describing what changed.
* **Diff view** -- Side-by-side comparison of `maverics.json` showing the current configuration versus the new configuration.
At the bottom of the dialog, click **Publish** to deploy the configuration bundle, or **Cancel** to close without publishing.
Use the Deployment Manager to verify that configuration changes are intentional before deploying to your Orchestrator instances.
## Revision History
Every publish creates a numbered revision that captures the complete configuration state. Revisions provide version control for your Orchestrator configuration.
### Revision Capabilities
* **Diff between revisions** -- Compare any two revisions to see what changed.
* **Revision notes** -- Add notes to each revision describing what changed and why.
* **Rollback** -- Deploy a specific historical revision to revert to a known-good configuration.
### Revision API
| Endpoint | Method | Description |
| ---------------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `/deployments/{id}/revisions` | `GET` | List all revisions for a deployment |
| `/deployments/{id}/revisions/{revisionNumber}` | `GET` | View a specific revision with diff |
| `/deployments/{id}/deploy` | `POST` | Deploy a revision. Include a `revisionNumber` field to deploy a specific historical revision instead of building a new one from current Console state. |
## Orchestrator Polling Configuration
The Orchestrator polls its configured storage provider for new bundles at a regular interval. Configure polling behavior with the following environment variables.
| Variable | Default | Description |
| ----------------------------------- | ------- | ---------------------------------------------------------------------------------------- |
| `MAVERICS_RELOAD_CONFIG` | `false` | Set to `true` to enable configuration hot-reload. Required for automatic bundle polling. |
| `MAVERICS_POLLING_INTERVAL_SECONDS` | `30` | How often (in seconds) the Orchestrator checks for new bundles. |
| `MAVERICS_BUNDLE_PUBLIC_KEY_FILE` | -- | Path to the public key PEM file for verifying bundle signatures. |
The Orchestrator retrieves bundles using the same mechanism as the deployment provider's config source type. See the [config source references](/reference/orchestrator/configuration/config-sources) for provider-specific environment variables (e.g., S3 bucket configuration, Azure Blob credentials).
## Override Config
Override config provides a configuration override mechanism for deployments. When enabled for your organization, you can inject custom settings that are merged into the compiled configuration at build time.
### How It Works
* A `_custom` key is added to the deployment's startup configuration.
* Custom settings in `_custom` are merged into the compiled configuration during the bundle build step.
* Top-level keys in the override can replace or extend Console-managed configuration objects.
### Use Cases
* **Orchestrator features not yet in the Console** -- Some Orchestrator configuration options are not yet manageable through the Console UI. Override config lets you use these features without waiting for Console support to be added.
Override configuration requires enablement for your organization. Contact your Strata account team or [Strata support](https://strataidentity.my.site.com/support/s/) to enable it.
## Common Errors
### Failed to read public key
```
failed to instantiate config provider: unable to read file 'public_key.pem'
```
The Orchestrator cannot find the public key file specified by `MAVERICS_BUNDLE_PUBLIC_KEY_FILE`. Verify that the file path is correct and the file is readable by the Orchestrator process.
### Bundle signature verification failed
```
bundle signature verification failed
```
The public key provided to the Orchestrator does not match the private key used to sign the bundle. This typically happens when the public key file belongs to a different deployment. Download the correct public key from the Console for the deployment that published the bundle.
## Related Pages
Emergency procedures when the Console is inaccessible
All Orchestrator configuration source types
Production deployment guide for the Orchestrator
Console administration overview and capabilities
# Microsoft Azure Blob Storage
Source: https://docs.strata.io/reference/console/config-publishing/azure-blob
Configure Microsoft Azure Blob Storage as the storage provider for your Maverics deployment. The Console publishes signed config bundles to your Azure Storage container, and Orchestrator instances poll the container for updates.
## Prerequisites
* **An active Azure account** -- with permissions to create and manage storage accounts, containers, and SAS tokens
* **A Maverics Console account** -- with access to create or edit deployments
## Azure Setup
In the Azure portal, search for **Storage accounts** and select **Create**.
Choose your subscription and resource group, enter a unique storage account name, and select a region. Use default settings for the remaining options and click **Review + Create**.
Navigate to your storage account and select **Containers** under **Data storage**.
Click **+ Container**, enter a name (e.g., `maverics-config`), and click **Create**.
On the container, click the three-dot menu (or right-click) and select **Generate SAS**.
Set **Signing method** to **Account key** and **Signing key** to **Key 1**.
Under **Permissions**, select **Create**, **Add**, and **Write** (these are the minimum permissions the Console needs to publish bundles).
Set an appropriate expiry date.
Click **Generate SAS token and URL**.
Copy the **Blob SAS token** value (starts with `sv=`) -- you will paste this into the Console's **SAS Token** field.
## Storage Configuration
Configure these fields in the Console when creating or editing a deployment with the **Microsoft Azure Blob Storage** provider.
| Field | Required | Description |
| ----------------------- | -------- | -------------------------------------------------------------------------------------------------- |
| Storage Account Name | Yes | The unique name of the storage account in Azure |
| Container Name | Yes | The name of the container in your storage account |
| SAS Token | Yes | The shared access signature URI granting access to the container |
| Configuration File Path | No | The path within the container where the bundle is stored |
| Endpoint | No | Override the default Azure API endpoint (e.g., `blob.core.usgovcloudapi.net` for Azure Government) |
The Orchestrator uses the corresponding [config source](/reference/orchestrator/configuration/config-sources) type to retrieve bundles from the deployment provider. If the Console deploys to Azure Blob Storage, the Orchestrator uses the [Azure Blob config source](/reference/orchestrator/configuration/config-sources/azure-blob) to poll for updates.
## Common Errors
### Azure deployment 403 error
```
Failed to deploy: error deploying bundle unexpected Azure response: 403
```
The SAS token used for Azure Blob Storage deployment does not have sufficient permissions. Regenerate the SAS token with Create, Add, and Write permissions on the target container.
## Related Pages
Bundle format, signing, deployment lifecycle, and revision history
Orchestrator-side Azure Blob configuration source reference
Production deployment guide for the Orchestrator
# Google Cloud Storage Bucket
Source: https://docs.strata.io/reference/console/config-publishing/gcs
Configure a Google Cloud Storage (GCS) bucket as the storage provider for your Maverics deployment. The Console publishes signed config bundles to your GCS bucket, and Orchestrator instances poll the bucket for updates.
## Prerequisites
* **A Google Cloud account** -- with permissions to create projects, buckets, and service accounts
* **A Maverics Console account** -- with access to create or edit deployments
## Google Cloud Setup
In the Google Cloud Console, select your project.
Go to **Cloud Storage** (under Quick Access or the Products menu).
Go to **Buckets** and click **Create**.
Enter a unique bucket name and click **Continue**.
Select a region and click **Continue**.
Accept defaults for the remaining options and click **Create**.
From the navigation menu, go to **IAM & Admin** then **Service Accounts**.
Click **Create Service Account**.
Enter a name (e.g., "Maverics Console") and click **Create and Continue**.
Under "Grant this service account access to project", add the **Storage Object Admin** role (provides read and write access needed by the Console) and click **Continue**.
Click **Done** to return to the Service Accounts list.
Click the service account name to open details.
Go to the **Keys** tab.
Click **Add Key**, then **Create New Key**, select **JSON**.
A JSON key file downloads -- open it and copy the entire JSON body to paste into the Console's **Google Service Account Key** field.
## Storage Configuration
Configure these fields in the Console when creating or editing a deployment with the **Google Cloud Storage Bucket** provider.
| Field | Required | Description |
| -------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| Bucket Name | Yes | The GCS bucket name |
| Google Service Account Key | Yes | Service account key JSON for bucket access. Paste the body of the JSON key file downloaded from IAM & Admin in the Google Cloud Console. |
| Configuration File Path | No | The path within the bucket where the bundle is stored |
The Orchestrator uses the corresponding [config source](/reference/orchestrator/configuration/config-sources) type to retrieve bundles from the deployment provider. If the Console deploys to GCS, the Orchestrator uses the [GCS config source](/reference/orchestrator/configuration/config-sources/gcs) to poll for updates.
## Related Pages
Bundle format, signing, deployment lifecycle, and revision history
Orchestrator-side GCS configuration source reference
Production deployment guide for the Orchestrator
# GitHub
Source: https://docs.strata.io/reference/console/config-publishing/github
Configure a GitHub repository as the storage provider for your Maverics deployment. The Console publishes signed config bundles to your GitHub repository, and Orchestrator instances poll the repository for updates.
## Prerequisites
* **A GitHub account** -- with permissions to create repositories and generate personal access tokens
* **A Maverics Console account** -- with access to create or edit deployments
## GitHub Setup
Create a new GitHub repository (or use an existing one) for Maverics configuration storage. This repository will hold the signed config bundles published by the Console.
Generate a fine-grained personal access token for the Console to write config bundles to the repository.
1. In GitHub, click your profile photo, then click **Settings**
2. In the left sidebar, click **Developer settings**
3. Under Personal access tokens, click **Fine-grained tokens**
4. Click **Generate new token**
5. Enter a **Token name** (e.g., "Maverics Console")
6. Select the **Resource owner** (your user or organization)
7. Set an **Expiration** date
8. Under Repository access, select **Only select repositories** and choose your Maverics repository
9. Under Permissions, expand **Repository permissions** and set **Contents** to **Read and write**
10. Click **Generate token** and copy the value -- paste this into the Console's **Token** field
For full details, see [Creating a fine-grained personal access token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#creating-a-fine-grained-personal-access-token) in the GitHub documentation.
## Storage Configuration
Configure these fields in the Console when creating or editing a deployment with the **GitHub** provider.
| Field | Required | Description |
| ----------------------- | -------- | ---------------------------------------------------------------------------- |
| Owner | Yes | Your GitHub organization name |
| Repository | Yes | The GitHub repository name |
| Token | Yes | A fine-grained personal access token with Contents read and write permission |
| Configuration File Path | No | The path within the repository where the bundle is stored |
The Orchestrator uses the corresponding [config source](/reference/orchestrator/configuration/config-sources) type to retrieve bundles from the deployment provider. If the Console deploys to GitHub, the Orchestrator uses the [GitHub config source](/reference/orchestrator/configuration/config-sources/github) to poll for updates.
## Related Pages
Bundle format, signing, deployment lifecycle, and revision history
Orchestrator-side GitHub configuration source reference
Production deployment guide for the Orchestrator
# GitLab
Source: https://docs.strata.io/reference/console/config-publishing/gitlab
Configure a GitLab repository as the storage provider for your Maverics deployment. The Console publishes signed config bundles to your GitLab repository, and Orchestrator instances poll the repository for updates.
## Prerequisites
* **A GitLab account** -- with permissions to create projects and generate personal access tokens
* **A Maverics Console account** -- with access to create or edit deployments
## GitLab Setup
Create a new GitLab project (or use an existing one) for Maverics configuration storage. This project will hold the signed config bundles published by the Console.
Generate a personal access token for the Console to read and write config bundles to the repository. The token needs `read_repository` and `write_repository` scopes.
1. In GitLab, click your avatar on the left sidebar, then click **Preferences**
2. On the left sidebar, click **Access tokens**
3. Click **Add new token**
4. Enter a **Token name** (e.g., "Maverics Console")
5. Set an **Expiration date** (default is 365 days; GitLab 17.6+ allows up to 400 days)
6. In Select scopes, check **`read_repository`** and **`write_repository`**
7. Click **Create personal access token**
8. Copy the token value from **Your new personal access token** -- paste this into the Console's **Token** field
For full details, see [Personal access tokens](https://docs.gitlab.com/user/profile/personal_access_tokens/) in the GitLab documentation.
## Storage Configuration
Configure these fields in the Console when creating or editing a deployment with the **GitLab** provider.
| Field | Required | Description |
| ----------------------- | -------- | ---------------------------------------------------------------------------- |
| Namespace | Yes | Your GitLab organization name |
| Repository | Yes | The GitLab repository name |
| Branch | Yes | The branch in the repository |
| Token | Yes | A personal access token with `read_repository` and `write_repository` scopes |
| Configuration File Path | No | The path within the repository where the bundle is stored |
The Orchestrator uses the corresponding [config source](/reference/orchestrator/configuration/config-sources) type to retrieve bundles from the deployment provider. If the Console deploys to GitLab, the Orchestrator uses the [GitLab config source](/reference/orchestrator/configuration/config-sources/gitlab) to poll for updates.
## Related Pages
Bundle format, signing, deployment lifecycle, and revision history
Orchestrator-side GitLab configuration source reference
Production deployment guide for the Orchestrator
# Amazon S3 Bucket
Source: https://docs.strata.io/reference/console/config-publishing/s3
Configure an Amazon S3 bucket as the storage provider for your Maverics deployment. The Console publishes signed config bundles to S3, and Orchestrator instances poll the bucket for updates.
## Prerequisites
* **An active AWS account** -- with permissions to create and manage S3 buckets, IAM roles, and policies
* **A Maverics Console account** -- with access to create or edit deployments
## AWS Setup
In the AWS Console, navigate to **S3** under the Services menu.
Select the AWS region where you want the bucket.
Click **Create bucket**.
Enter a globally unique bucket name.
Under **Object Ownership**, select **ACLs disabled (recommended)**.
Under **Block Public Access settings**, keep **Block all public access** enabled.
Click **Create bucket**.
In the AWS Console, navigate to **IAM** and select **Policies**.
Click **Create policy** and switch to the **JSON** editor.
Create a **Console policy** with the following permissions (the Console needs read and write access to publish bundles):
```json theme={null}
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:ListBucket",
"s3:DeleteObject"
],
"Resource": [
"arn:aws:s3:::YOUR-BUCKET-NAME",
"arn:aws:s3:::YOUR-BUCKET-NAME/*"
]
}
]
}
```
Name the policy (e.g., "MavericsConsoleBucketAccess") and click **Create policy**.
Repeat to create an **Orchestrator policy** with read-only access (the Orchestrator only needs to read configuration):
```json theme={null}
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::YOUR-BUCKET-NAME/*"
}
]
}
```
Replace `YOUR-BUCKET-NAME` with your actual bucket name in both policies.
In the AWS Console, navigate to **IAM** and select **Roles**.
Click **Create role**.
Under **Trusted entity type**, select **AWS account**.
Select **Another AWS account** and enter the Strata Account ID for your region:
| Region | Strata AWS Account ID |
| ------ | --------------------- |
| USA | `322849791940` |
| UK | `339713018853` |
Check **Require external ID** and enter a unique identifier. You will use this value in the Console's **External ID** field.
Click **Next** and attach the Console policy you created in the previous step.
Name the role (e.g., "MavericsConsoleRole") and click **Create role**.
Open the newly created role and copy the **Role ARN** -- you will enter this in the Console's **Role ARN** field.
## Storage Configuration
Configure these fields in the Console when creating or editing a deployment with the **Amazon S3 Bucket** provider.
| Field | Required | Description |
| ----------------------- | -------- | ---------------------------------------------------------- |
| Bucket Name | Yes | The bucket name in Amazon S3 |
| Role ARN | Yes | The ARN of the role with access to your bucket |
| External ID | No | A unique ID that ties the assume role request to your role |
| AWS Region | Yes | The AWS region where your bucket is located |
| Configuration File Path | No | The path to the configuration file within your S3 bucket |
The Orchestrator uses the corresponding [config source](/reference/orchestrator/configuration/config-sources) type to retrieve bundles from the deployment provider. If the Console deploys to AWS S3, the Orchestrator uses the [S3 config source](/reference/orchestrator/configuration/config-sources/s3) to poll for updates.
## Related Pages
Bundle format, signing, deployment lifecycle, and revision history
Orchestrator-side S3 configuration source reference
Production deployment guide for the Orchestrator
# Overview
Source: https://docs.strata.io/reference/console/overview
The Maverics Console is the centralized management plane for Maverics deployments. It provides a web-based interface for managing Orchestrator configuration, publishing config bundles, reviewing audit logs, and administering organizations and team membership.
## Key Capabilities
| Capability | Description |
| ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Deployment Management** | Create, configure, and manage Orchestrator deployments. Each deployment represents a distinct Orchestrator instance with its own configuration, storage provider, and signing keys. |
| **Config Publishing** | Compile Orchestrator configuration into signed bundles, deploy them to storage providers, and track revision history with diff views and rollback support. See [config bundle publishing overview](/reference/console/config-publishing). |
| **Audit Logging** | Capture every API action in the Console as an audit record. Filter and search logs by time range, category, and event type. See [Audit Logs](/reference/console/audit-logs). |
| **Organization Management** | Manage organization settings, organizational units, and cross-organization visibility. |
| **Membership and Access Control** | Invite team members, assign roles, configure access policies, transfer ownership, and manage access across your organization. See [User Management](/reference/console/user-management). |
| **Application and Identity Fabric Management** | Define applications, identity fabrics, and service extensions that compose your Orchestrator configuration. |
Audit logging requires enablement for your organization. Contact your Strata account team or [Strata support](https://strataidentity.my.site.com/support/s/) to enable this feature.
## Console Reference Pages
Complete audit log reference with full v1.0 schema, all event categories, and API documentation
Organization management, roles and permissions, member invitations, and organization settings
Bundle format, ECDSA signing, deployment providers, revision history, and Orchestrator polling
Emergency procedures when the Console is inaccessible -- recovery options and checklists
Configure enterprise SSO for Console login with Okta, Entra ID, or any OIDC provider
# Single Sign-On (SSO)
Source: https://docs.strata.io/reference/console/sso
Setting up SSO for the Maverics Console enables users in your organization to log in using your enterprise identity provider. Once SSO is configured and a domain is enabled, all users with that email domain must use the Enterprise SSO login option. New users must be invited to the organization by an organization owner.
## Prerequisites
* **Organization owner role** -- You must be an owner of the organization to configure SSO settings.
* **Identity provider administrative access** -- You need admin access to create and configure an OIDC application in your identity provider.
* **Required claims** -- Your identity provider must return `email`, `given_name`, and `family_name` claims.
* **User assignment** -- Users must be assigned to the application in your identity provider.
* **DNS administrative access** -- You need admin access to your domain's DNS settings for domain verification.
## Configure OIDC Connection
The Maverics Console supports an OIDC connection with any identity provider that returns the required claims (`email`, `given_name`, `family_name`).
Click your profile in the upper-right corner of the Console, then click **Organizations**. Select the organization you want to configure. In the **Organization Settings** card, click **Edit** to open the settings dialog. Toggle **Enable Single Sign-On (SSO)** to on. An SSO Configuration section appears on the organization page.
Create an OIDC application in your identity provider and collect the required connection details.
1. In Google Cloud Console, go to **APIs & Services** > **Credentials**.
2. Click **Create Credentials** > **OAuth client ID**.
3. Select **Web application** as the application type.
4. Complete the setup. You will add the redirect URI in a later step.
5. The Issuer URL for Google is:
```
https://accounts.google.com
```
6. From the credentials page, copy the **Client ID** and **Client Secret**.
1. In Okta, go to **Applications** and click **Create App Integration**.
2. Select **OIDC - OpenID Connect** as the sign-in method and **Web Application** as the application type.
3. Complete the application setup. You will add the redirect URI in a later step.
4. Note the **Issuer URL** for your Okta tenant. The format is:
```
https://{yourOktaDomain}.okta.com
```
5. From the application's **Client Credentials** section, copy the **Client ID** and **Client Secret**.
1. In the Azure portal, go to **Microsoft Entra ID** and select **App registrations** under Manage.
2. Click **New registration** and complete the registration form. You will add the redirect URI in a later step.
3. From the application's **Overview** page, copy the **Application (client) ID** and **Directory (tenant) ID**. The Issuer URL format is:
```
https://login.microsoftonline.com/{yourTenantId}/v2.0
```
4. Go to **Certificates & secrets** under Manage and create a new client secret. Copy the secret value.
5. Go to **Token configuration** under Manage. Click **Add optional claim**, select **ID** as the token type, and add the following claims: `email`, `given_name`, `family_name`.
6. Go to **API permissions** under Manage. Ensure **User.Read** under Microsoft Graph is listed. If it is not present, click **Add a permission**, select **Microsoft Graph**, choose **Delegated permissions**, and add **User.Read**. Grant admin consent if required.
In the **OIDC Configuration** section on the organization page, enter the following values from your identity provider:
* **Issuer URL** -- The OIDC issuer URL for your identity provider. The field includes inline examples showing the expected URL format for Google, Okta, and Microsoft Entra ID.
* **Client ID** -- The client ID of the application you created.
* **Client Secret** -- The client secret of the application you created. Use the show/hide toggle to verify the value.
Click **Save**.
After saving, a **Redirect URI** populates in the Console. Copy this URI and add it to your identity provider's application settings:
* **Google** -- Paste the URI in the **Authorized redirect URIs** field in the OAuth client settings.
* **Okta** -- Paste the URI in the **Sign-in redirect URIs** field in the application's Login settings.
* **Entra ID** -- Add the URI under **Redirect URIs** in the application registration's Authentication settings.
The Redirect URI does not populate until SSO settings have been saved in the Console.
## Verify Domains
In the **SSO Domains** section below the OIDC configuration, enter your domain name in the text box and click the **Add** button. If no domains have been configured yet, the section displays "No domains configured".
Copy the **name/host/alias** value that populates after adding the domain.
In your DNS provider, add a new TXT record. The record name must be `_strata` and the value must be the string copied from the Console.
The Console attempts DNS verification every 30 seconds. Domain verification may take up to 48 hours depending on DNS propagation.
## Enable Domains
After a domain is verified, it appears in the Domains list with a toggle switch. The domain is disabled by default after verification. Enable SSO for the domain by toggling the switch to the **On** position.
You can disable SSO for a domain by toggling the switch back to Off. You can also delete a domain using the trash icon, but if you want to use that domain again in the future you will need to re-enter the details and re-verify it.
When SSO is enabled for a domain, all users with that email domain must use Enterprise SSO login. If SSO is later disabled, those users will be prompted to sign in with another method. Deleting a domain requires re-verification if you want to use it again.
## Troubleshooting
Verify that the DNS TXT record is configured correctly. The record name must
be `_strata`, the record type must be TXT, and the value must be copied
exactly from the Console. DNS propagation can take up to 48 hours.
This error typically indicates an SSO configuration issue. Check the
following:
* **Issuer URL** -- Verify that you entered the issuer URL, not the
`.well-known` URL for the registered application.
* **Missing claims** -- Verify that your identity provider returns `email`,
`given_name`, and `family_name` claims in the ID token.
* **User permissions** -- Verify that users have permission to use the
application in your identity provider.
* **User profiles** -- Verify that user profiles include all required claim
values (`email`, `given_name`, `family_name`).
If SSO was enabled and then disabled, existing SSO users must sign in with
an alternative method. If SSO was re-enabled, verify that the domain toggle
is in the On position and that the OIDC connection details (Issuer URL,
Client ID, Client Secret) are still valid.
## Related Pages
Manage organization members and roles
Console administration overview and capabilities
Emergency procedures when the Console is inaccessible
# User Management
Source: https://docs.strata.io/reference/console/user-management
The Maverics Console supports multi-user organizations with role-based access. Organizations can have multiple owners and members. Users can belong to several organizations, switch between them, and manage membership through the Console interface.
## Organizations
Each user can own or be a member of multiple organizations. The Console provides two ways to navigate between them.
**Switching organizations** -- Use the org switcher in the top banner of the Console. It displays your current organization name and role badge (e.g., "Strata Identity OWNER"). Click it to switch between organizations you have access to.
**Viewing all organizations** -- Click your profile in the upper-right corner of the Console, then click **Organizations**. This page shows all organizations you own or are a member of, with the subtitle "View your organization memberships".
## Roles and Permissions
The Console uses two roles -- **Owner** and **Member** -- to control what actions a user can perform within an organization.
| Permission | Owner | Member |
| ---------------------------- | ----- | ------ |
| Configure identity fabrics | Yes | Yes |
| Configure applications | Yes | Yes |
| Configure service extensions | Yes | Yes |
| Manage members | Yes | No |
| Manage SSO settings | Yes | No |
| Delete the organization | Yes | No |
Organizations can have multiple owners. Grant owner privileges when inviting a new member or by updating an existing member's role.
## Inviting Members
Click your profile in the upper-right corner of the Console, then click **Organizations**.
Click the organization you want to manage.
Click the **Invite** button.
Enter the email address of the person you want to invite. Optionally toggle **Grant Owner Privileges** to give the new member owner-level access. Owner privileges allow managing members, SSO settings, and deleting the organization. Click **Send Invite** to confirm.
Invited users receive an email notification. If they do not already have a Maverics Console login, they will be prompted to create one before accepting the invitation.
## Accepting Invitations
When you receive an invitation, sign in to the Maverics Console -- or create a login if you do not have one. Click your profile in the upper-right corner, then click **Organizations**. The invitation appears in your organizations list. Click it to accept and gain access to the organization.
Once you accept an invitation, the organization appears in your org switcher and you can begin working with the organization's configuration immediately.
## Removing Members
Organization owners can remove members from an organization. Navigate to the organization's detail page by clicking your profile, then **Organizations**, and selecting the organization. Click the remove action next to the member you want to remove.
Removing a member revokes their access to the organization immediately. Any in-progress work by that member is not affected, but they will no longer be able to view or modify the organization's configuration.
## Organization Settings
Each organization's detail page includes an **Organization Settings** card. Click the **Edit** button on this card to open the settings dialog.
* **Rename organization** -- Change the organization's display name.
* **Organization icon** -- Upload a custom icon (JPEG, PNG, or SVG, max 2 MB).
* **Enable SSO** -- Toggle to enable enterprise SSO for the organization. When enabled, an SSO Configuration section appears on the organization page. See [Single Sign-On (SSO)](/reference/console/sso) for setup instructions.
* **Delete organization** -- Permanently delete the organization and all its configuration.
Deleting an organization is permanent and cannot be undone. All configuration, deployments, and member associations are removed.
## Related Pages
Console administration overview
Configure enterprise SSO for Console login
Emergency procedures when the Console is inaccessible
# AI Identity Gateway
Source: https://docs.strata.io/reference/modes/ai-identity-gateway
The AI Identity Gateway mode extends the Maverics Orchestrator into the world of AI agents and tool-use. As AI agents interact with enterprise systems through the Model Context Protocol (MCP), they need identity -- who is the agent acting on behalf of, what permissions does it have, and which tools can it access. The AI Identity Gateway solves these challenges through two specialized app types: MCP Bridge and MCP Proxy.
## App Types
The AI Identity Gateway provides two app types, each designed for a different deployment pattern. Both share provider-level settings for transports and OAuth authorization to authenticate inbound agent connections.
Translate REST APIs into MCP tools -- reads OpenAPI specs and generates an MCP tool catalog with delegated authorization
Proxy MCP traffic to upstream MCP servers with identity injection, per-tool authorization, and delegation token exchange
## Agent Identity
AI agents present unique identity challenges that traditional user authentication does not address. When an agent calls an MCP tool on behalf of a user, the system must track both the agent's identity and the delegated user identity -- ensuring that the agent can only access resources the user has authorized.
The AI Identity Gateway propagates identity context through the entire agent-to-tool chain:
* **Agent authentication** -- Verify the identity of the AI agent itself before allowing any tool access
* **User delegation** -- Carry the delegating user's identity and permissions through agent tool calls
* **Scope enforcement** -- Restrict agent actions to the specific permissions the user has granted
* **Audit trail** -- Log both agent and user identity for every tool invocation, enabling compliance and forensics
**When to use each sub-mode**
* **MCP Bridge** -- Choose this when you have existing REST APIs you want AI agents to access. MCP Bridge translates REST APIs into MCP tools automatically.
* **MCP Proxy** -- Choose this when you have existing MCP servers that need identity. MCP Proxy adds authentication and authorization to MCP connections.
## How It Works
The AI Identity Gateway processes agent requests through a layered pipeline that validates identity, enforces authorization, and preserves audit context at every step:
1. **Agent connection** -- An AI agent connects to the **AI Identity Gateway Orchestrator's** MCP endpoint via SSE or Streamable HTTP transport.
2. **OAuth discovery** -- The gateway returns protected resource metadata (RFC 9470) via `/.well-known/oauth-protected-resource`, which lists the **Auth Provider Orchestrator** (or other authorization servers) the agent can authenticate against.
3. **Agent authentication** -- The agent authenticates against the Auth Provider Orchestrator and obtains an access token. The agent presents this token to the AI Identity Gateway Orchestrator.
4. **Token validation** -- The AI Identity Gateway Orchestrator validates the agent's token against the configured authorization server. The token identifies both the agent and the delegating user.
5. **Tool discovery** -- The agent requests available tools. For MCP Bridge apps, tools are generated from OpenAPI specs. For MCP Proxy apps, tools are discovered from upstream MCP servers. Tools from multiple apps can be namespaced to avoid naming conflicts.
6. **Tool invocation with authorization** -- When the agent invokes a tool, the AI Identity Gateway Orchestrator evaluates OPA policies on the inbound request, performs token exchange via the Auth Provider Orchestrator to obtain a scoped delegation token, and forwards the request to the upstream service.
7. **Response and audit** -- The upstream response flows back through the Orchestrator to the agent, with full audit logging capturing the agent identity, delegating user identity, tool name, and outcome.
## Key Concepts
### Two-Deployment Architecture
The AI Identity Gateway involves two orchestrator roles that are typically (but not necessarily) separate deployments:
* **Auth Provider Orchestrator** -- Runs the OIDC Provider with OIDC apps. Acts as the OAuth authorization server. Handles agent authentication, token issuance, and token exchange (minting short-lived, scoped delegation tokens for each tool invocation).
* **AI Identity Gateway Orchestrator** -- Runs the MCP Provider with MCP Bridge and MCP Proxy apps. Handles MCP transport, tool routing, inbound authorization (OPA policies), and upstream forwarding.
The AI Identity Gateway Orchestrator includes an OIDC connector that points to the Auth Provider Orchestrator's well-known URL. This is how the two deployments connect -- the gateway discovers the auth server's signing keys and token endpoints through the standard OIDC discovery mechanism.
For simpler deployments, both roles can run on a single orchestrator instance. In production, they are typically separate to isolate the token-issuing infrastructure from the MCP gateway.
See [AI Identity overview](/guides/ai-identity/overview#set-up-the-auth-provider) for a step-by-step walkthrough of configuring both deployments.
### MCP (Model Context Protocol)
MCP is an open protocol for AI agents to discover and invoke tools. The AI Identity Gateway adds identity and authorization to MCP, which the protocol does not natively provide. The Orchestrator acts as an MCP server to agents while acting as an MCP client (or REST client) to upstream services.
### Provider-Level vs App-Level
Provider-level settings are shared across all MCP apps: inbound transports (how agents connect) and OAuth authorization (how agent tokens are validated). Individual MCP Bridge and MCP Proxy apps configure their own upstream connections, tool catalogs, and per-tool authorization. This separation means all MCP apps on one Orchestrator share the same inbound endpoint.
### Delegation vs Impersonation
Token exchange supports two modes. Delegation (default) produces tokens with an `act` claim showing both user and agent identity -- ideal for auditability. Impersonation produces tokens that fully assume the user's identity with no trace of the agent -- needed when upstream services don't understand the `act` claim.
### Per-Tool Authorization
Each tool can have its own OAuth scopes and token TTL, enabling least-privilege access. A read-only tool gets narrow scopes; a write tool gets broader scopes. Tool names support exact matching and regex patterns for wildcarding.
### Inbound vs Outbound
This is the critical architectural distinction. Inbound configuration (transports, OAuth) controls how agents connect TO the Orchestrator. Outbound configuration (upstream, token exchange) controls how the Orchestrator connects to backend services. They are independently configured.
## Setup
In the Maverics Console, MCP Provider settings are configured in the **Deployment Settings** dialog under the MCP Provider section.
**General**
| Field | Required | Description |
| ----------- | -------- | ------------------------------------------------------------------------------- |
| Enabled | Yes | Toggle to enable the MCP Provider. On by default. |
| Server Name | No | MCP server name for identification. Defaults to "Maverics AI Identity Gateway". |
**Agent Connection and Session Management**
*Transports (HTTP Stream):*
| Field | Required | Description |
| --------------- | -------- | ----------------------------------------------------------------- |
| Stream Endpoint | Yes | URL path where agents connect via Streamable HTTP (e.g., `/mcp`). |
*Session:*
| Field | Required | Description |
| ------------------------ | -------- | ----------------------------------------------------------------------- |
| Header Name | No | HTTP header used for session IDs. Default: `Mcp-Session-Id`. |
| Session Timeout | Yes | Duration before idle sessions expire. Default: 1 hour. |
| Allow Client Termination | No | Toggle to allow clients to terminate their own sessions. On by default. |
**OAuth 2.0 Authorization Settings**
| Field | Required | Description |
| -------------------------- | -------- | --------------------------------------------------------------------------------- |
| Enable OAuth Authorization | No | Toggle to enable OAuth authorization for inbound MCP connections. Off by default. |
The Console UI provides a subset of the full YAML configuration. SSE transport configuration, keep-alive settings, OAuth server details (well-known endpoint, token validation method, expected audiences), and metadata refresh intervals are only available in YAML. See the [Configuration tab](#setup) for the complete reference.
The AI Identity Gateway requires the MCP Provider top-level key for shared provider settings (transports and OAuth authorization). Individual MCP apps (MCP Bridge and MCP Proxy) are configured under the `apps` array -- see the [MCP Bridge App](/reference/orchestrator/applications/mcp-bridge) and [MCP Proxy App](/reference/orchestrator/applications/mcp-proxy) pages for app-level configuration.
```yaml theme={null}
# This mcpProvider config runs on the AI Identity Gateway Orchestrator
mcpProvider:
enabled: true
transports:
stream:
enabled: true
path: "/mcp"
session:
enabled: true
headerName: "Mcp-Session-Id"
timeout: 1h
authorization:
oauth:
enabled: true
metadataPath: /.well-known/oauth-protected-resource
servers:
- wellKnownEndpoint: https://auth.example.com/.well-known/oauth-authorization-server
tokenValidation:
expectedAudiences:
- https://gateway.example.com/
method: jwt
```
#### Configuration Reference
The `mcpProvider` top-level key configures the MCP server behavior shared across all MCP apps (MCP Bridge and MCP Proxy). It defines the inbound transports (how AI agents connect to the Orchestrator) and OAuth authorization (how agent tokens are validated). Every MCP app served by this Orchestrator instance uses these provider-level settings.
| Key | Type | Required | Description |
| -------------------------------------------------------------------------------------- | ------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `mcpProvider.enabled` | Boolean | Yes | Enable the MCP provider |
| `mcpProvider.serverName` | String | No | MCP server name for identification. Default: `Maverics AI Identity Gateway` |
| `mcpProvider.transports.sse.enabled` | Boolean | No | Enable SSE transport (legacy MCP transport) |
| `mcpProvider.transports.sse.baseURL` | String | No | Base URL for SSE connections. Overrides the default base URL derived from the Orchestrator's address. |
| `mcpProvider.transports.sse.basePath` | String | No | Base path prefix for SSE endpoints |
| `mcpProvider.transports.sse.path` | String | Conditional | SSE connection endpoint path. Required when SSE is enabled. |
| `mcpProvider.transports.sse.messagePath` | String | Conditional | SSE message posting endpoint path. Required when SSE is enabled. |
| `mcpProvider.transports.sse.keepAlive.enabled` | Boolean | No | Enable SSE keep-alive pings |
| `mcpProvider.transports.sse.keepAlive.interval` | String | No | Keep-alive interval (duration string, e.g., `30s`). Must be positive when enabled. |
| `mcpProvider.transports.stream.enabled` | Boolean | No | Enable Streamable HTTP transport (recommended for new deployments) |
| `mcpProvider.transports.stream.path` | String | Conditional | Stream endpoint path. Required when stream is enabled. |
| `mcpProvider.transports.stream.session.enabled` | Boolean | No | Enable session support for stateful MCP interactions |
| `mcpProvider.transports.stream.session.headerName` | String | Conditional | Session ID header name. Required when sessions are enabled. |
| `mcpProvider.transports.stream.session.allowClientTermination` | Boolean | No | Allow clients to terminate their sessions |
| `mcpProvider.transports.stream.session.timeout` | String | No | Session timeout (duration string, e.g., `1h`). Must be positive when enabled. |
| `mcpProvider.authorization.oauth.enabled` | Boolean | No | Enable OAuth authorization for inbound MCP connections |
| `mcpProvider.authorization.oauth.metadataPath` | String | Conditional | OAuth Protected Resource metadata path (RFC 9470). Required when OAuth is enabled. |
| `mcpProvider.authorization.oauth.servers[].wellKnownEndpoint` | String | Yes | OAuth authorization server discovery endpoint |
| `mcpProvider.authorization.oauth.servers[].refreshInterval` | String | No | Metadata refresh interval (duration string). Must be positive. |
| `mcpProvider.authorization.oauth.servers[].tokenValidation.expectedAudiences` | Array | Yes | Expected token audiences. At least one required. |
| `mcpProvider.authorization.oauth.servers[].tokenValidation.method` | String | No | Token validation method: `jwt`, `introspection`, or `auto`. The `auto` method tries JWT first, then falls back to introspection. |
| `mcpProvider.authorization.oauth.servers[].tokenValidation.jwt.clockSkew` | String | No | Clock skew tolerance for JWT validation (duration string, e.g., `15s`) |
| `mcpProvider.authorization.oauth.servers[].tokenValidation.introspection.clientID` | String | Conditional | Client ID for token introspection requests. Required when `method` is `introspection` or `auto`. |
| `mcpProvider.authorization.oauth.servers[].tokenValidation.introspection.clientSecret` | String | Conditional | Client secret for token introspection requests. Required when `method` is `introspection` or `auto`. |
| `mcpProvider.authorization.oauth.servers[].tokenValidation.introspection.timeout` | String | Conditional | Timeout for introspection requests (duration string, e.g., `5s`). Must be positive. Required when `method` is `introspection` or `auto`. |
| `mcpProvider.authorization.oauth.servers[].tokenValidation.introspection.maxRetries` | Integer | No | Maximum retry attempts for introspection requests |
#### Inbound vs Outbound
The MCP configuration has a critical directional distinction:
* **Inbound** (`mcpProvider.transports`) -- Configures how AI agents connect TO the Orchestrator. The Orchestrator exposes SSE and/or Streamable HTTP endpoints that agents connect to for tool discovery and invocation.
* **Outbound** (`apps[].upstream`) -- Configures how the Orchestrator connects to upstream services. For MCP Proxy, this is the upstream MCP server. For MCP Bridge, this is the REST API backend. Outbound transport is configured per-app on the respective app pages.
This separation means `mcpProvider.transports` settings apply to all MCP apps on this Orchestrator instance, while each app independently configures its own outbound connection.
## Related Integrations
The AI Identity Gateway uses Identity Fabric connectors on the **Auth Provider Orchestrator** (not on the gateway itself) to authenticate agents and issue tokens. The connector configuration for agent authentication lives on the Auth Provider's OIDC Provider deployment. These are the most commonly used connectors for agent identity:
Microsoft Entra ID for agent authentication
Okta for agent authentication
Auth0 for agent authentication
Any OIDC provider for agent authentication
See the [connector compatibility matrix](/guides/authentication/choosing-a-mode#connector-compatibility) for all supported pairings and the [Identity Fabric overview](/reference/orchestrator/identity-fabric) for the full connector list.
## Related Pages
Full configuration reference, Console UI setup, and troubleshooting for MCP Bridge apps
Full configuration reference, Console UI setup, and troubleshooting for MCP Proxy apps
Configure the Auth Provider Orchestrator for token issuance and exchange
Overview of all application types and how they fit into a deployment
# HTTP Proxy
Source: https://docs.strata.io/reference/modes/http-proxy
The HTTP Proxy mode deploys the Maverics Orchestrator as an identity-aware reverse proxy. It sits in front of your applications -- intercepting HTTP traffic to inject authentication headers, manage sessions, and enforce access policies without requiring any changes to the application's code or configuration.
**When to use this mode**
* **HTTP Proxy** -- Choose this mode when you cannot modify the application's authentication code. Best for legacy apps, COTS products, and header-based authentication patterns.
* **OIDC Provider** -- Choose this mode when the application natively supports OpenID Connect.
* **SAML Provider** -- Choose this mode when the application natively supports SAML 2.0.
* **LDAP Provider** -- Choose this mode for applications that require an LDAP directory. Often paired with HTTP Proxy for comprehensive legacy app identity.
* **AI Identity Gateway** -- Choose this mode for securing AI agent-to-tool communication via MCP.
## Use Cases
* **Protecting legacy apps without code changes** -- Add modern authentication to legacy applications that rely on form-based login, basic auth, or no authentication at all.
* **Header-based authentication injection** -- Inject identity headers (e.g., `SM_USER`, `REMOTE_USER`) into upstream requests for applications that expect header-based identity.
* **Session management for stateless apps** -- Provide cookie-based session management for applications that do not handle sessions natively.
* **Combining with LDAP Provider for legacy stacks** -- Pair HTTP Proxy with LDAP Provider mode to modernize applications that depend on both header-based auth and LDAP directory lookups.
## How It Works
The HTTP Proxy request flow follows these steps:
1. **Traffic interception** -- The Orchestrator listens on configured route patterns (hostname/path combinations) and intercepts all matching HTTP requests before they reach the upstream application.
2. **Policy evaluation** -- Each request is matched against location-based policies. The Orchestrator determines which authentication and authorization rules apply based on the request path.
3. **User authentication** -- If the user is not authenticated (no valid session), the Orchestrator redirects them to the configured identity provider. After successful authentication, a session cookie is established.
4. **Authorization check** -- The Orchestrator evaluates authorization rules against the authenticated user's attributes. Rules use `and`/`or` conditions with operators like `equals`, `contains`, etc. Unauthorized users are redirected or receive a 403 response.
5. **Header injection** -- For authorized requests, the Orchestrator injects identity headers (e.g., `SM_USER`, `X-Remote-User`) into the upstream request using template syntax (`{{ connector.claim }}`). The upstream application receives these headers and uses them for its own identity decisions.
6. **Proxying and response** -- The request (with injected headers) is forwarded to the upstream backend. The response flows back through the Orchestrator to the client. Optional Service Extensions can modify the request or response at this stage.
## Key Concepts
### Route Patterns and Upstreams
Route patterns define which traffic the proxy intercepts. Each proxy app maps one or more hostname/path patterns to an upstream backend URL. The Orchestrator acts as a transparent reverse proxy -- the client connects to the Orchestrator, and the Orchestrator forwards to the backend.
### Header Injection
Header injection is the primary mechanism for passing identity to legacy applications. Using `{{ connector.claim }}` template syntax, the Orchestrator maps claims from identity providers into HTTP headers that the upstream application expects. This replaces legacy access management products like SiteMinder without changing the application.
### Location-Based Policies
Unlike OIDC and SAML modes where authorization is per-app, HTTP Proxy supports location-based policies. Different URL paths within the same application can have different authentication requirements and authorization rules. For example, `/` might allow all authenticated users while `/admin` requires a specific role.
### Session Management
The Orchestrator manages sessions for proxied applications using cookies. This is critical for applications that lack their own session management. Session configuration (cookie name, lifetime, idle timeout) is defined at the global level and applies to all proxy apps.
### Upstream Login
Some legacy applications have their own login flows in addition to the identity headers. The upstream login feature automates posting credentials to the upstream's login form after the Orchestrator has authenticated the user, handling the "double login" problem.
## Setup
HTTP Proxy mode does not have deployment-level settings in the Maverics Console. Unlike OIDC Provider, SAML Provider, LDAP Provider, and MCP Provider -- which are configured in the Deployment Settings dialog -- HTTP Proxy is configured entirely at the **application level**.
To configure an HTTP Proxy application in the Console:
1. Navigate to **Applications** in the Maverics Console.
2. Create or select a proxy application.
3. Configure route patterns, upstream URL, headers, authentication policies, and authorization rules within the application's settings.
Each proxy application manages its own routes, header injection, and location-based policies. See the [Proxy App](/reference/orchestrator/applications/proxy) page for the complete field reference.
The **Deployment Settings** dialog does not include an HTTP Proxy section. All HTTP Proxy configuration is done through the Applications section of the Console. Some advanced options (Service Extensions for `modifyRequestSE`, `modifyResponseSE`, `handleUnauthorizedSE`, upstream login) are only available in YAML.
This example shows a proxy app protecting a legacy application with header injection, authentication policy, and logout configuration.
```yaml maverics.yaml theme={null}
connectors:
- name: my-idp
type: oidc
oidcWellKnownURL: https://idp.example.com/.well-known/openid-configuration
oauthClientID: my-client
oauthClientSecret:
oauthLoginRedirect:
urls:
- https://app.example.com/oidc-callback
scopes: openid profile email
apps:
- name: legacy-app
type: proxy
routePatterns:
- app.example.com/
upstream: https://backend.internal:8443
tls: upstream
headers:
- name: SM_USER
value: "{{ my-idp.email }}"
- name: X-User-Name
value: "{{ my-idp.name }}"
- name: X-User-Given-Name
value: "{{ my-idp.given_name }}"
policies:
- location: /
authentication:
idps:
- my-idp
authorization:
allowAll: true
- location: /admin
authentication:
idps:
- my-idp
authorization:
rules:
- and:
- equals: ["{{ my-idp.role }}", "admin"]
rulesAggregationMethod: "and"
logout:
logoutURL: /logout
postLogoutRedirectURL: https://app.example.com/
```
#### Configuration Reference
HTTP Proxy mode does not have a separate provider-level configuration key. The HTTP server settings (listen address, TLS, timeouts) are configured under the `http` top-level key, documented on the [Configuration](/reference/orchestrator/configuration#http-server-configuration) page. All proxy-specific configuration is at the app level.
#### Proxy App Configuration
Proxy apps define route patterns, upstream backend URL, header injection, location-based policies, and authorization rules.
Full configuration reference, Console UI setup steps, and troubleshooting for proxy apps
## Related Integrations
The HTTP Proxy mode works with all Identity Fabric connectors. The Orchestrator authenticates users via any upstream IdP and injects identity headers into proxied requests. These are the most commonly used pairings:
Microsoft Entra ID for enterprise SSO
Okta SSO consolidation
Directory attributes for header enrichment
Any OIDC-compliant provider
See the [connector compatibility matrix](/guides/authentication/choosing-a-mode#connector-compatibility) for all supported pairings and the [Identity Fabric overview](/reference/orchestrator/identity-fabric) for the full connector list.
The HTTP Proxy also pairs with:
* **[LDAP Provider](/reference/modes/ldap-provider)** -- Pair with LDAP Provider mode for applications that need both header-based auth and LDAP directory access
* **[Caches](/reference/orchestrator/caches)** -- Distributed session storage with Redis for multi-instance deployments
## Related Pages
Full proxy app configuration reference, setup steps, and troubleshooting
Virtualize LDAP directories for legacy applications -- often paired with HTTP Proxy
Configure the Orchestrator as an OpenID Connect authorization server
Connect upstream identity providers to the Orchestrator
Understand how modes fit into the Orchestrator architecture
# LDAP Provider
Source: https://docs.strata.io/reference/modes/ldap-provider
The LDAP Provider mode configures the Maverics Orchestrator as a virtual LDAP directory. It presents a standard LDAP interface to applications while sourcing identity data from modern cloud identity providers -- enabling LDAP-dependent applications to authenticate against Microsoft Entra ID, Okta, or other cloud IdPs without any application changes.
**When to use this mode**
* **LDAP Provider** -- Choose this mode for applications that require an LDAP directory for authentication or directory lookups. Often paired with HTTP Proxy mode for comprehensive legacy app identity.
* **HTTP Proxy** -- Choose this mode when you need to protect applications via reverse proxy. Frequently combined with LDAP Provider for legacy stacks.
* **OIDC Provider** -- Choose this mode when the application supports OpenID Connect natively.
* **SAML Provider** -- Choose this mode when the application supports SAML 2.0 natively.
* **AI Identity Gateway** -- Choose this mode for securing AI agent-to-tool communication via MCP.
## Prerequisites
**Service Extensions are required.** Every LDAP Provider integration requires Go-based Service Extensions to handle LDAP operations (bind authentication, search queries, credential lookups). The LDAP Provider cannot function without them -- there is no declarative-only configuration path. Plan for Service Extension development as part of your integration.
Before configuring the LDAP Provider, ensure you have:
1. **Service Extension development capability** -- You need to write Go-based Service Extensions that implement the LDAP operation handlers: `authenticateSE` for bind operations and `searchSE` for search queries. See [Service Extensions reference](/reference/orchestrator/service-extensions).
2. **Downstream application LDAP requirements** -- You must know what your LDAP-dependent application expects: which LDAP operations it performs (bind, search, compare), what base DNs it queries, which attributes it expects in search results (e.g., `cn`, `sAMAccountName`, `memberOf`), and what bind method it uses.
3. **Attribute source systems** -- You must have identity attribute data available in systems the Orchestrator can query during LDAP operations. These sources -- cloud IdPs (Microsoft Entra ID, Okta), databases, APIs, directories -- provide the data that the Service Extensions translate into LDAP responses.
4. **A running Maverics Orchestrator** -- Follow the [Quick Start guide](/guides/getting-started/quick-start) or [installation reference](/reference/orchestrator/installation) if not yet installed.
## Use Cases
* **Virtualizing cloud IdP as LDAP directory** -- Present Microsoft Entra ID, Okta, or PingFederate as an LDAP directory for applications that only know how to authenticate via LDAP bind operations.
* **LDAP-dependent legacy app migration** -- Migrate legacy applications off on-premises Active Directory to cloud identity providers without changing the application's LDAP configuration.
* **Combining with HTTP Proxy for full legacy stack** -- Pair LDAP Provider with HTTP Proxy mode to modernize applications that depend on both LDAP lookups and header-based authentication.
* **Directory consolidation** -- Present multiple identity sources as a single unified LDAP directory, consolidating user lookups across disparate systems.
## How It Works
The LDAP Provider operation flow follows these steps:
1. **LDAP client connects** -- An LDAP-dependent application (the LDAP client) connects to the Orchestrator's LDAP endpoint via `ldap://` or `ldaps://` (TLS-encrypted).
2. **Bind authentication** -- The client sends an LDAP bind request (simple bind with DN+password). The Orchestrator's Service Extension handles credential validation -- typically by translating the bind into an authentication request against a cloud identity provider.
3. **Root DSE discovery** -- The client reads the Root DSE entry to discover the directory's capabilities, naming contexts, and supported features. The Orchestrator serves configured Root DSE attributes.
4. **Search operations** -- The client sends LDAP search requests (base DN, scope, filter, attributes). The Orchestrator's search Service Extension translates these into queries against upstream identity sources and returns matching entries in LDAP format.
5. **Attribute translation** -- The Service Extension maps cloud IdP attributes (e.g., Microsoft Entra ID user properties) into the LDAP attribute names and formats the client application expects (e.g., `cn`, `sAMAccountName`, `memberOf`).
6. **Connection lifecycle** -- The Orchestrator manages connection timeouts (read/write deadlines) and handles multiple concurrent LDAP connections, each with its own bind state.
## Key Concepts
### Virtual Directory
The LDAP Provider is not a traditional LDAP server with its own data store. It is a virtual directory that translates LDAP protocol operations into queries against modern identity sources. The directory data comes from cloud IdPs, the LDAP protocol is just the interface.
### Service Extension-Driven
Unlike other Orchestrator modes that use declarative configuration for most operations, the LDAP Provider relies heavily on Service Extensions (Go code) for its core operations. The `authenticateSE` handles bind operations and the `searchSE` handles search queries. This provides maximum flexibility for translating between LDAP semantics and cloud IdP APIs.
### Authentication Methods
Simple bind (DN+password) is the supported authentication method. It requires a Service Extension to implement the actual credential validation against upstream providers.
### Pairing with HTTP Proxy
The LDAP Provider is most commonly deployed alongside HTTP Proxy mode in a **facade** (or "sandwich") pattern. The application sits between two Orchestrator roles: the HTTP Proxy handles browser-facing authentication while the LDAP Provider handles the application's backend LDAP operations.
**Facade flow:**
1. A user requests a protected page. The Orchestrator (HTTP Proxy) intercepts and redirects the browser to a cloud IdP (Okta, Microsoft Entra ID, Google, AWS, etc.) for authentication with modern MFA and policies.
2. After successful authentication, the Orchestrator creates one-time credentials and delivers them to the downstream application using one of three methods:
* **Header injection** -- The Orchestrator injects identity headers (e.g., `SM_USER`, `X-Remote-User`) into the proxied request. The application reads these headers directly.
* **Form-stuffing ([upstream login](/reference/modes/http-proxy#upstream-login))** -- The Orchestrator's `loginSE` Service Extension POSTs one-time credentials to the application's native login form, automating the "double login" problem. The `isLoggedInSE` checks whether the app session is already established.
* **Session/cookie** -- The Orchestrator stores credentials in the session, making them available to subsequent LDAP bind operations.
3. The application sends an LDAP Bind request to the Orchestrator (LDAP Provider) to validate those credentials.
4. The application sends LDAP Search requests to retrieve user attributes (e.g., `cn`, `memberOf`, `sAMAccountName`).
5. The Orchestrator translates the LDAP queries into lookups against the cloud IdP and returns the results in LDAP format. The user sees the requested page.
The diagram shows two Orchestrator roles, but these can be deployed as a single Orchestrator running both HTTP Proxy and LDAP Provider modes, two separate Orchestrator instances, or groups of Orchestrators for high-availability (HA) deployments.
**Shared cache required for dual-Orchestrator facade deployments.** When the HTTP Proxy and LDAP Provider run as **separate Orchestrator instances** (the most common facade deployment), they need a **[shared cache](/reference/orchestrator/caches)** so that one-time credentials generated by the proxy Orchestrator can be validated by the LDAP Provider Orchestrator. Without a shared cache, the LDAP Provider instance has no way to look up the credentials the proxy instance created.
When both modes run on a **single Orchestrator instance**, the local in-memory cache is sufficient because credential data stays in the same process.
See the [Caches reference](/reference/orchestrator/caches) for cache setup and the [Scale for Production guide](/guides/operations/scale) for multi-instance deployment guidance.
### No Apps Array
Unlike OIDC, SAML, and HTTP Proxy modes, the LDAP Provider does not use separate app entries. All settings are at the provider level -- there is one virtual directory per Orchestrator instance.
## Setup
In the Maverics Console, LDAP Provider settings are configured in the **Deployment Settings** dialog under the LDAP Provider section.
**Server Settings**
| Field | Required | Description |
| --------------- | -------- | -------------------------------------------------------------------------------------------- |
| Enable | Yes | Toggle to enable the LDAP Provider. The provider must be enabled for it to start. |
| Protocol | Yes | Dropdown to select the LDAP protocol: `ldap://` (unencrypted) or `ldaps://` (TLS-encrypted). |
| URI | Yes | LDAP listen address. Default port is 389 for `ldap://` or 636 for `ldaps://`. |
| TLS Certificate | No | File path to the TLS certificate (used when protocol is `ldaps://`). |
| TLS Key File | No | File path to the TLS private key (used when protocol is `ldaps://`). |
**Search**
| Field | Required | Description |
| ------------------------ | -------- | --------------------------------------------------------------------------- |
| Search Service Extension | No | Dropdown to select a Service Extension for handling LDAP search operations. |
**Authentication**
| Field | Required | Description |
| -------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------ |
| Allow Anonymous | No | Toggle to allow anonymous LDAP bind operations. Off by default. |
| Enable Simple Auth | No | Toggle to enable simple bind authentication (DN + password). |
| Authentication Service Extension | No | Dropdown to select a Service Extension for simple bind authentication. Required when simple auth is enabled. |
The Console UI provides a subset of the full YAML configuration. Advanced settings such as Root DSE attributes and read/write deadline timeouts are only available in YAML. See the [Configuration tab](#setup) for the complete reference.
This example shows an LDAP Provider configuration with LDAPS, simple bind authentication via a service extension, and search handling.
```yaml maverics.yaml theme={null}
tls:
ldap-server-tls:
certFile: /etc/maverics/certs/ldap-server.pem
keyFile: /etc/maverics/certs/ldap-server-key.pem
connectors:
- name: upstream-idp
type: oidc
oidcWellKnownURL: https://idp.example.com/.well-known/openid-configuration
oauthClientID: ldap-bridge
oauthClientSecret:
ldapProvider:
enabled: true
uri: ldaps://0.0.0.0:636
tls: ldap-server-tls
readDeadline: 5m
writeDeadline: 5m
rootDSE:
attributes:
namingContexts:
- dc=example,dc=com
authentication:
allowAnonymous: false
methods:
simple:
enabled: true
authenticateSE:
file: /etc/maverics/extensions/authenticate.go
funcName: Authenticate
search:
searchSE:
file: /etc/maverics/extensions/search.go
funcName: Search
```
#### Configuration Reference
The `ldapProvider` top-level key configures the virtual LDAP directory server. Unlike other modes, LDAP Provider does not use app entries -- all configuration is at the provider level.
| Key | Type | Default | Required | Description |
| ----------------------------------------------------------- | ------- | ------- | ----------- | ------------------------------------------------------------------------------------------ |
| `ldapProvider.enabled` | boolean | `false` | Yes | Enable the LDAP Provider |
| `ldapProvider.uri` | string | -- | Yes | LDAP listen URI -- `ldap://` for plain or `ldaps://` for TLS (e.g., `ldaps://0.0.0.0:636`) |
| `ldapProvider.tls` | string | -- | Conditional | Named TLS profile -- required when URI scheme is `ldaps://` |
| `ldapProvider.readDeadline` | string | -- | No | Read I/O timeout (duration string, e.g., `5m`, `30s`) |
| `ldapProvider.writeDeadline` | string | -- | No | Write I/O timeout (duration string, e.g., `5m`, `30s`) |
| `ldapProvider.rootDSE.attributes` | object | -- | No | Custom Root DSE attributes exposed to LDAP clients (e.g., `namingContexts`) |
| `ldapProvider.search.searchSE` | object | -- | No | Service Extension for handling LDAP search operations |
| `ldapProvider.authentication.allowAnonymous` | boolean | `false` | No | Allow anonymous LDAP bind operations |
| `ldapProvider.authentication.methods.simple.enabled` | boolean | `false` | No | Enable simple bind authentication |
| `ldapProvider.authentication.methods.simple.authenticateSE` | object | -- | Conditional | Service Extension for simple bind authentication -- required when simple auth is enabled |
## Root DSE
The Root DSE (DSA-Specific Entry) is the entry an LDAP client reads when connecting to discover directory capabilities. Custom attributes allow the virtual directory to present itself with the expected naming contexts and supported features.
Root DSE attributes are configured via YAML only. The Console UI manages the core LDAP Provider settings (enable, protocol, URI, TLS, search SE, authentication) in the Deployment Settings dialog. See the Configuration tab for Root DSE attribute configuration.
```yaml theme={null}
ldapProvider:
rootDSE:
attributes:
namingContexts:
- dc=example,dc=com
```
## Authentication Methods
### Simple Bind
Simple bind authentication uses a DN and password to authenticate. The `authenticateSE` Service Extension handles the actual credential validation -- typically by bridging the LDAP bind to an OIDC Resource Owner Password Credentials (ROPC) grant against an upstream identity provider.
Simple bind authentication Service Extension paths are configured via YAML only. In the Console, you enable simple auth and select the Service Extension from the dropdown in Deployment Settings. The YAML format shown here provides the same configuration with explicit file path and function name.
```yaml theme={null}
ldapProvider:
authentication:
allowAnonymous: false
methods:
simple:
enabled: true
authenticateSE:
file: /etc/maverics/extensions/authenticate.go
funcName: Authenticate
```
The `authenticateSE` receives the bind DN and password, and returns a boolean indicating success or failure. This is the most common pattern for bridging LDAP authentication to modern identity providers.
**Illustrative example only.** The following Service Extension uses hardcoded credentials for testing. A production implementation would validate credentials against your upstream identity provider. See the [Service Extensions reference](/reference/orchestrator/service-extensions) for production patterns.
```go simple.go theme={null}
import (
"strings"
"github.com/strata-io/service-extension/orchestrator"
)
// This is an example Simple Authentication Service Extension that shows a quick way
// to test a Bind request using the Simple Authentication method between the
// application and the Orchestrator. In this example, only a user with the username
// of `bob` and the password of `th3Bu!ld3R` to be authenticated.
//
// A production version of this Service Extension would typically retrieve the
// password hash of the user from either `api.Cache` or `api.Session` and would
// compute the hash of the password received and compare it with the one stored. The
// user is typically a short-lived / one-time user created by an Orchestrator serving
// as the identity-aware proxy, after the end-user has been authenticated by
// the configured IdP.
func Authenticate(api orchestrator.Orchestrator, username string, password string) (bool, error) {
api.Logger().Debug(
"service", "LDAP Provider",
"extension", "Authenticate",
"msg", "authenticating user",
"username", username,
)
if strings.EqualFold(username, "bob") && password == "th3Bu!ld3R" {
api.Logger().Debug(
"service", "LDAP Provider",
"extension", "Authenticate",
"msg", "user authenticated",
"username", username,
)
return true, nil
}
api.Logger().Debug(
"service", "LDAP Provider",
"extension", "Authenticate",
"msg", "user not authenticated",
"username", username,
)
return false, nil
}
```
## Search Handling
LDAP search operations are handled by the `searchSE` Service Extension. This allows the virtual directory to translate LDAP search requests into queries against upstream identity sources.
Search Service Extension configuration follows the same pattern as the Console -- in the Console, you select the Search Service Extension from the dropdown in Deployment Settings. The YAML format provides the explicit file path and function name.
```yaml theme={null}
ldapProvider:
search:
searchSE:
file: /etc/maverics/extensions/search.go
funcName: Search
```
The search Service Extension receives the LDAP search request (base DN, scope, filter, attributes) and returns matching entries. This enables the virtual directory to present cloud identity data in the LDAP format that consuming applications expect.
**Illustrative example only.** The following Service Extension returns hardcoded attributes for a test user. A production implementation would query your upstream identity provider or attribute source for real user data. See the [Service Extensions reference](/reference/orchestrator/service-extensions) for production patterns.
```go search.go theme={null}
import (
"strings"
"github.com/strata-io/service-extension/ldap"
"github.com/strata-io/service-extension/orchestrator"
)
// This is an example of an Search Service Extension and shows a simple way to verify
// the LDAP connection between the application and the Orchestrator. It is configured
// to return hard-coded attributes for a test user, regardless of the Search request
// received.
//
// A production version will be dependant on the application and environment; however,
// typically, attributes originate from the end-users Session and would NOT be
// hardcoded. For example, if the policy requires a user to be authenticated
// using Entra ID, then the attributes would likely come from Entra ID, and stored
// on the cache via the Orchestrator servicing as the proxy for the application.
func Search(api orchestrator.Orchestrator, dn string, filter string, reqAttrs []string) (map[string]map[string]interface{}, error) {
api.Logger().Debug(
"service", "LDAP Provider",
"extension", "Search",
"msg", "processing request",
"user", ldap.BindDN(api.Context()),
"dn", dn,
"filter", filter,
"attributes", strings.Join(reqAttrs, ","),
)
result := make(map[string]map[string]interface{})
// User attributes would typically originate from the users Session and would NOT
// be hardcoded. For example, if the policy requires a user to be authenticated
// using Entra ID, then the attributes would likely come from Entra ID.
userAttrs := make(map[string]interface{})
userAttrs["Name"] = "Test User"
userAttrs["mail"] = "test.user@acme.org"
userAttrs["givenName"] = "Test"
userAttrs["sn"] = "User"
result["CN=Test,CN=Domain Users,CN=Users,DC=acme,DC=local"] = userAttrs
api.Logger().Debug(
"service", "LDAP Provider",
"extension", "Search",
"msg", "request processed",
"dn", dn,
"filter", filter,
"attributes", strings.Join(reqAttrs, ","),
)
return result, nil
}
```
## Service Extension Hooks
The LDAP Provider relies on Service Extensions for its core operations. Service Extensions are Go source files referenced by file path and function name.
| Hook | Location | Purpose |
| ---------------- | ---------------------------------------------- | --------------------------------------------------------------------------------------- |
| `authenticateSE` | `authentication.methods.simple.authenticateSE` | Handles simple bind authentication -- receives DN and password, returns success/failure |
| `searchSE` | `search.searchSE` | Handles LDAP search operations -- receives search parameters, returns matching entries |
Service Extensions use the `file` and `funcName` fields to specify the Go source file and entry point function:
Service Extension file paths and function names are configured via YAML only. In the Console, Service Extensions are selected from dropdowns in the Deployment Settings dialog.
```yaml theme={null}
authenticateSE:
file: /etc/maverics/extensions/authenticate.go
funcName: Authenticate
```
## Related Integrations
The LDAP Provider mode works with all Identity Fabric connectors. The Orchestrator sources identity data from any upstream IdP and presents it as LDAP entries. These are the most commonly used pairings:
Microsoft Entra ID as LDAP backend
Okta as LDAP backend
LDAP directory as attribute source
AD as attribute source
See the [connector compatibility matrix](/guides/authentication/choosing-a-mode#connector-compatibility) for all supported pairings and the [Identity Fabric overview](/reference/orchestrator/identity-fabric) for the full connector list.
The LDAP Provider also pairs with:
* **[HTTP Proxy](/reference/modes/http-proxy)** -- Pair with HTTP Proxy mode for applications that need both LDAP directory access and header-based authentication
* **[Caches](/reference/orchestrator/caches)** -- Shared cache for facade deployments and directory lookup caching
## Troubleshooting
**Symptoms:** The application receives LDAP error code 49 (`invalidCredentials`) when attempting to bind.
**Causes:**
* The `authenticateSE` Service Extension is returning a failure response.
* The upstream identity provider is rejecting the translated credentials.
* The ROPC (Resource Owner Password Credentials) grant type is not enabled on the upstream IdP application.
**Resolution:**
* Check the `authenticateSE` logs for the specific upstream authentication error.
* Verify the upstream identity provider supports the ROPC (password grant) flow and that it is enabled on the application registration.
* Confirm the client ID and client secret configured on the upstream connector are correct.
**Symptoms:** The application connects and binds successfully but LDAP search operations return no entries.
**Causes:**
* The `searchSE` Service Extension is not matching the incoming search filter.
* The upstream identity source query is returning empty results.
* The base DN in the search request does not match the directory's naming contexts.
**Resolution:**
* Add logging in the `searchSE` to inspect the incoming search parameters (base DN, scope, filter).
* Verify the upstream data source contains entries that match the search criteria.
* Check that `rootDSE.attributes.namingContexts` matches the base DN the application queries.
**Symptoms:** The LDAP client cannot connect to the Orchestrator. Logs show "TLS handshake failed" or similar errors.
**Causes:**
* The TLS certificate does not match the hostname the client connects to.
* The TLS certificate has expired.
* The client does not trust the certificate authority (CA) that signed the LDAP server certificate.
**Resolution:**
* Verify the TLS certificate's Subject Alternative Names (SANs) cover the hostname the client uses to connect.
* Check the certificate expiry date and renew if needed.
* Ensure the LDAP client trusts the CA that signed the server certificate (install the CA certificate in the client's trust store).
**Symptoms:** The LDAP client hangs and eventually times out without receiving an error response.
**Causes:**
* A firewall is blocking the LDAP port (389 for `ldap://` or 636 for `ldaps://`).
* `ldapProvider.enabled` is not set to `true` in the Orchestrator configuration.
* URI scheme mismatch -- the client is connecting with `ldaps://` but the Orchestrator is listening on `ldap://` (or vice versa).
**Resolution:**
* Verify the Orchestrator is listening on the expected port (`ldap://` defaults to 389, `ldaps://` defaults to 636).
* Check firewall rules to confirm the LDAP port is open between the client and the Orchestrator.
* Confirm `ldapProvider.enabled: true` is set in the configuration.
**Symptoms:** LDAP bind succeeds for credentials generated by the same Orchestrator instance but fails for credentials from a separate HTTP Proxy Orchestrator in a facade deployment.
**Causes:**
* No shared cache is configured between the HTTP Proxy and LDAP Provider Orchestrator instances. The LDAP Provider cannot look up the one-time credentials generated by the proxy instance.
**Resolution:**
* Configure a shared [Redis cache](/reference/orchestrator/caches/redis) that both Orchestrator instances can access.
* Reference the shared cache in both the HTTP Proxy and LDAP Provider configurations so credentials generated by the proxy are available to the LDAP Provider.
## Related Pages
Protect applications with reverse proxy mode -- often paired with LDAP Provider
Connect upstream identity providers to the Orchestrator
Understand how modes fit into the Orchestrator architecture
Configure the Orchestrator as an OpenID Connect authorization server
# OIDC Provider
Source: https://docs.strata.io/reference/modes/oidc-provider
The OIDC Provider mode configures the Maverics Orchestrator as an OpenID Connect authorization server. It sits between your applications and upstream identity providers -- handling authentication flows, enriching claims from multiple sources, and providing seamless IdP failover without application changes.
**When to use this mode**
* **OIDC Provider** -- Choose this mode when your applications support OpenID Connect. Best for modern apps that can consume OIDC tokens natively.
* **SAML Provider** -- Choose this mode for applications that only support SAML 2.0 assertions.
* **HTTP Proxy** -- Choose this mode when you cannot modify the application's authentication code.
* **LDAP Provider** -- Choose this mode for applications that require an LDAP directory for authentication.
* **AI Identity Gateway** -- Choose this mode for securing AI agent-to-tool communication via MCP.
## Use Cases
* **SSO consolidation** -- Unify multiple identity providers behind a single OIDC-compliant interface, giving users one login experience across all applications.
* **IdP migration with zero downtime** -- Route authentication traffic between old and new identity providers during migration without disrupting end users.
* **Legacy app modernization via OIDC** -- Add OpenID Connect support to applications that previously relied on proprietary or outdated authentication mechanisms.
* **Claim enrichment from multiple sources** -- Aggregate user attributes from directories, databases, and APIs into a single enriched token for downstream applications.
## How It Works
The OIDC Provider authentication flow follows these steps:
1. **Application redirects** -- A user accesses an application registered as an OIDC relying party. The application redirects the user to the Orchestrator's authorization endpoint.
2. **Upstream authentication** -- The Orchestrator routes the user to the configured upstream identity provider (Microsoft Entra ID, Okta, etc.) for authentication. If multiple IdPs are configured, failover rules determine which to use.
3. **Attribute enrichment** -- After authentication, the Orchestrator loads additional attributes from configured attribute providers (directories, databases, APIs) and enriches the user's profile.
4. **Token issuance** -- The Orchestrator generates OIDC tokens (ID token, access token, optional refresh token) with claims mapped from the authenticated identity and enriched attributes.
5. **Application receives tokens** -- The application receives the tokens at its redirect URI and uses them for session establishment and authorization decisions.
6. **Ongoing token operations** -- The Orchestrator serves the JWKS endpoint for token verification, handles token introspection and revocation, and manages token refresh flows.
## Key Concepts
### Provider vs Apps
The OIDC Provider has two configuration levels: provider-level settings (issuer, endpoints, signing keys) shared across all OIDC apps, and individual app entries that each register a specific relying party (client application) with its own credentials, scopes, and claims mapping. One Orchestrator can serve many OIDC apps.
### Claims Mapping
Claims mapping translates attributes from upstream identity providers into OIDC token claims. The format `connector.attribute` (e.g., `upstream-idp.email`) references a specific claim from a named connector. This enables enriching tokens with data from multiple identity sources.
### IdP Failover
When multiple identity providers are listed under `authentication.idps`, the Orchestrator tries them in order. If the primary IdP is unavailable, authentication falls back to the next provider seamlessly -- no application changes required.
### Token Types
The Orchestrator issues two token formats: JWT tokens (self-contained, verified via JWKS) and opaque tokens (reference tokens, verified via introspection). Choice depends on whether resource servers can validate locally or must call back.
### Service Extensions
Go-based extension hooks allow custom logic at key points in the flow -- custom authentication checks, custom claim building, and custom attribute loading. These provide escape hatches when standard configuration is insufficient.
## Setup
In the Maverics Console, OIDC Provider settings are configured in the **Deployment Settings** dialog under the OIDC Provider section.
**Issuer and Endpoints**
| Field | Required | Description |
| ------------- | -------- | ------------------------------------------------------------------------------------------------------ |
| Issuer | Yes | Case-sensitive HTTPS URL that identifies this OIDC Provider. Used as the `iss` claim in issued tokens. |
| Generate | -- | Button that auto-generates all endpoint URLs from the Issuer domain. |
| Well-Known | Yes | OIDC discovery endpoint (auto-generated from Issuer). |
| Authorization | Yes | Authorization endpoint for login flows (auto-generated). |
| Token | Yes | Token endpoint for code exchange and refresh (auto-generated). |
| Introspect | Yes | Token introspection endpoint (auto-generated). |
| Revocation | Yes | Token revocation endpoint (auto-generated). |
| End Session | Yes | End session / logout endpoint (auto-generated). |
**User Info Claims**
| Field | Required | Description |
| ------------------------- | -------- | -------------------------------------------------------------------------------- |
| User Info | Yes | UserInfo endpoint URL (auto-generated from Issuer). |
| Build User Info Claims SE | No | Dropdown to select a Service Extension for customizing UserInfo response claims. |
**JSON Web Keys**
| Field | Required | Description |
| ---------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| JWKS | Yes | JWKS endpoint URL for publishing public keys (auto-generated from Issuer). |
| Edit JSON Web Keys | -- | Button to open the JWK editor drawer, where keys are added, removed, and configured. |
| Use RFC 7638 thumbprint for key ID | No | Per-key toggle in the JWK editor. When on, the published key ID (`kid`) is the canonical [RFC 7638](https://datatracker.ietf.org/doc/html/rfc7638) JWK thumbprint; when off, a pre-RFC-7638 legacy `kid` is used for backward compatibility. New keys default to **on**. The toggle is only available when creating a key — changing the algorithm for an existing key requires deleting and recreating it in the editor, or managing the key in YAML. |
**Additional Settings**
| Field | Required | Description |
| ------------------- | -------- | ------------------------------------------------------------------------------ |
| Redis Cache | No | Dropdown to select a configured Redis cache. Defaults to in-memory if not set. |
| Session Correlation | No | Toggle to correlate OIDC sessions with HTTP sessions. |
The Console UI provides a subset of the full YAML configuration. Options like `buildUserInfoClaimsSE` parameters, advanced JWKS algorithm settings, and per-app grant type selection are only available in YAML or at the [app level](/reference/orchestrator/applications/oidc). The Console auto-generates endpoints from the Issuer URL; in YAML, each endpoint is set independently.
The OIDC Provider mode requires two configuration levels: the `oidcProvider` top-level key for authorization server settings, and one or more `apps` entries with `type: oidc` for client applications.
```yaml theme={null}
version: 0.0.1
http:
address: 0.0.0.0:443
tls: server
tls:
server:
certFile: /etc/maverics/certs/server.pem
keyFile: /etc/maverics/certs/server-key.pem
upstream-idp:
caFile: /etc/maverics/certs/ca.pem
session:
cookie:
name: auth_session
lifetime:
maxTimeout: 24h
idleTimeout: 15m
connectors:
- name: upstream-idp
type: oidc
tls: upstream-idp
oidcWellKnownURL: https://idp.example.com/.well-known/openid-configuration
oauthClientID: my-oidc-provider
oauthClientSecret:
oauthLoginRedirect:
urls:
- https://auth.example.com/oidc-callback
oauthLogoutRedirect:
urls:
- https://auth.example.com/logout
scopes: openid profile email
oidcProvider:
correlateSession: true
discovery:
issuer: https://auth.example.com
endpoints:
wellKnown: https://auth.example.com/.well-known/openid-configuration
jwks: https://auth.example.com/oauth2/jwks
auth: https://auth.example.com/oauth2/auth
token: https://auth.example.com/oauth2/token
userinfo: https://auth.example.com/oauth2/userinfo
introspect: https://auth.example.com/oauth2/introspect
jwks:
- algorithm: RSA256
publicKey:
privateKey:
apps:
- name: my-spa
type: oidc
clientID: my-spa
credentials:
secrets:
-
redirectURLs:
- https://spa.example.com/callback
authentication:
idps:
- upstream-idp
accessToken:
type: jwt
claimsMapping:
email: upstream-idp.email
name: upstream-idp.name
```
#### Configuration Reference
The `oidcProvider` top-level key configures the authorization server behavior shared across all OIDC apps. It defines the issuer identity, OIDC discovery endpoints, signing keys (JWKS), and optional session correlation. Every OIDC app served by this Orchestrator instance uses these provider-level settings.
| Key | Type | Required | Description |
| --------------------------------------------- | ------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `oidcProvider.discovery.issuer` | String | Yes | Issuer URL used in OIDC discovery and the `iss` claim in tokens |
| `oidcProvider.discovery.endpoints.wellKnown` | String | No | OIDC discovery endpoint path (typically `/.well-known/openid-configuration`) |
| `oidcProvider.discovery.endpoints.jwks` | String | No | JWKS endpoint path for publishing public keys |
| `oidcProvider.discovery.endpoints.auth` | String | No | Authorization endpoint path |
| `oidcProvider.discovery.endpoints.token` | String | No | Token endpoint path |
| `oidcProvider.discovery.endpoints.userinfo` | String | No | UserInfo endpoint path |
| `oidcProvider.discovery.endpoints.introspect` | String | No | Token introspection endpoint path (RFC 7662) |
| `oidcProvider.discovery.endpoints.revoke` | String | No | Token revocation endpoint path (RFC 7009) |
| `oidcProvider.discovery.endpoints.endSession` | String | No | End session (logout) endpoint path |
| `oidcProvider.jwks[].algorithm` | String | Yes | Signing algorithm (`RSA256` is the only supported value) |
| `oidcProvider.jwks[].publicKey` | String | No\* | PEM-encoded public key. \*Required for production. If omitted, the Orchestrator auto-generates an ephemeral key pair (not suitable for production). |
| `oidcProvider.jwks[].privateKey` | String | No\* | PEM-encoded private key. \*Required for production. If omitted, the Orchestrator auto-generates an ephemeral key pair (not suitable for production). |
| `oidcProvider.jwks[].useRFC7638Thumbprint` | Boolean | No | Selects the key ID (`kid`) algorithm. Defaults to `false` (legacy, pre-RFC-7638 algorithm) for backward compatibility with deployments whose relying parties have already cached the legacy `kid`. Set to `true` to publish the canonical [RFC 7638](https://datatracker.ietf.org/doc/html/rfc7638) JWK thumbprint; recommended for new keys. Changing this on an in-use key changes the `kid`, which breaks relying parties that cache or pin it — rotate to a new key instead. |
| `oidcProvider.cache` | String | No | Name of a cache to use (references a `caches` entry) |
| `oidcProvider.correlateSession` | Boolean | No | Correlate OIDC sessions with HTTP sessions |
| `oidcProvider.buildUserInfoClaimsSE` | Object | No | Service extension for customizing the UserInfo response claims |
If the `jwks` array is omitted, the Orchestrator auto-generates an RSA key pair at startup. This key pair is **ephemeral** -- a new key pair is generated on every restart, invalidating all previously issued tokens. Auto-generation is intended only for local development and testing. Production deployments should always provide explicit keys using [secret provider](/guides/security/secrets-management) references (e.g., ``, ``).
When config reload is enabled (`MAVERICS_RELOAD_CONFIG=true`) and the Orchestrator uses an auto-generated signing key, a reload rotates the key and invalidates any tokens or in-flight authorization flows issued before the reload. To preserve token validity across reloads, configure a static signing key in your OIDC Provider settings.
#### OIDC App Configuration
Each OIDC client application is registered under the `apps` array with `type: oidc`. App configuration includes client credentials, grant types, redirect URLs, claims mapping, token settings, DPoP, and CORS.
Full configuration reference, Console UI setup steps, and troubleshooting for OIDC apps
#### Key Rotation
The `oidcProvider.jwks` field is an array, supporting multiple key pairs for seamless key rotation. The first entry in the array is the **active signing key** used to sign new tokens. Additional entries are published in the JWKS endpoint so that resource servers can still verify tokens signed with previous keys.
To rotate keys:
1. Generate a new key pair.
2. Insert the new key pair as the first entry in the `jwks` array.
3. Move the old key pair to a later position in the array.
4. Deploy the updated configuration. New tokens are signed with the new key; existing tokens remain verifiable.
5. After all tokens signed with the old key have expired, remove the old entry.
Key rotation is managed via YAML only. The Console UI allows editing the current JSON Web Keys through the **Edit JSON Web Keys** button in Deployment Settings, but multi-key rotation (maintaining old keys alongside new ones for seamless verification) requires direct YAML configuration.
```yaml theme={null}
oidcProvider:
jwks:
# Active signing key (signs new tokens)
- algorithm: RSA256
publicKey:
privateKey:
useRFC7638Thumbprint: true
# Previous key (still published in JWKS for verification)
- algorithm: RSA256
publicKey:
privateKey:
```
## Related Integrations
The OIDC Provider mode works with all Identity Fabric connectors. The Orchestrator translates between any upstream IdP protocol and OIDC tokens for your applications. These are the most commonly used pairings:
Microsoft Entra ID for enterprise SSO
Okta SSO consolidation
Any OIDC-compliant provider
IdP failover and migration
See the [connector compatibility matrix](/guides/authentication/choosing-a-mode#connector-compatibility) for all supported pairings and the [Identity Fabric overview](/reference/orchestrator/identity-fabric) for the full connector list.
The OIDC Provider also pairs with:
* **[Secret Providers](/reference/orchestrator/configuration/secret-providers)** -- Store signing keys and client secrets securely
* **[Caches](/reference/orchestrator/caches)** -- Distributed token and session storage with Redis
## Related Pages
Client application configuration, setup steps, and troubleshooting for OIDC apps
Configure the Orchestrator as a SAML 2.0 identity provider for federation
Connect upstream identity providers to the Orchestrator
Understand how modes fit into the Orchestrator architecture
Protect applications without code modification using reverse proxy mode
# SAML Provider
Source: https://docs.strata.io/reference/modes/saml-provider
The SAML Provider mode configures the Maverics Orchestrator as a SAML 2.0 identity provider. It handles SAML assertion generation, attribute mapping, and protocol translation -- allowing you to federate enterprise applications that depend on SAML while connecting to modern or legacy upstream identity providers.
**When to use this mode**
* **SAML Provider** -- Choose this mode for applications that only support SAML 2.0. Best for enterprise apps with rigid SAML requirements.
* **OIDC Provider** -- Choose this mode for modern applications that can consume OpenID Connect tokens natively.
* **HTTP Proxy** -- Choose this mode for applications that cannot handle SAML directly or where you cannot modify authentication code.
* **LDAP Provider** -- Choose this mode for applications that require an LDAP directory for authentication.
* **AI Identity Gateway** -- Choose this mode for securing AI agent-to-tool communication via MCP.
## Use Cases
* **SAML federation for enterprise apps** -- Provide SAML 2.0 assertions to enterprise applications like Salesforce, ServiceNow, and Workday that require SAML-based single sign-on.
* **Protocol translation (OIDC-to-SAML)** -- Bridge modern OIDC identity providers to legacy SAML-dependent applications without modifying either side.
* **IdP migration for SAML-dependent apps** -- Migrate SAML service providers from one identity provider to another with zero downtime and no SP reconfiguration.
* **Attribute mapping and enrichment** -- Enrich SAML assertions with attributes sourced from multiple directories, databases, and APIs beyond what the upstream IdP provides.
## How It Works
The SAML Provider authentication flow follows these steps:
1. **SP-initiated request** -- A user accesses a SAML service provider. The SP generates a SAML AuthnRequest and redirects the user to the Orchestrator's SSO endpoint.
2. **Upstream authentication** -- The Orchestrator routes the user to the configured upstream identity provider for authentication. The upstream IdP can use any protocol (OIDC, SAML, LDAP) -- the Orchestrator handles protocol translation.
3. **Attribute enrichment** -- After authentication, the Orchestrator loads additional attributes from configured attribute providers and merges them with the authenticated identity.
4. **Assertion generation** -- The Orchestrator generates a signed SAML assertion containing the NameID and mapped claims from the authenticated identity and enriched attributes.
5. **SP receives assertion** -- The SAML response (containing the signed assertion) is POSTed to the SP's assertion consumer service URL. The SP validates the signature and establishes a session.
6. **IdP-initiated flow (optional)** -- Users can also start from the Orchestrator's IdP-initiated login URL, which generates an assertion and sends it directly to the SP without an AuthnRequest.
## Key Concepts
### Provider vs Apps
The SAML Provider has two configuration levels: provider-level settings (issuer, SSO/SLO endpoints, signing material) shared across all SAML apps, and individual app entries that each register a specific service provider with its own entity ID, ACS URL, NameID format, and claims mapping.
### Protocol Translation
The Orchestrator can translate between protocols -- an upstream OIDC identity provider can feed a downstream SAML service provider, or vice versa. The service provider only sees SAML; the identity provider only sees OIDC. This makes IdP migration possible without changing SP configurations.
### Assertion Signing
By default, both the SAML assertion and the SAML response are signed using the provider's signing material. Individual apps can override signing behavior (e.g., disable assertion signing for SPs that don't verify it) or use per-app signing keys.
### NameID and Claims
The NameID identifies the authenticated subject in the SAML assertion. Claims mapping uses the same `connector.attribute` format as OIDC, translating connector attributes into SAML assertion attributes.
### Request Verification
When service providers sign their AuthnRequest messages, the Orchestrator verifies the signature using the SP's certificate. This can be skipped for SPs that don't sign requests.
## Setup
In the Maverics Console, SAML Provider settings are configured in the **Deployment Settings** dialog under the SAML Provider section.
**Issuer and Endpoints**
| Field | Required | Description |
| -------------- | -------- | ----------------------------------------------------------------------------------- |
| Issuer | Yes | Unique SAML IdP identifier (Entity ID). Typically the base URL of the Orchestrator. |
| Generate | -- | Button that auto-generates endpoint URLs from the Issuer. |
| Metadata | No | SAML metadata endpoint URL (auto-generated from Issuer). |
| Single Sign-on | Yes | SSO endpoint URL for receiving AuthnRequest messages (auto-generated). |
| Single Logout | Yes | SLO endpoint URL (auto-generated). |
**Signing**
| Field | Required | Description |
| -------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Signing Option | Yes | Dropdown to select what is signed. Options: "Response and Assertion" (default), "Response Only", "Assertion Only". |
| Edit | -- | Button to edit the private key and public key (certificate) pair used for signing SAML responses and assertions. The signature properties can be overridden per-app. |
**Additional Settings**
| Field | Required | Description |
| ----------- | -------- | ------------------------------------------------------------------------------------------------------------------------------- |
| Redis Cache | No | Dropdown to select a configured Redis cache for SAML request data and provider state storage. Defaults to in-memory if not set. |
The Console UI provides a subset of the full YAML configuration. Per-app signature overrides, assertion encryption settings, and advanced request verification options are configured at the app level and are only available in YAML. See the [Configuration tab](#setup) for the complete reference.
The following example configures the Orchestrator as a SAML 2.0 identity provider with one SAML service provider application. The `samlProvider` block defines the IdP-wide settings (issuer, endpoints, signing), while each `saml` app defines a service provider registration.
```yaml theme={null}
samlProvider:
issuer: https://auth.example.com
cache: redis-cache
endpoints:
metadata: https://auth.example.com/saml/metadata
singleSignOnService: https://auth.example.com/saml/sso
singleLogoutService: https://auth.example.com/saml/slo
signature:
certificate:
privateKey:
apps:
- name: my-saml-app
type: saml
entityIDs:
- identifier: https://sp.example.com
default: true
consumerServiceURLs:
- url: https://sp.example.com/acs
default: true
logoutServiceURL: https://sp.example.com/logout
duration: 300
nameID:
format: urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
attrMapping: upstream-idp.email
requestVerification:
skipVerification: true
authentication:
idps:
- upstream-idp
claimsMapping:
email: upstream-idp.email
firstName: upstream-idp.given_name
lastName: upstream-idp.family_name
idpInitiatedLogin:
loginURL: https://auth.example.com/saml/sso/my-saml-app
relayStateURL: https://sp.example.com/
```
#### Configuration Reference
The `samlProvider` top-level key configures the Orchestrator as a SAML 2.0 identity provider. This block defines the IdP issuer, SAML endpoints, signing material, and cache. All `saml` type apps require `samlProvider` to be configured.
| Key | Type | Required | Default | Description |
| ---------------------------------- | ------- | ----------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `issuer` | string | Yes | -- | SAML EntityID for the identity provider. Typically the base URL of the Orchestrator (e.g., `https://auth.example.com`). |
| `endpoints.metadata` | string | Yes | -- | URL where the IdP publishes SAML metadata XML. |
| `endpoints.singleSignOnService` | string | Yes | -- | URL for the SAML SSO endpoint that receives `AuthnRequest` messages. |
| `endpoints.singleLogoutService` | string | Yes | -- | URL for the SAML Single Logout endpoint. |
| `signature.certificate` | string | Conditional | -- | PEM-encoded X.509 certificate for signing SAML assertions and responses. Inline value. Mutually exclusive with `certificateFile`. |
| `signature.certificateFile` | string | Conditional | -- | File path to the X.509 certificate. Mutually exclusive with `certificate`. |
| `signature.privateKey` | string | Conditional | -- | PEM-encoded private key for signing. Inline value. Mutually exclusive with `privateKeyFile`. |
| `signature.privateKeyFile` | string | Conditional | -- | File path to the private key. Mutually exclusive with `privateKey`. |
| `signature.disableSignedAssertion` | boolean | No | `false` | When `true`, SAML assertions are not signed. See [Signed and Unsigned Assertions](/reference/orchestrator/applications/saml#signed-and-unsigned-assertions). |
| `signature.disableSignedResponse` | boolean | No | `false` | When `true`, SAML responses are not signed. See [Signed and Unsigned Assertions](/reference/orchestrator/applications/saml#signed-and-unsigned-assertions). |
| `cache` | string | No | -- | Name of a configured cache (Redis) for SAML request data and provider state storage. References a `caches[]` entry by name. |
Signing material must be provided as either inline values (`certificate` + `privateKey`) or file paths (`certificateFile` + `privateKeyFile`). Use secret references (e.g., ``) for inline values to avoid storing credentials in config files.
#### SAML App Configuration
Each SAML Service Provider is registered under the `apps` array with `type: saml`. App configuration includes entity IDs, assertion consumer service URLs, NameID format, claims mapping, signing overrides, request verification, IdP-initiated login, and assertion encryption.
Full configuration reference, Console UI setup steps, and troubleshooting for SAML apps
## Related Integrations
The SAML Provider mode works with all Identity Fabric connectors. The Orchestrator translates between any upstream IdP protocol and SAML assertions for your applications. These are the most commonly used pairings:
Microsoft Entra ID for enterprise SSO
Okta SSO consolidation
Any SAML 2.0-compliant provider
Any OIDC provider (protocol translated to SAML)
IdP failover and migration
See the [connector compatibility matrix](/guides/authentication/choosing-a-mode#connector-compatibility) for all supported pairings and the [Identity Fabric overview](/reference/orchestrator/identity-fabric) for the full connector list.
The SAML Provider also pairs with:
* **[Secret Providers](/reference/orchestrator/configuration/secret-providers)** -- Store signing certificates and encryption keys securely
## Related Pages
SAML app configuration reference, Console UI setup, and troubleshooting
Configure the Orchestrator as an OpenID Connect authorization server
Connect upstream identity providers to the Orchestrator
Understand how modes fit into the Orchestrator architecture
Protect applications without code modification using reverse proxy mode
# Applications
Source: https://docs.strata.io/reference/orchestrator/applications
Applications represent the services you are protecting with the Maverics Orchestrator. When you set up a deployment, you configure three things: **identity providers** (where users authenticate), **applications** (what you are protecting), and the **policies** that connect them. Applications are the "what" -- each one describes a service the Orchestrator manages on behalf of your users.
## How Applications Fit into a Deployment
A typical Maverics deployment looks like this:
1. **Identity Fabric** -- connect one or more identity providers (Entra ID, Okta, LDAP, etc.) that authenticate your users
2. **Applications** -- register the services the Orchestrator protects, each with a type that matches how the service communicates (HTTP, OIDC, SAML, or MCP)
3. **Policies** -- define who can access what, which identity providers handle authentication, and what identity information flows to each application
The Orchestrator sits between your users and your applications. When a request comes in, the Orchestrator matches it to an application, authenticates the user or agent against the configured identity providers, evaluates authorization policies, and then takes the appropriate action -- forwarding the request with injected headers, issuing an OIDC or SAML token, or translating and proxying MCP tool calls to upstream services.
## Applications, Policies, and Identity Providers
In both the Maverics Console and YAML configuration, an application's authentication policies, header mappings, and identity provider bindings are configured directly on the application itself -- there is no separate object that ties them together.
The typical Console workflow is:
1. Create an **Identity Fabric** connector (e.g., Entra ID)
2. Create an **Application** (e.g., a proxy app for your legacy HR portal)
3. Configure the application's authentication policies, header mappings, and identity provider bindings to control sign-on behavior and what identity information reaches the application
In YAML, the same information is configured directly within each application's `policies`, `headers`, and `attrProviders` blocks.
## App Types and Orchestrator Modes
Each application has a type that determines which protocol it uses and which Orchestrator mode it connects to. Choose the app type that matches how your service communicates.
| App Type | Orchestrator Mode | Protocol | When to Use |
| ---------- | ----------------------------------------------------------- | ---------- | ---------------------------------------------------- |
| Proxy | [HTTP Proxy](/reference/modes/http-proxy) | HTTP | Legacy apps -- identity via headers, no code changes |
| OIDC | [OIDC Provider](/reference/modes/oidc-provider) | OIDC | Modern apps with native OpenID Connect support |
| SAML | [SAML Provider](/reference/modes/saml-provider) | SAML 2.0 | Enterprise apps requiring SAML assertions |
| MCP Proxy | [AI Identity Gateway](/reference/modes/ai-identity-gateway) | MCP | AI agents accessing upstream MCP servers |
| MCP Bridge | [AI Identity Gateway](/reference/modes/ai-identity-gateway) | MCP + REST | Expose REST APIs as MCP tools for AI agents |
**Looking for Custom APIs?** Custom API endpoints (the `apis[]` configuration) are not an application type. They are managed through [Service Extensions](/reference/orchestrator/service-extensions/custom-apis). In the Console, create and manage APIs from the **Service Extensions** area in the sidebar.
Not sure which type fits your service? See the [Choosing a Mode](/guides/authentication/choosing-a-mode) guide for a decision framework.
## App Type Pages
Each app type has its own page with Console UI setup steps and configuration reference.
Identity-aware reverse proxy for legacy and header-based applications
Register OIDC clients with the Orchestrator's built-in OIDC Provider
Register SAML Service Providers with the Orchestrator's SAML Provider
Proxy MCP traffic to upstream MCP servers with identity injection
Expose REST APIs as MCP tools using OpenAPI specifications
## Related Pages
Configure the identity providers that authenticate users for your applications
Authorization rules that control who can access what
Custom request/response modification and API endpoints
Session storage for user authentication state
Named TLS profiles for upstream connections and IdP communication
Decision framework for selecting the right Orchestrator mode
# MCP Bridge App
Source: https://docs.strata.io/reference/orchestrator/applications/mcp-bridge
Expose existing REST APIs as MCP tools for AI agents without any API code changes. The MCP Bridge app reads an OpenAPI specification and automatically generates a tool catalog that agents can discover and invoke through the Model Context Protocol. The Orchestrator handles MCP-to-REST translation, identity, and authorization -- so your REST APIs gain AI agent connectivity with zero modification.
## Overview
The MCP Bridge app type enables [AI Identity Gateway](/reference/modes/ai-identity-gateway) mode by translating between the Model Context Protocol and your existing REST APIs. It requires an [MCP Provider](/reference/modes/ai-identity-gateway#setup) to be configured. In bridge mode, the Orchestrator reads an OpenAPI specification and auto-generates an MCP tool catalog -- each operation with an `operationId` becomes a discoverable tool that AI agents can invoke. The Orchestrator enforces inbound authorization on agent requests and handles outbound token exchange when calling the upstream REST API.
## How It Works
The MCP Bridge operates as a translator between the MCP protocol and REST APIs:
1. **Agent discovers tools** -- MCP Bridge exposes your REST API endpoints as discoverable MCP tools. Agents see a catalog of tools with names, descriptions, and parameter schemas -- all generated from your OpenAPI spec.
2. **Agent requests tool** -- The AI agent invokes an MCP tool, which maps to a specific REST API endpoint. The agent provides parameters in MCP format; the Orchestrator handles the translation.
3. **Identity and authorization** -- The Orchestrator authenticates the agent via OAuth, then evaluates OPA policies before the request proceeds.
4. **Token exchange** -- The Orchestrator exchanges the agent's token for a delegation token scoped to the target REST API, preserving the user's identity through the agent-to-API chain.
5. **REST translation** -- The Orchestrator converts the MCP tool call into the corresponding REST API request, mapping parameters to path variables, query strings, headers, and request body as defined in the OpenAPI spec.
6. **Response translation** -- The REST API response is converted back into MCP format and returned to the agent, with audit logging capturing the complete interaction for compliance.
## Use Cases
* **Opening REST APIs to AI agents without API code changes** -- deploy the Orchestrator in front of existing REST APIs and let AI agents discover and call them through MCP, with no modifications to the API itself
* **Multi-API tool catalogs** -- aggregate tools from multiple REST APIs into a single MCP endpoint, giving agents a unified catalog of capabilities with tool namespacing to avoid name collisions
* **Compliance and audit** -- log every agent-to-tool interaction through the Orchestrator, providing a centralized audit trail of which agents called which tools, when, and on behalf of which users
* **Gradual AI adoption** -- start by exposing a few endpoints as MCP tools, then expand coverage over time as confidence grows, using per-tool authorization to control access at each step
## Key Concepts
### OpenAPI-Driven Tool Generation
MCP Bridge reads an OpenAPI specification and automatically generates an MCP tool catalog. Each `operationId` in the spec becomes a discoverable MCP tool. Parameter definitions in the spec determine how MCP tool inputs map to REST request components (path params, query params, headers, body). No manual tool definition is required -- the spec IS the tool catalog.
### Tool Namespacing
When multiple MCP Bridge apps serve tools from different APIs, tool names can collide. The `toolNamespace` feature adds a configurable prefix to all tool names from an app (e.g., `employee_directory_listEmployees`). This lets agents access tools from multiple APIs through a single MCP endpoint without ambiguity.
### Token Exchange for REST APIs
MCP Bridge uses RFC 8693 token exchange to convert the agent's inbound OAuth token into a scoped token for the target REST API. Each tool can have its own scopes and TTL, so a `listEmployees` tool gets `employee:List` scope while `createEmployee` gets `employee:Create` scope. The delegation token preserves both agent and user identity for audit.
### Inbound OPA Policies
Before any REST API call is made, OPA Rego policies evaluate the inbound MCP request. This provides a governance layer at the gateway -- blocking unauthorized tool calls before they reach the backend API. Policies can evaluate agent identity, requested tool name, and user attributes. See the [Authorization Policies guide](/guides/security/policies#opa-authorization-ai-identity-gateway) for the full OPA input schema, output schema, and example policies.
### Upstream Token Validation Best Practice
The target REST APIs do not need to know about MCP, agents, or the Orchestrator -- they receive standard REST requests with OAuth tokens, and the entire MCP-to-REST translation is transparent to the backend.
While no MCP-specific changes are required, it is best practice for upstream REST APIs to validate the received token. Specifically, upstreams should:
* **Validate the token signature and expiry** -- Confirm the token has not been tampered with and is still valid.
* **Confirm the issuer matches the Auth Provider Orchestrator** -- The `iss` claim should match the expected authorization server.
* **Verify the audience claim matches the API's own identifier** -- The `aud` claim should contain the API's registered audience.
* **Check that the token's scopes authorize the requested operation** -- The `scope` claim should include the permissions required for the specific endpoint.
This defense-in-depth approach ensures that even if the gateway is misconfigured or compromised, the upstream API independently enforces authorization.
## Setup
Go to **Applications** in the sidebar and click **Create**. Select **MCP Bridge App** from the application type list.
Enter a **Name** to identify this MCP Bridge application.
Tool namespacing is enabled by default. Enter a **Namespace** prefix for tool names (e.g., `employee_directory_`). Only alphanumeric characters, dots, dashes, and underscores are allowed. Disable the **Enable Tool Namespacing** toggle only if this is the sole MCP app.
Drag or click to upload an icon image (JPEG, PNG, or SVG, up to 2MB).
Click **Add** or drag and drop to upload your OpenAPI specification file (YAML or JSON format). Each operation with an `operationId` in the spec becomes a discoverable MCP tool.
Enter a **Base URL Override** if the actual API URL differs from what is defined in the OpenAPI spec. This is useful when the spec references a public URL but the Orchestrator connects to an internal address.
Under **Inbound Request Policy**, upload an OPA policy definition (.rego file) to enforce fine-grained access control for incoming MCP requests. Policies can evaluate agent identity, requested tool name, and user attributes.
Under **Outbound Request Authorization**, select the **Authorization Type** (Token Exchange). Choose the **Exchange Type**: **Delegation** (recommended -- preserves both agent and user identity) or **Impersonation** (fully assumes user identity). Select the **OIDC Identity Provider** and enter the **Audience** for the target REST API.
Click **Add Tool Configuration** to set per-tool authorization including custom token lifetimes and OAuth scopes. Tool names can be exact matches or regex patterns (prefix with `~ `).
Click **Save** to create the MCP Bridge application.
MCP Bridge apps are defined under the `apps` top-level key with `type: mcpBridge`:
#### Configuration Reference
| Key | Type | Required | Description |
| ------------------------------------------------------------------- | ------- | ----------- | ---------------------------------------------------------------------------------------------------------------- |
| `apps[].mode` | String | Yes | Bridge mode. Currently only `openapi` is supported. |
| `apps[].toolNamespace.disabled` | Boolean | No | Disable tool namespacing. When `false`, all tool names are prefixed with `toolNamespace.name`. |
| `apps[].toolNamespace.name` | String | No | Prefix for tool names (e.g., `api_`). Characters allowed: a-z, A-Z, 0-9, `.`, `-`, `_`. |
| `apps[].openapi.spec.uri` | String | Conditional | URI to the OpenAPI spec file (e.g., `file:///path/to/spec.yaml`). Mutually exclusive with `spec.data`. |
| `apps[].openapi.spec.data` | String | Conditional | Inline OpenAPI spec content. Mutually exclusive with `spec.uri`. |
| `apps[].openapi.baseURL` | String | No | Override the server URL from the OpenAPI spec. Used when the actual API URL differs from what the spec declares. |
| `apps[].authorization.inbound.opa.name` | String | No | Name identifier for the OPA policy. |
| `apps[].authorization.inbound.opa.file` | String | Conditional | Path to the Rego policy file. Mutually exclusive with `rego`. |
| `apps[].authorization.inbound.opa.rego` | String | Conditional | Inline Rego policy. Mutually exclusive with `file`. |
| `apps[].authorization.outbound.type` | String | No | Outbound authorization type: `tokenExchange` or `unprotected`. |
| `apps[].authorization.outbound.tokenExchange.type` | String | No | Token exchange type: `delegation` (default) or `impersonation`. |
| `apps[].authorization.outbound.tokenExchange.idp` | String | Conditional | Identity provider connector name for token exchange. Required when using token exchange. |
| `apps[].authorization.outbound.tokenExchange.audience` | String | Conditional | Token audience for the target API. Required when using token exchange. |
| `apps[].authorization.outbound.tokenExchange.tools[].name` | String | No | Tool name (exact) or regex pattern (`~ pattern`) for per-tool config. |
| `apps[].authorization.outbound.tokenExchange.tools[].ttl` | String | No | Access token lifetime for this tool (duration string, e.g., `5s`). |
| `apps[].authorization.outbound.tokenExchange.tools[].scopes[].name` | String | No | OAuth scope to request when exchanging tokens for this tool. |
#### OpenAPI-to-MCP Tool Conversion
MCP Bridge reads an OpenAPI specification and automatically generates an MCP tool catalog. Each operation in the spec becomes a discoverable MCP tool.
* **Spec loading** -- Use `openapi.spec.uri` with a `file://` URI to load the spec from a local file (e.g., `file:///etc/maverics/apps/api/openapi.yaml`). Alternatively, use `openapi.spec.data` to provide the spec inline. These two options are mutually exclusive.
* **Base URL override** -- `openapi.baseURL` overrides the `servers[].url` declared in the OpenAPI spec. This is useful when the spec references a public URL but the Orchestrator connects to an internal address.
* **Tool name generation** -- Tool names derive from the `operationId` values in the OpenAPI spec. For example, an operation with `operationId: listEmployees` becomes an MCP tool named `listEmployees` (or `employee_directory_listEmployees` with namespacing enabled).
* **Parameter mapping** -- The Orchestrator maps MCP tool input parameters to the appropriate REST request components (path parameters, query parameters, headers, and request body) based on the OpenAPI parameter definitions.
* **Response translation** -- REST API responses are converted back into MCP tool results. The Orchestrator handles status codes, response bodies, and error conditions.
MCP Bridge supports the `openapi` mode. The tool catalog is auto-generated from the spec -- no manual tool definition is required.
#### Token Exchange
MCP Bridge uses [RFC 8693](https://datatracker.ietf.org/doc/html/rfc8693) token exchange to obtain scoped tokens for outbound API calls. Token exchange supports two modes: delegation (default) and impersonation.
* **Delegation** (`tokenExchange.type: delegation`) -- Delegation is the default and recommended mode. The Orchestrator exchanges the agent's token for a delegation token that contains an `act` (actor) claim identifying the agent alongside the original user's identity. The target API sees both identities -- who the user is and which agent is acting on their behalf -- which supports auditability and least-surprise behavior for downstream services.
* **Impersonation** (`tokenExchange.type: impersonation`) -- The Orchestrator exchanges the agent's token for an impersonation token that fully assumes the user's identity, with no trace of agent involvement. The target API receives a token that looks like it came directly from the user, meaning audit trails at the downstream API will not show agent participation. Impersonation may be required when downstream APIs do not support the `act` claim pattern.
* **Token minting policies** -- When token exchange is processed by the [OIDC Provider](/reference/modes/oidc-provider), administrators can configure OPA-based token minting policies (`authorization.tokenMinting.accessToken.policies` on the OIDC Provider app) to control which tokens get issued. These policies evaluate the token exchange request context and can deny token issuance based on agent identity, requested scopes, audience, or delegating user attributes. This provides a governance layer over token exchange independent of the inbound OPA policies that control tool access.
* **Per-tool scopes** -- Each tool can have its own OAuth scopes and token TTL. This enables least-privilege access: a read-only tool gets `employee:List` scope, while a write tool gets `employee:Create` scope. Tool names support exact matching and regex patterns (prefix with `~`) for wildcarding.
Token exchange configuration for MCP Bridge apps is available via YAML only. The Console UI does not yet support configuring outbound authorization or per-tool token exchange settings.
```yaml theme={null}
authorization:
outbound:
type: tokenExchange
tokenExchange:
type: delegation
idp: oidc-provider
audience: https://api.example.com/
tools:
- name: listResources
ttl: 5s
scopes:
- name: resources:read
- name: "~ create.*"
ttl: 5s
scopes:
- name: resources:write
```
In the example above, the tool named `listResources` is matched exactly, while `~ create.*` uses a regex pattern to match any tool name starting with `create` (e.g., `createResource`, `createUser`). Per-tool token exchange ensures each tool invocation receives a minimally-scoped token.
The token exchange connects to the [OIDC Provider](/reference/modes/oidc-provider) for token issuance. The OIDC Provider must be configured with the `urn:ietf:params:oauth:grant-type:token-exchange` grant type to support token exchange requests.
#### Inbound Authorization (OPA)
MCP Bridge evaluates OPA (Open Policy Agent) Rego policies on inbound MCP requests before performing outbound token exchange. This blocks unauthorized tool calls early, before any outbound API call is made.
Configure `authorization.inbound.opa` with a `name` and either a `file` path to a Rego policy file or inline `rego` content. The policy is evaluated against the MCP request context including the agent's identity and the requested tool.
#### Example
An MCP Bridge app exposing an employee directory REST API as MCP tools with delegation-based token exchange and per-tool scopes:
```yaml theme={null}
apps:
- name: employee-directory-bridge
type: mcpBridge
mode: openapi
toolNamespace:
disabled: false
name: employee_directory_
openapi:
spec:
uri: file:///etc/maverics/apps/employee-directory/openapi.yaml
baseURL: https://employee-directory.example.com/api/v1
authorization:
inbound:
opa:
name: employee-directory-authz
file: /etc/maverics/policies/employee-directory-authz.rego
outbound:
type: tokenExchange
tokenExchange:
type: delegation
idp: oidc-provider
audience: https://employee-directory.example.com/
tools:
- name: listEmployees
ttl: 5s
scopes:
- name: employee:List
- name: getEmployee
ttl: 5s
scopes:
- name: employee:Get
```
## Troubleshooting
**Symptoms:** The agent connects and authenticates successfully, but `tools/list` returns no tools.
**Causes:**
* The OpenAPI spec URL is unreachable from the Orchestrator.
* The spec has parsing errors (invalid YAML/JSON, unsupported OpenAPI features).
* The spec contains no `operationId` definitions -- MCP Bridge requires `operationId` values to generate tool names.
**Resolution:**
* Verify the OpenAPI spec URL is accessible from the Orchestrator host (e.g., `file://` path exists or HTTP URL is reachable).
* Check Orchestrator logs for spec parsing errors.
* Confirm the OpenAPI spec contains operations with `operationId` values.
**Symptoms:** The agent gets an error when invoking a tool. Orchestrator logs show a token exchange failure.
**Causes:**
* The Auth Provider Orchestrator's token endpoint is unreachable.
* The `urn:ietf:params:oauth:grant-type:token-exchange` grant type is not enabled on the OIDC Provider app.
* Audience mismatch -- the `audience` in the token exchange configuration does not match the OIDC Provider's `expectedAudiences`.
**Resolution:**
* Verify the Auth Provider Orchestrator's token endpoint is reachable from the Gateway Orchestrator.
* Ensure the OIDC Provider app has `urn:ietf:params:oauth:grant-type:token-exchange` in its `grantTypes` list.
* Check that the `audience` value in the MCP Bridge app's `tokenExchange` configuration matches the OIDC Provider app's `expectedAudiences`.
**Symptoms:** Tool invocation fails with an upstream authentication or authorization error even though token exchange succeeded.
**Causes:**
* The exchanged token's scopes do not match what the REST API requires.
* The API's expected audience does not match the `aud` claim in the token.
**Resolution:**
* Verify the `scopes` in the tool's `tokenExchange` configuration match the scopes the REST API expects.
* Check the API's expected audience against the `aud` claim in the exchanged token.
* Review the REST API's authorization configuration to confirm it accepts tokens from the Auth Provider Orchestrator.
**Symptoms:** The REST API receives wrong parameters, missing required fields, or unexpected values.
**Causes:**
* The OpenAPI spec parameter definitions do not accurately describe the API's actual parameters.
* Path parameter extraction fails because the `operationId` path template does not match the actual API path structure.
**Resolution:**
* Verify the OpenAPI spec accurately describes all parameters (path, query, header, body) for each operation.
* Check Orchestrator logs for parameter mapping details.
* Test the OpenAPI spec against the actual API to confirm parameter definitions are correct.
**Symptoms:** Authorized agents are denied access to tools they should be able to invoke.
**Causes:**
* The OPA Rego policy contains a logic error that incorrectly denies valid requests.
* The policy input data does not contain the expected fields or values.
**Resolution:**
* Review the OPA policy Rego code for logic errors.
* Add logging to inspect the policy input data and confirm it contains the expected agent identity, tool name, and user attributes.
* Test the policy independently using the OPA CLI (`opa eval`) with sample input data.
## Related Pages
Overview of application types, route patterns, and shared configuration
AI Identity Gateway mode configuration and concepts
Proxy MCP traffic to upstream MCP servers with identity
# MCP Proxy App
Source: https://docs.strata.io/reference/orchestrator/applications/mcp-proxy
Proxy MCP (Model Context Protocol) requests to upstream MCP servers with identity injection, per-tool authorization, and delegation token exchange. The MCP Proxy app sits between AI agents and your existing MCP servers, adding enterprise identity and access control without modifying the upstream servers.
## Overview
The MCP Proxy app type is used in [AI Identity Gateway](/reference/modes/ai-identity-gateway) mode to secure MCP server traffic. It acts as an identity-aware proxy between AI agents and upstream MCP servers, applying inbound authorization policies and performing outbound token exchange so that upstream servers receive properly scoped delegation tokens. The MCP Proxy app requires an [MCP Provider](/reference/modes/ai-identity-gateway#setup) to be configured.
## How It Works
The MCP Proxy operates as an identity-aware intermediary for MCP traffic:
1. **Agent connects** -- The AI agent connects to the Orchestrator's MCP endpoint (SSE or Streamable HTTP).
2. **OAuth authentication** -- The Orchestrator validates the agent's OAuth token against the configured authorization server.
3. **Tool discovery** -- The Orchestrator proxies tool discovery to the upstream MCP server and returns the available tools (optionally namespaced with a prefix).
4. **Policy evaluation** -- When the agent invokes a tool, the Orchestrator evaluates OPA policies before forwarding the request.
5. **Token exchange** -- The Orchestrator exchanges the agent's token for a delegation token scoped to the upstream MCP server, with per-tool scopes and TTLs.
6. **Upstream forwarding** -- The tool call is forwarded to the upstream MCP server via the configured HTTP streaming transport.
7. **Response passthrough** -- The upstream server's response flows back through the Orchestrator to the agent, with audit logging capturing the interaction.
## Use Cases
* **Securing existing MCP servers** -- Add identity and authorization to upstream MCP servers without modifying them. The Orchestrator handles OAuth authentication and token exchange.
* **Per-tool authorization** -- Apply different scopes and TTLs to different tools based on the tool name. Read-only tools get read scopes; write tools get write scopes.
* **HTTP streaming transport** -- Connect to upstream MCP servers over the network via HTTP streaming.
* **Centralized token exchange** -- Exchange agent tokens for service-specific delegation tokens with per-tool granularity, preserving the user's identity through the agent-to-server chain.
## Key Concepts
### Upstream Transport
MCP Proxy connects to upstream MCP servers over HTTP streaming. Configure the upstream server URL, optional TLS profile, and connection pooling settings.
### Tool Namespacing
When multiple MCP Proxy apps connect to different upstream MCP servers, tool names can collide. The `toolNamespace` feature adds a configurable prefix to all tools from an app, enabling agents to access tools from multiple MCP servers through a single endpoint.
### Token Exchange for MCP Servers
MCP Proxy uses RFC 8693 token exchange to convert the agent's inbound OAuth token into a scoped token for the upstream MCP server. Each tool gets its own scopes and TTL, enabling least-privilege access. The delegation token carries both agent and user identity through the entire chain.
### Inbound OPA Policies
OPA Rego policies evaluate inbound MCP requests before forwarding to the upstream server. This adds a centralized authorization layer to MCP servers that may lack their own authorization. Policies can block specific tool invocations based on agent identity, user attributes, or requested tool name. See the [Authorization Policies guide](/guides/security/policies#opa-authorization-ai-identity-gateway) for the full OPA input schema, output schema, and example policies.
### Upstream Token Validation Best Practice
The upstream MCP servers receive standard MCP requests, and the Orchestrator adds identity, authorization, and audit transparently -- upgrading existing MCP servers with enterprise identity without modifying them.
While no protocol-level changes are required, it is best practice for upstream MCP servers to validate the received delegation token. Specifically, upstreams should:
* **Validate the token signature and expiry** -- Confirm the token has not been tampered with and is still valid.
* **Confirm the issuer matches the Auth Provider Orchestrator** -- The `iss` claim should match the expected authorization server.
* **Verify the audience claim matches the server's own identifier** -- The `aud` claim should contain the MCP server's registered audience.
* **Check that the token's scopes authorize the requested tool invocation** -- The `scope` claim should include the permissions required for the specific tool.
This defense-in-depth approach ensures that even if the gateway is misconfigured or compromised, the upstream server independently enforces authorization.
## Setup
Go to **Applications** in the sidebar and click **Create**. Select **MCP Proxy App** from the application type list.
Enter a **Name** to identify this MCP Proxy application.
Tool namespacing is enabled by default. Enter a **Namespace** prefix for tool names (e.g., `mission_control_`). Only alphanumeric characters, dots, dashes, and underscores are allowed. Disable the **Enable Tool Namespacing** toggle only if this is the sole MCP app.
Drag or click to upload an icon image (JPEG, PNG, or SVG, up to 2MB).
Under **Upstream MCP Server**, the **Transport Type** defaults to HTTP Streaming. Enter the **Upstream URL** of the remote MCP server (e.g., `http://mcp-server:8080/mcp`).
Under **TLS Settings**, optionally set a **CA Path** for self-signed certificates on the upstream. Enable **Skip TLS Verification** only for testing. Under **mTLS**, provide the **TLS Cert** and **TLS Key** file paths or secret provider references if the upstream server requires client certificate authentication.
Under **Authorization > Connection Policy**, upload an OPA policy definition (.rego file) or click **Add** to write an inline policy. This front-door admission policy is evaluated against the inbound token before a session to the upstream MCP server is established; a denial blocks the connection.
Under **Authorization > Tool Filtering Policy**, upload an OPA policy definition (.rego file) or click **Add** to write an inline policy. When configured, this policy runs once per tool during a `tools/list` request; tools the policy denies are hidden from the MCP client.
Under **Authorization > Inbound Request Policy**, upload an OPA policy definition (.rego file) or click **Add** to write an inline policy. The policy enforces fine-grained access control for incoming MCP requests based on agent identity, requested tool name, and user attributes.
Under **Outbound Request Authorization**, select the **Authorization Type** (Token Exchange or Unprotected). For Token Exchange, choose the **Exchange Type**: **Delegation** (recommended -- preserves both agent and user identity) or **Impersonation** (fully assumes user identity). Select the **OIDC Identity Provider** and enter the **Audience** for the upstream MCP server.
Click **Add Tool Configuration** to define per-tool authorization. Enter the **Tool Name** (exact match or regex pattern prefixed with `~ `), set an optional **Token Lifetime (TTL)**, and add **OAuth Scopes** that will be requested during token exchange for that tool.
Click **Add Operation Configuration** to configure authorization for MCP protocol operations. Select a **Method** (`initialize` or `tools/list`), set an optional **Token Lifetime (TTL)**, and add **OAuth Scopes** for the operation.
Click **Save** to create the MCP Proxy application.
MCP Proxy apps are defined under the `apps` top-level key with `type: mcpProxy`:
#### Configuration Reference
| Key | Type | Required | Description |
| ------------------------------------------------------------------------ | ------- | ----------- | ------------------------------------------------------------------------------------------------------- |
| `apps[].toolNamespace.disabled` | Boolean | No | Disable tool namespacing. When `false`, all tool names are prefixed with `toolNamespace.name`. |
| `apps[].toolNamespace.name` | String | No | Prefix for tool names (e.g., `service_`). Characters allowed: a-z, A-Z, 0-9, `.`, `-`, `_`. |
| `apps[].upstream.transport` | String | Yes | Upstream transport type: `stream` (HTTP streaming) |
| `apps[].upstream.stream.url` | String | Yes | Upstream MCP server URL |
| `apps[].upstream.stream.tls` | String | No | TLS profile name for the upstream connection (references a `tls` entry) |
| `apps[].upstream.stream.connection.dialTimeout` | String | No | Connection dial timeout (duration string, e.g., `10s`) |
| `apps[].upstream.stream.connection.keepAlive.interval` | String | No | Keep-alive interval for the upstream connection (duration string) |
| `apps[].upstream.stream.connection.pool.maxIdleConns` | Integer | No | Maximum number of idle connections in the pool |
| `apps[].upstream.stream.connection.pool.maxIdleConnsPerHost` | Integer | No | Maximum idle connections per upstream host |
| `apps[].authorization.connection.opa.name` | String | Yes | Name identifier for the connection (front-door admission) OPA policy. Supported on MCP Proxy apps only. |
| `apps[].authorization.connection.opa.file` | String | Conditional | Path to the Rego policy file for the connection policy. Mutually exclusive with `rego`. |
| `apps[].authorization.connection.opa.rego` | String | Conditional | Inline Rego connection policy. Mutually exclusive with `file`. |
| `apps[].authorization.inbound.opa.name` | String | No | Name identifier for the OPA policy |
| `apps[].authorization.inbound.opa.file` | String | Conditional | Path to the Rego policy file. Mutually exclusive with `rego`. |
| `apps[].authorization.inbound.opa.rego` | String | Conditional | Inline Rego policy. Mutually exclusive with `file`. |
| `apps[].authorization.listing.opa.name` | String | Yes | Name identifier for the tool filtering OPA policy |
| `apps[].authorization.listing.opa.file` | String | Conditional | Path to the Rego policy file for tool filtering. Mutually exclusive with `rego`. |
| `apps[].authorization.listing.opa.rego` | String | Conditional | Inline Rego tool filtering policy. Mutually exclusive with `file`. |
| `apps[].authorization.outbound.type` | String | No | Outbound authorization type: `tokenExchange` or `unprotected` |
| `apps[].authorization.outbound.tokenExchange.type` | String | No | Token exchange type: `delegation` (default) or `impersonation` |
| `apps[].authorization.outbound.tokenExchange.idp` | String | Conditional | Identity provider connector name for token exchange. Required when using token exchange. |
| `apps[].authorization.outbound.tokenExchange.audience` | String | Conditional | Token audience for the upstream MCP server. Required when using token exchange. |
| `apps[].authorization.outbound.tokenExchange.operations[].method` | String | No | MCP protocol operation method: `initialize` or `tools/list` |
| `apps[].authorization.outbound.tokenExchange.operations[].ttl` | String | No | Access token lifetime for this operation (duration string, e.g., `5s`) |
| `apps[].authorization.outbound.tokenExchange.operations[].scopes[].name` | String | No | OAuth scope to request when exchanging tokens for this operation |
| `apps[].authorization.outbound.tokenExchange.tools[].name` | String | No | Tool name (exact match) or regex pattern (`~ pattern`) for per-tool config |
| `apps[].authorization.outbound.tokenExchange.tools[].ttl` | String | No | Access token lifetime for this tool (duration string, e.g., `5s`) |
| `apps[].authorization.outbound.tokenExchange.tools[].scopes[].name` | String | No | OAuth scope to request when exchanging tokens for this tool |
#### Upstream Transport
MCP Proxy connects to upstream MCP servers over HTTP streaming. Configure the server URL, optional TLS profile, and connection pooling settings.
```yaml theme={null}
upstream:
transport: stream
stream:
url: http://mcp-server:8080/mcp
tls: upstream-tls
connection:
dialTimeout: 10s
keepAlive:
interval: 15s
pool:
maxIdleConns: 100
maxIdleConnsPerHost: 100
```
#### Token Exchange
MCP Proxy uses [RFC 8693](https://datatracker.ietf.org/doc/html/rfc8693) token exchange to obtain scoped tokens for outbound MCP server calls. Token exchange supports two modes: delegation (default) and impersonation.
* **Delegation** (`tokenExchange.type: delegation`) -- Delegation is the default and recommended mode. The Orchestrator exchanges the agent's token for a delegation token that contains an `act` (actor) claim identifying the agent alongside the original user's identity. The upstream MCP server sees both identities -- who the user is and which agent is acting on their behalf -- which supports auditability and least-surprise behavior for downstream services.
* **Impersonation** (`tokenExchange.type: impersonation`) -- The Orchestrator exchanges the agent's token for an impersonation token that fully assumes the user's identity, with no trace of agent involvement. The upstream MCP server receives a token that looks like it came directly from the user, meaning audit trails at the upstream server will not show agent participation. Impersonation may be required when upstream MCP servers do not support the `act` claim pattern.
* **Token minting policies** -- When token exchange is processed by the [OIDC Provider](/reference/modes/oidc-provider), administrators can configure OPA-based token minting policies (`authorization.tokenMinting.accessToken.policies` on the OIDC Provider app) to control which tokens get issued. These policies evaluate the token exchange request context and can deny token issuance based on agent identity, requested scopes, audience, or delegating user attributes. This provides a governance layer over token exchange independent of the inbound OPA policies that control tool access.
* **Per-tool scopes** -- Each tool can have its own OAuth scopes and token TTL. Tool names support exact matching and regex patterns for wildcarding.
* **Per-operation scopes** -- MCP protocol operations (`initialize` and `tools/list`) can have their own scopes and TTL, separate from tool-level configuration. This allows shorter-lived tokens for connection setup and tool discovery, independent of the tokens used for actual tool invocations.
Configure outbound authorization from the MCP Proxy app's setup flow. See Steps 9-11 above for the Console UI walkthrough.
```yaml theme={null}
authorization:
outbound:
type: tokenExchange
tokenExchange:
type: delegation
idp: oidc-provider
audience: https://service.example.com/
operations:
- method: initialize
ttl: 30s
scopes:
- name: items:read
- method: tools/list
ttl: 30s
scopes:
- name: items:read
tools:
- name: listItems
ttl: 5s
scopes:
- name: items:read
- name: "~ create.*"
ttl: 5s
scopes:
- name: items:read
- name: items:write
```
In the example above, the `operations` block configures token exchange for MCP protocol-level methods (`initialize` and `tools/list`). Operations typically carry the same base scopes required for all upstream calls -- here `items:read` -- so the upstream MCP server accepts the delegation token during connection setup and tool discovery. The per-tool configurations then include those same base scopes alongside any additional scopes needed for the specific tool. The tool named `listItems` is matched exactly, while `~ create.*` uses a regex pattern to match any tool name starting with `create` (e.g., `createItem`, `createOrder`) and adds `items:write`. This ensures each interaction -- whether protocol operation or tool invocation -- receives a properly scoped token for the upstream MCP server.
The token exchange connects to the [OIDC Provider](/reference/modes/oidc-provider) for token issuance. The OIDC Provider must be configured with the `urn:ietf:params:oauth:grant-type:token-exchange` grant type to support token exchange requests.
#### Connection Authorization (OPA)
MCP Proxy supports an optional `authorization.connection` block that gates whether an upstream MCP session may be established at all. This is a front-door admission decision -- distinct from the per-tool-call inbound policy and the outbound token-exchange policy -- evaluated when the proxy would open a new upstream session for the inbound bearer token.
Configure `authorization.connection.opa` with a `name` and either a `file` path to a Rego policy file or inline `rego` content. The policy is evaluated against the same OPA input schema as the inbound policy; the bearer token is available at `input.request.http.headers.Authorization`, and the policy decodes its claims with the [`jwt.parse_bearer`](/guides/security/policies#jwtparse_bearer) built-in. There is no `input.request.mcp` tool context at admission time, since no tool has been invoked yet. A deny decision blocks the session and can set `external_message` to surface a meaningful error to the MCP client.
Connection authorization is currently supported on MCP Proxy apps only. MCP Bridge apps reject the `authorization.connection` field at configuration validation time.
The admission decision is evaluated when a new upstream session is established. On a permit, the decision is sticky for the lifetime of that session; on a deny, the policy is re-evaluated on subsequent requests (for example, when the client lists or calls a tool).
See the [Authorization Policies guide](/guides/security/policies#opa-authorization-ai-identity-gateway) for the full OPA input schema, output schema, and example policies.
#### Inbound Authorization (OPA)
MCP Proxy evaluates OPA (Open Policy Agent) Rego policies on inbound MCP requests before performing outbound token exchange. This blocks unauthorized tool calls early, before any outbound MCP server call is made.
Configure `authorization.inbound.opa` with a `name` and either a `file` path to a Rego policy file or inline `rego` content. The policy is evaluated against the MCP request context including the agent's identity and the requested tool.
#### Tool Filtering (OPA)
The `authorization.listing` block controls which tools are exposed to the MCP client. When a client calls `tools/list`, the Orchestrator evaluates this policy once per tool returned by the upstream server and removes any tool the policy denies before sending the response. This limits what capabilities an AI agent can discover and invoke without changing the upstream MCP server.
Configure `authorization.listing.opa` with a `name` and either a `file` path or inline `rego`. When absent, all upstream tools are forwarded to the client without filtering. The policy runs fail-closed: if evaluation produces an error for a tool, that tool is excluded from the response.
See the [Authorization Policies guide](/guides/security/policies#mcp-app-input-schema) for the `tools_list` OPA input schema and an example filtering policy.
Under **Authorization > Tool Filtering Policy**, upload an OPA policy definition (.rego file) or click **Add** to write an inline policy.
```yaml maverics.yaml theme={null}
authorization:
inbound:
opa:
name: my-auth-policy
file: /etc/maverics/policies/auth.rego
listing:
opa:
name: my-listing-policy
rego: |
package orchestrator
default result["allowed"] := false
allowed_tools := {"listUsers", "getUser", "searchUsers"}
result["allowed"] if {
input.request.mcp.type == "tools_list"
input.request.mcp.response.tools_list.name in allowed_tools
}
```
#### Example
An MCP Proxy app securing a mission control MCP server with connection admission, inbound OPA authorization, and outbound delegation token exchange:
```yaml theme={null}
apps:
- name: mission-control-proxy
type: mcpProxy
toolNamespace:
disabled: false
name: mission_control_
upstream:
transport: stream
stream:
url: http://mission-control:8080/mcp
connection:
dialTimeout: 10s
keepAlive:
interval: 15s
pool:
maxIdleConns: 100
maxIdleConnsPerHost: 100
authorization:
connection:
opa:
name: mission-control-connection-authz
file: /etc/maverics/policies/mission-control-connection-authz.rego
inbound:
opa:
name: mission-control-authz
file: /etc/maverics/policies/mission-control-authz.rego
listing:
opa:
name: mission-control-listing
file: /etc/maverics/policies/mission-control-listing.rego
outbound:
type: tokenExchange
tokenExchange:
type: delegation
idp: oidc-provider
audience: https://mission-control.example.com/
operations:
- method: initialize
ttl: 30s
scopes:
- name: mission:List
- name: mission:Get
- method: tools/list
ttl: 30s
scopes:
- name: mission:List
- name: mission:Get
tools:
- name: listMissions
ttl: 5s
scopes:
- name: mission:List
- name: mission:Get
- name: getMission
ttl: 5s
scopes:
- name: mission:List
- name: mission:Get
- name: createMission
ttl: 5s
scopes:
- name: mission:List
- name: mission:Get
- name: mission:Create
```
## Troubleshooting
**Symptoms:** The agent connects to the proxy but tool discovery fails with a connection error. No tools are returned.
**Causes:**
* The `upstream.stream.url` is incorrect or unreachable from the Orchestrator.
* TLS certificate issues when connecting to the upstream MCP server over HTTPS.
* The upstream MCP server is not running or is not accepting connections.
**Resolution:**
* Verify the `upstream.stream.url` is correct and reachable from the Orchestrator host.
* If using TLS, check the TLS profile configuration and ensure the upstream server's certificate is trusted.
* Confirm the upstream MCP server is running and accepting connections on the expected port.
**Symptoms:** Tools from different upstream MCP servers have name collisions, causing unexpected behavior when agents invoke tools.
**Causes:**
* The `toolNamespace` feature is not configured on one or more MCP Proxy apps.
* Namespace prefixes are not unique across apps, so tools from different servers still collide.
**Resolution:**
* Configure unique `toolNamespace.name` values for each MCP Proxy app to prefix tool names (e.g., `service_a_` and `service_b_`).
* Ensure `toolNamespace.disabled` is set to `false` (the default) on all apps that share a single MCP endpoint.
**Symptoms:** The agent authenticates successfully but tool invocation fails. Orchestrator logs show a token exchange failure.
**Causes:**
* The Auth Provider Orchestrator's token endpoint is unreachable from the Gateway Orchestrator.
* The `urn:ietf:params:oauth:grant-type:token-exchange` grant type is not enabled on the OIDC Provider app.
* Audience mismatch -- the `audience` in the token exchange configuration does not match the OIDC Provider's `expectedAudiences`.
**Resolution:**
* Verify the Auth Provider Orchestrator's token endpoint is reachable from the Gateway Orchestrator.
* Ensure the OIDC Provider app has `urn:ietf:params:oauth:grant-type:token-exchange` in its `grantTypes` list.
* Check that the `audience` value in the MCP Proxy app's `tokenExchange` configuration matches the OIDC Provider app's `expectedAudiences`.
**Symptoms:** The agent connection drops during tool invocation. Logs show "connection reset" or timeout errors.
**Causes:**
* SSE keep-alive is not configured, so the connection appears idle to intermediate proxies or load balancers.
* A proxy or load balancer is enforcing a timeout that kills long-lived connections.
**Resolution:**
* Configure `upstream.stream.connection.keepAlive.interval` with an appropriate interval (e.g., `15s`) to keep connections alive.
* Configure any intermediate proxy or load balancer to allow long-lived connections for the MCP endpoint.
**Symptoms:** Multi-step agent interactions fail partway through. The agent loses its session between tool invocations.
**Causes:**
* The session timeout is too short for the expected agent workflow duration.
* The upstream MCP server takes longer to respond than the configured timeout allows.
**Resolution:**
* Increase the session timeout to accommodate the expected workflow duration.
* Review the upstream MCP server's response times and adjust connection timeouts (`upstream.stream.connection.dialTimeout`) accordingly.
## Related Pages
Overview of application types, route patterns, and shared configuration
AI Identity Gateway mode configuration for MCP Proxy deployments
Bridge REST APIs as MCP-compatible tools for AI agents
# OIDC App
Source: https://docs.strata.io/reference/orchestrator/applications/oidc
Register OpenID Connect clients with the Orchestrator's built-in OIDC Provider. The Orchestrator acts as an authorization server, handling authentication flows, enriching claims from multiple identity sources, and providing seamless IdP failover -- all without changes to your OIDC-compatible applications.
**Console vs. YAML:** In the Maverics Console, an OIDC app's authentication, authorization, claims, scopes, token settings, and the Identity Fabric components it relies on are configured directly on the application's settings page. In YAML, these elements are configured within each app's configuration block (for example under `apps[].authentication`, `apps[].authorization`, and `apps[].claimsMapping`).
## Overview
An OIDC app registers an OpenID Connect client with the Orchestrator's [OIDC Provider](/reference/modes/oidc-provider) mode. Each app entry defines a client with its own credentials, redirect URLs, grant types, and token settings. The Orchestrator issues ID tokens, access tokens, and refresh tokens to registered clients, acting as a standards-compliant authorization server.
## How It Works
The OIDC Provider authentication flow follows these steps:
1. **Application redirects** -- A user accesses an application registered as an OIDC relying party. The application redirects the user to the Orchestrator's authorization endpoint.
2. **Upstream authentication** -- The Orchestrator routes the user to the configured upstream identity provider (Microsoft Entra ID, Okta, etc.) for authentication. If multiple IdPs are configured, failover rules determine which to use.
3. **Attribute enrichment** -- After authentication, the Orchestrator loads additional attributes from configured attribute providers (directories, databases, APIs) and enriches the user's profile.
4. **Token issuance** -- The Orchestrator generates OIDC tokens (ID token, access token, optional refresh token) with claims mapped from the authenticated identity and enriched attributes.
5. **Application receives tokens** -- The application receives the tokens at its redirect URI and uses them for session establishment and authorization decisions.
6. **Ongoing token operations** -- The Orchestrator serves the JWKS endpoint for token verification, handles token introspection and revocation, and manages token refresh flows.
## Use Cases
* **SSO consolidation** -- Unify multiple IdPs behind a single OIDC interface so applications authenticate against one provider.
* **IdP migration with zero downtime** -- Move users between identity providers transparently while applications continue to use the same OIDC endpoints.
* **Legacy app modernization** -- Add OIDC-based authentication to older applications without rewriting them.
* **Claim enrichment from multiple sources** -- Combine attributes from multiple [Identity Fabric](/reference/orchestrator/identity-fabric) connectors into a single set of OIDC claims.
## Key Concepts
### Claims Mapping
Claims mapping translates attributes from upstream identity providers into OIDC token claims. The format `connector.attribute` (e.g., `upstream-idp.email`) references a specific claim from a named connector. This enables enriching tokens with data from multiple identity sources.
### IdP Failover
When multiple identity providers are listed under `authentication.idps`, the Orchestrator tries them in order. If the primary IdP is unavailable, authentication falls back to the next provider seamlessly -- no application changes required.
### Token Types
The Orchestrator issues two token formats: JWT tokens (self-contained, verified via JWKS) and opaque tokens (reference tokens, verified via introspection). Choice depends on whether resource servers can validate locally or must call back.
### Service Extensions
Go-based extension hooks allow custom logic at key points in the flow -- custom authentication checks, custom claim building, and custom attribute loading. These provide escape hatches when standard configuration is insufficient.
### Resources and Dependencies
An OIDC app declares the Identity Fabric components and service extensions it uses as its **resources**. Identity providers, attribute providers, and service extensions must be added to the app's resources before they can be referenced anywhere else in its configuration -- the authentication source, authorization rules, claim sources, and the Access Token and ID Token claim service extensions all select from the app's declared resources. This guarantees every reference points at a component the app actually uses.
## Setup
In the Maverics Console you create an OIDC app from a few essentials, then refine the rest of its configuration from the application's settings page.
Go to **Applications** in the sidebar, click **Create**, and select **OIDC-based**.
Provide:
* **Name** -- the friendly name of your application.
* **Client ID** -- the client ID OIDC clients use to authenticate. A unique value is suggested by default; keep it, or replace it with the existing `client_id` when migrating an existing integration.
* **Public Client** (optional) -- enable for single-page or native apps that cannot securely store credentials. Public clients cannot use flows that require a client secret, such as `client_credentials`.
* **Client authentication** -- a **Client Secret** or a **JWT** public key (RFC 7523).
* **Grant Types** -- the flows this client supports. New apps default to **Authorization Code** and **Refresh Token**; the create form offers only modern and machine-to-machine flows (legacy flows can be enabled later).
* **Redirect URLs** -- the allow-list of URLs your clients can be redirected to. Required when Authorization Code is used.
* **Authentication Source** -- the identity service or authentication service extension that authenticates users. Required for interactive grants; not needed for non-interactive grants (Client Credentials, Token Exchange) since there is no end user to sign in.
Click **Save**. Maverics creates the app with defaults -- the selected grant types and an allow-all access policy that uses the authentication source you chose -- and opens the settings page.
Once created, the settings page presents the configuration as a set of cards. Click **Edit** on a card to open its drawer.
**Client Configuration**
* **Client Credentials** -- the **Client ID** and the client authentication method: one or more **Client Secret** values, or **JWT Client Authentication (RFC 7523)** with a name, optional audience, and a public key from an uploaded file or a secret store reference.
* **Redirect URLs & Endpoints** -- the **Redirect URLs** allow-list, an optional **Default Redirect URL (Fallback)** toggle, and **Logout Redirect URLs**.
* **Application Security Settings** -- **Public Client**, **Require DPoP**, and **CORS** (**Allowed Origins** and **Include Credentials**).
* **PKCE Configuration** -- **Bypass Proof Key for Code Exchange (PKCE)**, for legacy apps only.
Store client secrets in a [secret provider](/reference/orchestrator/configuration/secret-providers) rather than entering them directly. Use secret reference syntax (e.g., ``) so the Orchestrator resolves the value at runtime.
**Grant Types & Tokens**
* **Grant Types** -- choose from **Recommended and Modern Flows** (Authorization Code, Refresh Token), **Machine to Machine and Agentic Flows** (Client Credentials, Token Exchange), and **Legacy or Deprecated Flows** (ROPC, Implicit (ID Token), Implicit (Access Token)).
* **Audience & Resource Configuration** -- the **Allowed Audiences** permitted in token requests.
* **Access Token Settings** -- **Type** (**JWT** or **Opaque**), **Lifetime Seconds**, and **Length** (22--256 characters for opaque tokens).
* **Refresh Token Settings** -- **Allow Offline Access**, **Lifetime Seconds**, and **Length** (22--256 characters).
**Resources**
Declare the Identity Fabric components and service extensions this app depends on. Click **Add Resource** and pick an identity provider, attribute provider, or service extension. Attribute providers also require an **Identity Source** and **Username Mapping**; service extensions that expose metadata can have per-app **Metadata Overrides**. Only resources declared here can be referenced by the app's authentication source, authorization rules, claim sources, and claim service extensions.
**Access Control**
* **Authentication** -- select the authentication source (an identity provider, continuity strategy, or authentication service extension from the app's resources) that establishes who the user is.
* **Authorization** -- choose an **Authorization method**: **Allow all access**, **Use rules to define access**, **Use service extension**, or **Use rules + service extension**.
* **Rules-Based Authorization** -- when using rules, define conditions with an **Identity Source**, **Attribute**, **Condition** (**Equals**, **Contains**, **Does not equal**, **Does not contain**), and **Value**. Combine conditions within a rule, and combine multiple rules, using **AND**/**OR**.
* **Token Minting** -- optionally define Rego access-token minting policies (each with a **Policy Name** and **Policy Code**) that run across all grant types before a token is returned. At least one policy must accept the access token for the request to succeed.
**Claims and OAuth 2.0 Scopes**
* **Attribute to Standard OIDC Claim Mapping** -- map each OIDC claim by name to a source (one of the app's resources) and a value, so issued tokens carry consistent user information such as name, email, or roles.
* **Custom Claim Service Extensions** -- optionally select a service extension to build non-standard claims for the **Access Token** and/or the **ID Token**.
* **Custom OAuth Scopes** -- define additional scopes beyond the standard `openid`, `profile`, `email`, and `offline_access`.
OIDC apps are defined under the `apps` key with `type: oidc`. For shared app fields (`name`, `type`) and authorization rule syntax, see the [Applications reference](/reference/orchestrator/applications).
#### Configuration Reference
**Core Fields**
| Key | Type | Required | Description |
| --------------------------------------- | ------- | -------- | ---------------------------------------------------------------------------- |
| `clientID` | String | Yes | Unique client identifier for the OIDC relying party |
| `public` | Boolean | No | When `true`, marks the client as a public client (no client secret required) |
| `credentials.secrets` | Array | No | Client secrets used for client authentication |
| `credentials.jwtPublicKeys[].name` | String | No | Name identifier for a JWT-based client authentication key |
| `credentials.jwtPublicKeys[].aud` | String | No | Expected audience value for the client JWT assertion |
| `credentials.jwtPublicKeys[].publicKey` | String | No | PEM-encoded public key for verifying client JWT assertions (RFC 7523) |
The `clientSecret` field is deprecated. Use `credentials.secrets` instead to support multiple secrets and secret rotation.
**DPoP (Demonstrating Proof-of-Possession)**
| Key | Type | Required | Description |
| --------------------- | ------- | -------- | ------------------------------------------------- |
| `dpop.enabled` | Boolean | No | Enable DPoP sender-bound access tokens (RFC 9449) |
| `dpop.nonce.disabled` | Boolean | No | When `true`, disables the DPoP nonce requirement |
**Grant Types and URLs**
| Key | Type | Required | Description |
| ------------------------- | ------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `grantTypes` | Array | No | Allowed OAuth 2.0 grant types. Defaults to `authorization_code`, `client_credentials`, `refresh_token`. Also supports `urn:ietf:params:oauth:grant-type:token-exchange` (RFC 8693) and `password` (ROPC). |
| `redirectURLs` | Array | No | Allowed redirect URIs for authorization code flow |
| `logoutRedirectURLs` | Array | No | Allowed redirect URIs after logout |
| `allowDefaultRedirectURI` | Boolean | No | Allow a default redirect URI when none is supplied in the request |
**Claims and Scopes**
| Key | Type | Required | Description |
| ---------------------------- | ------ | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `claimsMapping` | Object | No | Map connector attributes to OIDC claims. Keys are claim names, values are `connector.attribute` references (e.g., `email: upstream-idp.email`). |
| `customScopes.scopes[].name` | String | No | Define custom OAuth scopes beyond the standard set |
| `allowedAudiences` | Array | No | Restrict which audience values are permitted in token requests |
**Authentication**
| Key | Type | Required | Description |
| ------------------------------------------- | ------ | ----------- | -------------------------------------------------------------------------------------- |
| `authentication` | Object | Conditional | See note below. |
| `authentication.idps` | Array | No | List of identity provider connector names for user authentication |
| `authentication.isAuthenticatedSE` | Object | No | Service extension for custom authentication checks |
| `authentication.authenticateSE` | Object | No | Service extension for custom authentication flows |
| `authentication.backchannel.authenticateSE` | Object | No | Service extension for backchannel authentication (used with the `password` grant type) |
The `authentication` block is required when the client allows any interactive grant type. It may be omitted when `grantTypes` is restricted to `client_credentials` and/or `urn:ietf:params:oauth:grant-type:token-exchange`.
`isAuthenticatedSE` and `authenticateSE` must be defined together. When using SE-based authentication, you cannot also specify `idps`.
**Authorization**
| Key | Type | Required | Description |
| ------------------------------------------------- | ------- | -------- | ------------------------------------------------------------------------------------------------------------------------- |
| `authorization.allowAll` | Boolean | No | Allow all authenticated users |
| `authorization.rules` | Array | No | Authorization rules with `and`/`or` conditions. See [Applications](/reference/orchestrator/applications) for rule syntax. |
| `authorization.rulesAggregationMethod` | String | No | How to combine top-level rules: `and` (all must pass) or `or` (any may pass) |
| `authorization.isAuthorizedSE` | Object | No | Service Extension for custom authorization logic. Mutually exclusive with `allowAll` and `rules`. |
| `authorization.unauthorizedPage` | String | No | Redirect URL for unauthorized users |
| `authorization.tokenMinting.accessToken.policies` | Array | No | OPA policies for access token minting. Each entry has `name`, `file` (or `rego`). |
**Access Tokens**
| Key | Type | Required | Description |
| ----------------------------- | ------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `accessToken.type` | String | No | Token format: `jwt` (signed JSON Web Token) or `opaque` (random string reference token) |
| `accessToken.length` | Integer | No | Length of opaque access tokens (22--256). Only applies when `accessToken.type` is `opaque`. |
| `accessToken.lifetimeSeconds` | Integer | No | Access token lifetime in seconds |
| `accessToken.claimsMapping` | Object | No | Map claim names to values included in the access token. Keys are claim names; values are either `{{ connector.attribute }}` templates resolved from the session, or plain string literals. Claims whose template resolves to an empty value are omitted. If `buildAccessTokenClaimsSE` is also set, the service extension takes precedence for overlapping keys. |
**Refresh Tokens**
| Key | Type | Required | Description |
| --------------------------------- | ------- | -------- | ------------------------------------------------------------------------------------------------------------------------ |
| `refreshToken.allowOfflineAccess` | Boolean | No | Enable refresh tokens for this client. The client must request the `offline_access` scope. |
| `refreshToken.autoGrant` | Boolean | No | Automatically inject the `offline_access` scope for clients that do not request it. Requires `allowOfflineAccess: true`. |
| `refreshToken.length` | Integer | No | Refresh token length (22--256) |
| `refreshToken.lifetimeSeconds` | Integer | No | Refresh token lifetime in seconds |
**Attribute Providers and Service Extensions**
| Key | Type | Required | Description |
| --------------------------------- | ------ | -------- | --------------------------------------------------------------------- |
| `attrProviders[].connector` | String | No | Connector name for loading additional attributes after authentication |
| `attrProviders[].usernameMapping` | String | No | Template mapping for the username lookup (e.g., `{{ azure.sub }}`) |
| `loadAttrsSE` | Object | No | Service extension for custom attribute loading |
| `buildIDTokenClaimsSE` | Object | No | Service extension for customizing ID token claims |
| `buildAccessTokenClaimsSE` | Object | No | Service extension for customizing access token claims |
**CORS**
| Key | Type | Required | Description |
| ------------------------- | ------- | -------- | ------------------------------------------------- |
| `cors.allowedOrigins` | Array | No | Allowed CORS origins for browser-based OIDC flows |
| `cors.allowedCredentials` | Boolean | No | Allow credentials in CORS requests |
**Security**
| Key | Type | Required | Description |
| ------------------ | ------- | -------- | --------------------------------------------------------------------------------------------------------------- |
| `insecureSkipPKCE` | Boolean | No | Disable PKCE requirement. **Not recommended** -- PKCE protects against authorization code interception attacks. |
#### Example
A complete OIDC app with authorization code flow, claim enrichment, and refresh tokens:
```yaml theme={null}
apps:
- name: employee-portal
type: oidc
clientID: employee-portal-client
credentials:
secrets:
-
grantTypes:
- authorization_code
- refresh_token
redirectURLs:
- https://portal.example.com/callback
claimsMapping:
email: azure.preferred_username
name: azure.name
groups: azure.groups
accessToken:
type: jwt
lifetimeSeconds: 3600
claimsMapping:
roles: "{{ azure.groups }}"
env: production
refreshToken:
allowOfflineAccess: true
cors:
allowedOrigins:
- https://portal.example.com
```
## DPoP (Demonstrating Proof-of-Possession)
DPoP ([RFC 9449](https://datatracker.ietf.org/doc/html/rfc9449)) creates sender-bound access tokens -- the token is cryptographically tied to a specific client's key pair, preventing token theft and replay attacks. When a client presents a DPoP-bound access token, it must also present a proof that it possesses the private key. If an attacker intercepts the access token, they cannot use it without the client's private key.
DPoP is configured per-app on OIDC Provider applications. When enabled, the Orchestrator validates DPoP proof headers on token requests and issues sender-bound access tokens.
In the Console, DPoP is set on the application's **Client Configuration** card under **Application Security Settings**. Enable **Require DPoP** to bind issued access tokens to the client's key; DPoP proofs are rejected if they are older than five minutes or issued more than five minutes in the future.
```yaml theme={null}
apps:
- name: my-secure-client
type: oidc
clientID: my-secure-client
credentials:
secrets:
-
dpop:
enabled: true
nonce:
disabled: false # nonce required by default
accessToken:
type: jwt
lifetimeSeconds: 3600
authentication:
idps:
- upstream-idp
```
| Key | Type | Default | Description |
| --------------------- | ------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `dpop.enabled` | Boolean | `false` | Enable DPoP sender-bound access tokens per RFC 9449. When enabled, the Orchestrator validates DPoP proof headers and binds issued tokens to the client's public key. |
| `dpop.nonce.disabled` | Boolean | `false` | When `false` (the default), the Orchestrator requires a server-issued nonce in DPoP proofs. This prevents pre-generated proof replay. Set to `true` to disable the nonce requirement. |
DPoP provides defense against token exfiltration attacks. Even if an access token is stolen from a log, cache, or network trace, it cannot be used without the corresponding private key. For maximum security, combine DPoP with short token lifetimes and [TLS](/reference/orchestrator/tls-security) for transport-level protection.
## JWT and Opaque Token Options
The `accessToken.type` field controls whether the OIDC Provider issues JWT tokens or opaque (reference) tokens:
* **JWT tokens** (`accessToken.type: jwt`) -- Self-contained tokens that include claims directly. Resource servers can validate them locally using the JWKS endpoint without calling back to the provider. This is the most common choice for APIs and modern applications.
* **Opaque tokens** (`accessToken.type: opaque`) -- Random string tokens that carry no claims. Resource servers must call the introspection endpoint to validate them. Use opaque tokens when you need to revoke tokens immediately or avoid exposing claims to intermediate services.
In the Console, the access token format is set on the application's **Grant Types & Tokens** card under **Access Token Settings**. Choose the **Type** -- **JWT** or **Opaque** -- and optionally set **Lifetime Seconds** and, for opaque tokens, **Length** (22--256 characters).
```yaml theme={null}
# JWT access tokens (self-contained, validated via JWKS)
apps:
- name: my-api-client
type: oidc
clientID: my-api-client
accessToken:
type: jwt
lifetimeSeconds: 3600
# Opaque access tokens (reference tokens, validated via introspection)
- name: my-internal-client
type: oidc
clientID: my-internal-client
accessToken:
type: opaque
length: 32
lifetimeSeconds: 3600
```
## Token Minting Policies
OIDC apps can attach OPA token minting policies that the Orchestrator evaluates on every token request before issuance. They add a governance layer on top of authentication and authorization -- even after a user authenticates, a policy can deny or constrain the token based on client identity, grant type, requested scopes, or environmental conditions.
In the Console, manage these on the application's **Access Control** card under **Token Minting** (each policy has a **Policy Name** and **Policy Code**). In YAML, they are defined under `authorization.tokenMinting.accessToken.policies`.
For the policy `input` document, the `result` output schema, and worked deny-by-default Rego examples, see [OPA token minting policies](/guides/security/policies#configure-opa-token-minting-policies-oidc-provider-only-optional) in the Policies guide.
## Troubleshooting
**Symptoms:** The application rejects tokens with "invalid signature", "unable to verify token", or similar errors.
**Causes:**
* The JWKS endpoint is unreachable from the application's network.
* A key mismatch occurred after key rotation -- the application cached an old JWKS response.
* The `oidcProvider.discovery.issuer` URL does not match the `iss` claim the application expects.
**Resolution:**
1. Verify that `oidcProvider.discovery.issuer` matches exactly what the application has configured as the issuer (including scheme, host, and path).
2. Confirm the JWKS endpoint is accessible from the application by requesting `/.well-known/openid-configuration` and following the `jwks_uri`.
3. If you recently rotated keys, ensure the active signing key is the **first** entry in the `jwks` array and that old keys are still present for verification of previously issued tokens.
**Symptoms:** Users see a "redirect\_uri\_mismatch" or "invalid redirect URI" error during the login flow.
**Causes:**
* The redirect URL sent by the application is not listed in the app's `redirectURLs` array.
* A subtle mismatch in scheme (`http` vs. `https`), port, or trailing slash between the configured and requested redirect URI.
**Resolution:**
1. Add the exact redirect URI (including scheme, host, port, and path) to `apps[].redirectURLs` in the OIDC app configuration.
2. Compare the redirect URI in the browser's address bar during the error with the configured values -- they must match character-for-character.
**Symptoms:** The application receives a valid token but expected claims (e.g., `email`, `groups`) are empty or absent.
**Causes:**
* The `claimsMapping` references a wrong connector name or attribute that does not exist on the upstream identity.
* Attribute providers (`attrProviders`) are not configured, so enrichment attributes are not loaded.
* The upstream IdP does not return the expected attributes in its token or UserInfo response.
**Resolution:**
1. Verify that connector names in `claimsMapping` match the `connectors[].name` values exactly.
2. If enrichment is needed, confirm `attrProviders` entries are configured with the correct connector names and `usernameMapping`.
3. Test the upstream IdP directly to confirm it returns the expected attributes.
**Symptoms:** Authentication fails when the primary IdP is down instead of falling back to a secondary IdP.
**Causes:**
* Only one IdP is listed in `authentication.idps` -- there is no fallback configured.
* The secondary IdP connector is misconfigured (wrong URL, expired credentials, network issue).
**Resolution:**
1. Verify that multiple IdP connector names are listed in `authentication.idps` in the desired failover order.
2. Test each connector independently by temporarily making it the only entry to confirm it works on its own.
3. Check Orchestrator logs for connector-specific error messages when failover is attempted.
**Symptoms:** All previously issued tokens become invalid after an Orchestrator restart. Logs may show a warning about ephemeral key generation.
**Causes:**
* The `jwks` array is omitted from `oidcProvider`, so the Orchestrator auto-generates an ephemeral RSA key pair on every startup. Each restart produces new keys, invalidating tokens signed with the previous keys.
**Resolution:**
1. Provide explicit signing keys in the `oidcProvider.jwks` array using [secret provider](/guides/security/secrets-management) references (e.g., ``, ``).
2. Ensure both `publicKey` and `privateKey` are set for at least one entry in the `jwks` array.
## Related Pages
Overview of application types and routing configuration
Configure the Orchestrator as an OIDC authorization server
Connect identity sources for claim enrichment and IdP failover
Session storage and lifecycle configuration
# Proxy App
Source: https://docs.strata.io/reference/orchestrator/applications/proxy
Protect legacy web applications without code changes by deploying the Orchestrator as an identity-aware reverse proxy. It intercepts HTTP traffic, applies authentication policies, and injects identity headers -- so your backend apps receive authenticated user information with zero code modification.
## Overview
The proxy app type is the most common application type in the Orchestrator. It acts as an identity-aware reverse proxy in [HTTP Proxy](/reference/modes/http-proxy) mode, forwarding requests to a backend after applying authentication and authorization policies. Route patterns determine which incoming traffic matches the app, policies enforce authentication at specific URL paths, and headers inject identity attributes into upstream requests.
## How It Works
The HTTP Proxy request flow follows these steps:
1. **Traffic interception** -- The Orchestrator listens on configured route patterns (hostname/path combinations) and intercepts all matching HTTP requests before they reach the upstream application.
2. **Policy evaluation** -- Each request is matched against location-based policies. The Orchestrator determines which authentication and authorization rules apply based on the request path.
3. **User authentication** -- If the user is not authenticated (no valid session), the Orchestrator redirects them to the configured identity provider. After successful authentication, a session cookie is established.
4. **Authorization check** -- The Orchestrator evaluates authorization rules against the authenticated user's attributes. Rules use `and`/`or` conditions with operators like `equals`, `contains`, etc. Unauthorized users are redirected or receive a 403 response.
5. **Header injection** -- For authorized requests, the Orchestrator injects identity headers (e.g., `SM_USER`, `X-Remote-User`) into the upstream request using template syntax (`{{ connector.claim }}`). The upstream application receives these headers and uses them for its own identity decisions.
6. **Proxying and response** -- The request (with injected headers) is forwarded to the upstream backend. The response flows back through the Orchestrator to the client. Optional Service Extensions can modify the request or response at this stage.
## Use Cases
* **Protecting legacy apps without code changes** -- deploy the Orchestrator in front of applications that lack modern authentication support, adding SSO and MFA without modifying application code
* **Header-based authentication injection** -- inject identity headers like `SM_USER`, `REMOTE_USER`, or `X-Remote-User` into upstream requests, enabling SiteMinder-to-modern-IdP migration with zero backend changes
* **Session management for stateless apps** -- the Orchestrator manages user sessions and authentication state on behalf of backend applications that do not track sessions themselves
* **Combining with LDAP Provider for legacy stacks** -- pair proxy apps with an [LDAP attribute provider](/reference/orchestrator/identity-fabric) to load additional user attributes from a directory and inject them as headers, bridging legacy LDAP-dependent applications to modern identity providers
## Key Concepts
### Route Patterns and Upstreams
Route patterns define which traffic the proxy intercepts. Each proxy app maps one or more hostname/path patterns to an upstream backend URL. The Orchestrator acts as a transparent reverse proxy -- the client connects to the Orchestrator, and the Orchestrator forwards to the backend.
### Header Injection
Header injection is the primary mechanism for passing identity to legacy applications. Using `{{ connector.claim }}` template syntax, the Orchestrator maps claims from identity providers into HTTP headers that the upstream application expects. This replaces legacy access management products like SiteMinder without changing the application.
### Header Security on Open Routes
The Orchestrator treats injected identity headers as trusted assertions, so it must never forward a client-supplied copy of a header it manages. How this is enforced depends on whether a route is protected or open.
A route is **open** when its policy sets both `allowUnauthenticated: true` and `allowAll: true`, so unauthenticated requests are proxied straight to the upstream. Open routes are never enabled by default. You must explicitly configure them, and they are intended only for non-sensitive resources such as CSS, images, and login pages.
* **Protected routes** strip any client-supplied copy of a managed header and then inject the Orchestrator's own value, so the upstream never receives a spoofed identity header.
* **Open routes** are proxied without header injection. To prevent spoofing, the Orchestrator strips client-supplied copies of every *statically configured* managed header name -- the names under the app-level `headers:` and every policy's `headers:` -- before proxying. All other client headers are forwarded unchanged.
Header names produced dynamically by a [`createHeaderSE`](/reference/orchestrator/service-extensions/proxy#createheaderse) are **not** known when configuration loads, so they are **not** stripped on open routes. If you use a `createHeaderSE` to set an identity header -- especially a single global `createHeaderSE` with no static `headers:` entries -- the Orchestrator applies no managed-header filtering on open routes, and the upstream receives whatever header the client sends.
Never mark a route open if it is sensitive or if the upstream trusts injected identity headers (for example, SiteMinder-style `SM_USER`). Under the shared-responsibility model, choosing which routes are open, and ensuring open routes do not front header-trusting upstreams, is the administrator's responsibility.
### Location-Based Policies
Unlike OIDC and SAML modes where authorization is per-app, HTTP Proxy supports location-based policies. Different URL paths within the same application can have different authentication requirements and authorization rules. For example, `/` might allow all authenticated users while `/admin` requires a specific role.
### Session Management
The Orchestrator manages sessions for proxied applications using cookies. This is critical for applications that lack their own session management. Session configuration (cookie name, lifetime, idle timeout) is defined at the global level and applies to all proxy apps.
### Upstream Login
Some legacy applications have their own login flows in addition to the identity headers. The upstream login feature automates posting credentials to the upstream's login form after the Orchestrator has authenticated the user, handling the "double login" problem.
## Setup
Go to **Applications** in the sidebar and click **Create**. Select **Proxied App** from the application type list.
Enter a **Name** to identify this application. This name appears in the Console.
Enter the **Upstream URL** -- the backend server the Orchestrator forwards requests to after authentication (e.g., `https://internal-hr.example.com`).
Click **Route Pattern** to add URL patterns that map incoming requests to this app. Patterns support hostnames (`example.com`), paths (`/app`), or both (`example.com/app`).
Optionally set a **CA Path** for self-signed certificates on the upstream. Enable **Skip TLS Verification** only for testing.
For upstream servers requiring client certificate authentication, provide the **TLS Cert** and **TLS Key** file paths or secret provider references.
Optionally enter an **Unauthorized Page** URL where users are redirected when a policy evaluation denies access (e.g., `https://example.com/403`).
Enable the **Preserve Host** toggle to keep the original Host header on proxied requests. Enable this when the upstream expects the original hostname (e.g., behind another reverse proxy like Apache).
Set the **Logout Callback URL** -- the endpoint that facilitates logout for application users. Optionally set the **Post Logout Redirect URL** for where users go after successful logout.
Click **Save** to create the application. You can now configure its authentication policies, headers, and identity provider bindings.
Proxy apps are defined under the `apps` top-level key with `type: proxy`.
#### Configuration Reference
| Key | Type | Default | Required | Description |
| ---------------------- | ------- | ------- | -------- | -------------------------------------------------------------------------------------- |
| `name` | string | -- | Yes | Unique application identifier |
| `type` | string | -- | Yes | Must be `proxy` |
| `upstream` | string | -- | Yes | Backend URL to forward requests to (e.g., `https://backend:8080`) |
| `routePatterns` | array | -- | Yes | URL patterns to match -- at least one required |
| `preserveHost` | boolean | `false` | No | Preserve the original Host header when proxying to the upstream |
| `tls` | string | -- | No | Named TLS profile for the upstream connection |
| `headers` | array | -- | No | Headers to inject on proxied requests |
| `policies` | array | -- | No | Location-based authentication and authorization policies |
| `attrProviders` | array | -- | No | Attribute providers for post-authentication attribute loading |
| `unauthorizedPage` | string | -- | No | Default redirect URL for unauthorized requests |
| `handleUnauthorizedSE` | object | -- | No | Service Extension for custom 403 handling (mutually exclusive with `unauthorizedPage`) |
| `modifyRequestSE` | object | -- | No | Service Extension to modify the request before proxying |
| `modifyResponseSE` | object | -- | No | Service Extension to modify the response before returning to the client |
| `logout` | object | -- | No | Logout configuration |
**Route pattern formats:**
* `"example.com"` -- matches all requests to this hostname
* `"/path"` -- matches requests to this path on any hostname
* `"example.com/path"` -- matches requests to this hostname and path
#### Header Injection
Headers inject identity attributes into upstream requests using template syntax. This enables legacy applications to receive user information via HTTP headers without supporting modern authentication protocols.
Each header entry uses either a `name`/`value` pair with template syntax, or a `createHeaderSE` Service Extension. These two approaches are mutually exclusive per header entry.
| Key | Type | Description |
| -------------------------- | ------ | ---------------------------------------------------------------------------------------- |
| `headers[].name` | string | HTTP header name (e.g., `SM_USER`, `X-Remote-User`) |
| `headers[].value` | string | Value using `{{ connector.claim }}` template syntax |
| `headers[].createHeaderSE` | object | Service Extension for dynamic header generation (mutually exclusive with `name`/`value`) |
**Template syntax:** `{{ connector_name.claim_name }}` references a claim from a named connector. The connector name must match a `connectors[].name` entry, and the claim name must be a valid attribute from that connector.
In the Maverics Console, headers are configured within each application's settings. An application can define headers that inject identity attributes into upstream requests. The Console supports the `name`/`value` pair approach. Service Extension-based header generation (`createHeaderSE`) is configured via YAML only.
```yaml theme={null}
headers:
- name: SM_USER
value: "{{ my-idp.email }}"
- name: X-User-Name
value: "{{ my-idp.name }}"
- name: X-User-Given-Name
value: "{{ my-idp.given_name }}"
- name: X-User-Family-Name
value: "{{ my-idp.family_name }}"
- name: X-Forwarded-User
value: "{{ my-idp.preferred_username }}"
```
Headers can also be defined at the policy level under `policies[].headers`, which override app-level headers for that specific location.
On open routes (`allowUnauthenticated` + `allowAll`), only *statically configured* managed header names are stripped from client input before proxying. Header names emitted dynamically by a `createHeaderSE` are not stripped. See [Header security on open routes](#header-security-on-open-routes).
#### Authentication Policies
Policies control authentication and authorization for matched URL locations. Each policy applies to a specific `location` path within the app's route patterns.
| Key | Type | Default | Description |
| ------------------------------------------------- | ------- | ------- | ------------------------------------------------------------------------------------- |
| `policies[].location` | string | -- | Resource path this policy applies to (required, must be unique per app) |
| `policies[].authentication.idps` | array | -- | Connector names for authentication |
| `policies[].authentication.allowUnauthenticated` | boolean | `false` | Allow unauthenticated access to this location |
| `policies[].authentication.isAuthenticatedSE` | object | -- | Service Extension for custom authentication check (must pair with `authenticateSE`) |
| `policies[].authentication.authenticateSE` | object | -- | Service Extension for custom authentication flow (must pair with `isAuthenticatedSE`) |
| `policies[].authorization.allowAll` | boolean | -- | Allow all authenticated users |
| `policies[].authorization.rules` | array | -- | Authorization rules with `and`/`or` conditions |
| `policies[].authorization.rulesAggregationMethod` | string | -- | How top-level rules combine: `"and"` or `"or"` |
| `policies[].authorization.isAuthorizedSE` | object | -- | Service Extension for custom authorization |
| `policies[].authorization.unauthorizedPage` | string | -- | Redirect URL for unauthorized requests on this location |
| `policies[].authorization.tokenMinting` | object | -- | Token minting policy with OPA access token policies |
| `policies[].decision.lifetime` | string | -- | Decision cache TTL (duration string, e.g., `5m`) |
| `policies[].headers` | array | -- | Policy-level headers (override app-level headers for this location) |
| `policies[].useQueryParamsMatching` | boolean | `false` | Enable query parameter matching for this location |
SE-based authentication (`isAuthenticatedSE` + `authenticateSE`) cannot be mixed with `idps` or `allowUnauthenticated` on the same policy. Use one approach or the other.
For details on authorization rule operators (`equals`, `notEquals`, `contains`, `notContains`) and nested `and`/`or` conditions, see the [Applications](/reference/orchestrator/applications) reference.
#### Attribute Providers
Attribute providers load additional attributes from connectors after authentication. This is useful when you need claims from a second identity source (e.g., loading LDAP attributes after OIDC authentication).
| Key | Type | Description |
| --------------------------------- | ------ | ---------------------------------------------------------------------------------------------- |
| `attrProviders[].name` | string | Connector name to load attributes from |
| `attrProviders[].usernameMapping` | string | Template to map the authenticated user to the connector's lookup key (e.g., `{{ azure.sub }}`) |
#### Upstream Login
Upstream login automates authentication to the backend application after the Orchestrator has authenticated the user. This is useful when the upstream application has its own login flow that must be completed.
| Key | Type | Description |
| ---------------------------- | ------ | --------------------------------------------------------------------------------------------- |
| `upstreamLogin.isLoggedInSE` | object | Service Extension to check if the user is logged in to the upstream (required with `loginSE`) |
| `upstreamLogin.loginSE` | object | Service Extension to perform the upstream login (required with `isLoggedInSE`) |
#### Logout
| Key | Type | Description |
| ------------------------------ | ------ | --------------------------------------------------------------- |
| `logout.logoutURL` | string | URL path that triggers logout (required for logout to function) |
| `logout.postLogoutRedirectURL` | string | URL to redirect the user to after logout |
#### Service Extension Hooks
The proxy app type supports several Service Extension hooks for custom behavior. Service Extensions are referenced by file path and function name.
| Hook | Purpose |
| ---------------------- | ------------------------------------------------------------------------------------------ |
| `modifyRequestSE` | Modify the HTTP request before it is forwarded to the upstream |
| `modifyResponseSE` | Modify the HTTP response before it is returned to the client |
| `handleUnauthorizedSE` | Custom handler for 403 unauthorized responses (mutually exclusive with `unauthorizedPage`) |
| `createHeaderSE` | Generate headers dynamically (per-header, mutually exclusive with `name`/`value`) |
| `loadAttrsSE` | Custom attribute loading logic |
| `isLoggedInSE` | Check upstream login status (part of `upstreamLogin`) |
| `loginSE` | Perform upstream login (part of `upstreamLogin`) |
| `isAuthenticatedSE` | Custom authentication check (per-policy, must pair with `authenticateSE`) |
| `authenticateSE` | Custom authentication flow (per-policy, must pair with `isAuthenticatedSE`) |
| `isAuthorizedSE` | Custom authorization logic (per-policy) |
#### Example
A proxy app protecting a legacy application with header injection, authentication policy, and logout configuration:
```yaml theme={null}
apps:
- name: legacy-hr-portal
type: proxy
upstream: https://internal-hr.example.com
routePatterns:
- "hr.example.com"
preserveHost: true
policies:
- location: "/"
authentication:
idps: ["azure"]
authorization:
rules:
- or:
- contains: ["{{ azure.groups }}", "hr-staff"]
- contains: ["{{ azure.groups }}", "hr-managers"]
rulesAggregationMethod: "or"
decision:
lifetime: "5m"
headers:
- name: "X-Remote-User"
value: "{{ azure.email }}"
- name: "X-Remote-Name"
value: "{{ azure.name }}"
- name: "X-Remote-Groups"
value: "{{ azure.groups }}"
attrProviders:
- name: "corporate-ldap"
usernameMapping: "{{ azure.sub }}"
logout:
logoutURL: /logout
postLogoutRedirectURL: https://hr.example.com/
```
## Troubleshooting
**Symptoms:** The upstream application does not see injected headers. User identity is missing from the request.
**Causes:**
* Header template syntax error -- missing `{{ }}` delimiters or incorrect spacing.
* Connector name typo in the template (e.g., `{{ my_idp.email }}` when the connector is named `my-idp`).
* The upstream application or an intermediate proxy is stripping custom or `X-` headers.
**Resolution:**
* Verify template syntax uses the `{{ connector.attribute }}` format exactly, with double curly braces and a dot separator.
* Confirm the connector name in the template matches a `connectors[].name` entry in your configuration.
* Check whether the upstream application or any intermediate load balancer strips custom headers. Some application servers discard headers with underscores or specific prefixes by default.
**Symptoms:** The browser loops endlessly between the Orchestrator and the identity provider, never completing authentication.
**Causes:**
* Session cookie domain mismatch -- the cookie is set for a domain that does not cover the Orchestrator's hostname.
* The IdP callback URL does not match the `oauthLoginRedirect.urls` configured on the connector.
* The `routePatterns` do not cover the callback path, so the Orchestrator does not intercept the callback.
**Resolution:**
* Verify `session.cookie.domain` covers the Orchestrator's hostname (e.g., `.example.com` for `app.example.com`).
* Ensure the callback URL registered at the IdP is listed in `oauthLoginRedirect.urls` on the connector.
* Check that `routePatterns` include the callback path so the Orchestrator can process the authentication response.
**Symptoms:** The user authenticates successfully but receives a 403 response on specific paths.
**Causes:**
* Location-based policy mismatch -- the `location` path in the policy does not match the actual request path.
* Authorization rules reference a connector attribute that does not return the expected value.
* `rulesAggregationMethod` is set to `and` when `or` is needed (all rules must pass vs. any rule).
**Resolution:**
* Verify the `location` path in the policy matches the request path. Location matching is prefix-based.
* Check that the `connector.attribute` references in rules return expected values by inspecting the connector's claims.
* Review the `rulesAggregationMethod` setting -- use `or` if any single rule should grant access, or `and` if all rules must pass.
**Symptoms:** 502 Bad Gateway or connection timeout after the user successfully authenticates.
**Causes:**
* The `upstream` URL is unreachable from the Orchestrator host.
* TLS certificate mismatch on the upstream -- the Orchestrator cannot verify the upstream's certificate.
* Wrong port in the `upstream` URL.
**Resolution:**
* Verify the Orchestrator can reach the upstream URL from its host (test with `curl` or equivalent).
* If using HTTPS for the upstream, check the TLS profile configuration and ensure the upstream's certificate is trusted.
* Confirm the port in the `upstream` URL matches the port the backend application is listening on.
**Symptoms:** Users are forced to re-authenticate frequently, even during active use.
**Causes:**
* `session.lifetime.idleTimeout` or `maxTimeout` is set too low for the expected user activity pattern.
* A load balancer in front of multiple Orchestrator instances is not using sticky sessions, causing requests to hit instances that do not have the user's session.
**Resolution:**
* Adjust `session.lifetime.idleTimeout` and `session.lifetime.maxTimeout` to match your expected user session duration.
* Configure sticky sessions on the load balancer using the `maverics_session` cookie so that requests from the same user are routed to the same Orchestrator instance.
## Related Pages
Overview of application types, route patterns, and shared configuration
HTTP Proxy mode configuration for proxy app deployments
Configure the identity providers referenced in app policies
Authorization rules, operators, and rule aggregation
Custom request/response modification via Service Extensions
Named TLS profiles for upstream connections
# SAML App
Source: https://docs.strata.io/reference/orchestrator/applications/saml
Register SAML Service Providers with the Orchestrator's built-in SAML Provider. The Orchestrator handles SAML assertion generation, attribute mapping, and protocol translation -- allowing you to federate enterprise applications that depend on SAML while connecting to modern or legacy upstream identity providers.
**Console vs. YAML:** In the Maverics Console, a SAML app's authentication,
authorization, attribute mappings, and the Identity Fabric components it relies on
are configured directly on the application's settings page. In YAML, these elements
are configured within each app's configuration block (for example under
`apps[].authentication`, `apps[].authorization`, and `apps[].claimsMapping`).
## Overview
SAML apps represent Service Providers registered with the Orchestrator's [SAML Provider](/reference/modes/saml-provider) mode. When a Service Provider sends a SAML authentication request, the Orchestrator authenticates the user against a configured identity provider, generates a SAML assertion with the mapped attributes, and returns it to the SP's Assertion Consumer Service URL. This requires `samlProvider` to be configured in the deployment.
## How It Works
The SAML Provider authentication flow follows these steps:
1. **SP-initiated request** -- A user accesses a SAML service provider. The SP generates a SAML AuthnRequest and redirects the user to the Orchestrator's SSO endpoint.
2. **Upstream authentication** -- The Orchestrator routes the user to the configured upstream identity provider for authentication. The upstream IdP can use any protocol (OIDC, SAML, LDAP) -- the Orchestrator handles protocol translation.
3. **Attribute enrichment** -- After authentication, the Orchestrator loads additional attributes from configured attribute providers and merges them with the authenticated identity.
4. **Assertion generation** -- The Orchestrator generates a signed SAML assertion containing the NameID and mapped claims from the authenticated identity and enriched attributes.
5. **SP receives assertion** -- The SAML response (containing the signed assertion) is POSTed to the SP's assertion consumer service URL. The SP validates the signature and establishes a session.
6. **IdP-initiated flow (optional)** -- Users can also start from the Orchestrator's IdP-initiated login URL, which generates an assertion and sends it directly to the SP without an AuthnRequest.
## Use Cases
* **SAML federation for enterprise apps** -- register Service Providers like Salesforce, ServiceNow, and Workday so the Orchestrator acts as their SAML Identity Provider
* **Protocol translation (OIDC-to-SAML)** -- authenticate users with an OIDC provider upstream while issuing SAML assertions downstream to applications that only support SAML
* **IdP migration for SAML-dependent apps** -- migrate applications from a legacy SAML IdP to a modern identity provider without reconfiguring each Service Provider
* **Attribute mapping and enrichment** -- map and transform attributes from upstream identity providers into the SAML assertion format each Service Provider expects
## Key Concepts
### Protocol Translation
The Orchestrator can translate between protocols -- an upstream OIDC identity provider can feed a downstream SAML service provider, or vice versa. The service provider only sees SAML; the identity provider only sees OIDC. This makes IdP migration possible without changing SP configurations.
### Assertion Signing
By default, both the SAML assertion and the SAML response are signed using the provider's signing material. Individual apps can override signing behavior (e.g., disable assertion signing for SPs that don't verify it) or use per-app signing keys.
### NameID and Claims
The NameID identifies the authenticated subject in the SAML assertion. By default, the `` element includes `NameQualifier` and `SPNameQualifier` attributes. Some service providers do not expect these qualifiers -- use `disableNameQualifier` and `disableSPNameQualifier` to omit them when needed. Claims mapping uses the same `connector.attribute` format as OIDC, translating connector attributes into SAML assertion attributes.
### Request Verification
When service providers sign their AuthnRequest messages, the Orchestrator verifies the signature using the SP's certificate. This can be skipped for SPs that don't sign requests.
### Resources and Dependencies
A SAML app declares the Identity Fabric components and service extensions it uses as its **resources**. Identity providers, attribute providers, and service extensions must be added to the app's resources before they can be referenced anywhere else in its configuration -- the authentication source, authorization rules, NameID source, attribute claim sources, and the Build Claims and Build RelayState service extensions all select from the app's declared resources. This guarantees every reference points at a component the app actually uses.
## Setup
In the Maverics Console you create a SAML app from a few essentials, then refine the rest of its configuration from the application's settings page.
Go to **Applications** in the sidebar, click **Create**, and select **SAML-based**.
Provide:
* **Name** -- the friendly name of your application.
* **Assertion Consumer Service URL** -- the URL where your service provider receives SAML assertions. You can add more URLs and change the default after creating the app.
* **Authentication Source** -- the identity service or authentication service extension that authenticates users. Only identity providers and authentication-capable service extensions from your Identity Fabric are selectable.
Click **Save**. Maverics creates the app with defaults -- a generated entity ID (`urn:strata:app:`), a signed response and assertion, and an allow-all access policy that uses the authentication source you selected -- and opens the settings page.
Once created, the settings page presents the configuration as a set of cards. Click **Edit** on a card to open its drawer.
**Service Provider Configuration**
Manage the identifiers and endpoints the SP advertises:
* **Entity IDs** -- one or more SP entity identifiers. Mark one as the default.
* **Assertion Consumer Service (ACS) URLs** -- one or more ACS endpoints. Mark one as the default.
* **Logout Service URL** -- the single logout (SLO) endpoint where the IdP sends logout requests.
* **Unauthorized Page** -- the URL users are redirected to after a denied authorization.
**Protocol & Assertion Settings**
* **Signing Mode** -- choose **Sign both response and assertion**, **Sign assertion only (disable signed response)**, or **Sign response only (disable signed assertion)**.
* **Request Verification** -- enable **Skip Request Verification** to accept inbound SAML requests without checking their signature, or upload a **Certificate File** (PEM) to verify signed `AuthnRequest` messages.
* **NameID** -- set the **Name ID Format** URI and, optionally, source the NameID dynamically by selecting a **Dynamic NameID Source** (one of the app's resources) and the **Dynamic NameID Attribute** to read from it. Two optional toggles control the `` element in the SAML assertion:
* **Omit Name Qualifier** -- omit the `NameQualifier` attribute from the `` element in the SAML assertion.
* **Omit SP Name Qualifier** -- omit the `SPNameQualifier` attribute from the `` element in the SAML assertion.
* **IdP-Initiated Login** -- set a **Login URL** to enable IdP-initiated SSO and an optional **Relay State URL** for where the user lands afterward.
* **Assertion Lifetime** -- the **Duration (seconds)** an assertion is valid. Defaults to 300 seconds (5 minutes).
**Resources**
Declare the Identity Fabric components and service extensions this app depends on. Click **Add Resource** and pick an identity provider, attribute provider, or service extension. Attribute providers also require an **Identity Source** and **Username Mapping**; service extensions that expose metadata can have per-app **Metadata Overrides**. Only resources declared here can be referenced by the app's authentication source, authorization rules, NameID source, and attribute mappings.
**Access Control**
* **Authentication** -- select the authentication source (an identity provider, continuity strategy, or authentication service extension from the app's resources) that establishes who the user is.
* **Authorization** -- choose an **Authorization method**: **Allow all access**, **Use rules to define access**, **Use service extension**, or **Use rules + service extension**.
* **Rules-Based Authorization** -- when using rules, define conditions with an **Identity Source**, **Attribute**, **Condition** (**Equals**, **Contains**, **Does not equal**, **Does not contain**), and **Value**. Combine conditions within a rule, and combine multiple rules, using **AND**/**OR**.
**Attribute Mappings**
* **Attributes** -- map each SAML assertion attribute by name to a **Claim Source** (one of the app's resources) and a value. When the source exposes known claims, pick the value from a list; otherwise enter it directly.
* **Service Extensions** -- optionally select a **Build Claims** service extension to construct assertion attributes and a **Build RelayState** service extension to construct the RelayState value.
SAML apps are defined under the `apps` top-level key with `type: saml`:
#### Configuration Reference
**Core Fields**
| Key | Type | Required | Default | Description |
| --------------------- | ------- | -------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `name` | string | Yes | -- | Unique name for the SAML app. |
| `type` | string | Yes | -- | Must be `saml`. |
| `entityIDs` | array | Yes | -- | Service provider entity IDs. Each entry has `identifier` (string) and `default` (boolean). At least one entry with `default: true` is required. |
| `consumerServiceURLs` | array | Yes | -- | Assertion Consumer Service URLs. Each entry has `url` (string) and `default` (boolean). At least one entry with `default: true` is required. |
| `logoutServiceURL` | string | No | -- | SP logout service URL for single logout. |
| `duration` | integer | No | `3600` | Assertion lifetime in seconds. |
**NameID Configuration**
| Key | Type | Required | Default | Description |
| ------------------------------- | ------- | -------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `nameID.format` | string | No | -- | SAML NameID format URN (e.g., `urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress`). |
| `nameID.attrMapping` | string | No | -- | Connector attribute to use as the NameID value (e.g., `upstream-idp.email`). Uses `connector.attribute` format. |
| `nameID.disableNameQualifier` | boolean | No | `false` | When `true`, omits the `NameQualifier` attribute from the `` element in the SAML assertion. Per the SAML 2.0 spec, this attribute is optional. |
| `nameID.disableSPNameQualifier` | boolean | No | `false` | When `true`, omits the `SPNameQualifier` attribute from the `` element in the SAML assertion. Per the SAML 2.0 spec, this attribute is optional. |
**Authentication**
| Key | Type | Required | Default | Description |
| ---------------------------------- | ------ | ----------- | ------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `authentication.idps` | array | Conditional | -- | List of identity provider connector names for user authentication. Cannot be combined with `isAuthenticatedSE`/`authenticateSE`. |
| `authentication.isAuthenticatedSE` | object | Conditional | -- | Service Extension for custom authentication checks. Must be defined together with `authenticateSE`. |
| `authentication.authenticateSE` | object | Conditional | -- | Service Extension for custom authentication flows. Must be defined together with `isAuthenticatedSE`. |
**Authorization**
| Key | Type | Required | Default | Description |
| -------------------------------------- | ------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `authorization.allowAll` | boolean | No | -- | When `true`, all authenticated users are authorized. |
| `authorization.rules` | array | No | -- | Authorization rules using `and`/`or` conditions with `equals`, `notEquals`, `contains`, `notContains` operators. See [Applications](/reference/orchestrator/applications) for the full rules reference. |
| `authorization.rulesAggregationMethod` | string | No | `"and"` | How top-level rules are combined: `"and"` (all must match) or `"or"` (any may match). |
| `authorization.isAuthorizedSE` | object | No | -- | Service Extension for custom authorization logic. Mutually exclusive with `allowAll` and `rules`. |
| `authorization.unauthorizedPage` | string | No | -- | Redirect URL for unauthorized users. |
**Claims and Attributes**
| Key | Type | Required | Default | Description |
| --------------- | ------ | -------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `claimsMapping` | object | No | -- | Maps SAML assertion attribute names to connector attribute values. Keys are assertion attribute names; values use `connector.attribute` format (e.g., `email: upstream-idp.email`). |
| `buildClaimsSE` | object | No | -- | Service Extension for custom SAML assertion claims. When defined, replaces `claimsMapping`. |
| `attrProviders` | array | No | -- | Additional attribute providers for post-authentication attribute loading. Each entry has `connector` (string) and `usernameMapping` (string in `{{ connector.attribute }}` format). |
| `loadAttrsSE` | object | No | -- | Service Extension for custom attribute loading logic. |
**Request Verification**
| Key | Type | Required | Default | Description |
| -------------------------------------- | ------- | ----------- | ------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `requestVerification.certificate` | string | Conditional | -- | PEM-encoded SP certificate for verifying signed `AuthnRequest` messages. Required when `skipVerification` is `false` or not set. |
| `requestVerification.skipVerification` | boolean | No | `false` | When `true`, skip signature verification of incoming `AuthnRequest` messages. Use when the SP does not sign its requests. |
**Per-App Signature Override**
Individual SAML apps can override the provider-level signing configuration. When a per-app `signature` block is defined, it takes precedence over `samlProvider.signature` for that specific app.
| Key | Type | Required | Default | Description |
| ---------------------------------- | ------- | ----------- | ------- | -------------------------------------------------------- |
| `signature.certificate` | string | Conditional | -- | PEM-encoded X.509 certificate for this app's assertions. |
| `signature.certificateFile` | string | Conditional | -- | File path to the certificate. |
| `signature.privateKey` | string | Conditional | -- | PEM-encoded private key for this app's signing. |
| `signature.privateKeyFile` | string | Conditional | -- | File path to the private key. |
| `signature.disableSignedAssertion` | boolean | No | `false` | Disable assertion signing for this specific app. |
| `signature.disableSignedResponse` | boolean | No | `false` | Disable response signing for this specific app. |
**Deprecated Fields**
The following fields are deprecated. Migrate to the replacement fields listed below.
* `audience` -- Use `entityIDs` instead
* `consumerServiceURL` -- Use `consumerServiceURLs` instead
* `nameIDFormat` -- Use `nameID.format` instead
#### Example
A SAML app registering Salesforce as a Service Provider with attribute mapping, authentication, and IdP-initiated login:
```yaml theme={null}
apps:
- name: salesforce
type: saml
entityIDs:
- identifier: "https://salesforce.example.com"
default: true
consumerServiceURLs:
- url: "https://salesforce.example.com/saml/acs"
default: true
logoutServiceURL: "https://salesforce.example.com/saml/logout"
duration: 300
nameID:
format: "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
attrMapping: "{{ azure.email }}"
disableNameQualifier: true
disableSPNameQualifier: true
requestVerification:
skipVerification: true
authentication:
idps:
- azure
claimsMapping:
email: "azure.preferred_username"
firstName: "azure.given_name"
lastName: "azure.family_name"
groups: "azure.groups"
idpInitiatedLogin:
loginURL: "https://auth.example.com/saml/sso/salesforce"
relayStateURL: "https://salesforce.example.com/"
```
## Signed and Unsigned Assertions
By default, the SAML Provider signs both the SAML assertion and the SAML response using the signing material configured in `samlProvider.signature`. Some service providers require unsigned assertions or unsigned responses depending on their verification capabilities.
**Controlling signature behavior at the provider level:**
Provider-level signing is configured in the Maverics Console under **Deployment Settings** in the SAML Provider section. The Console UI provides a **Signing Option** dropdown with options for "Response and Assertion" (default), "Response Only", and "Assertion Only".
To override the default signing flags directly using `disableSignedAssertion` or `disableSignedResponse`, use the Configuration tab.
```yaml theme={null}
samlProvider:
signature:
certificate:
privateKey:
# Signed assertion + signed response (default)
disableSignedAssertion: false
disableSignedResponse: false
```
**Controlling signature behavior per app:**
Individual apps can override the provider defaults. For example, if the provider signs both but a specific SP needs unsigned assertions:
In the Console, per-app signing is set on the application's **Protocol & Assertion Settings** card. Use the **Signing Mode** dropdown to choose **Sign both response and assertion** (default), **Sign assertion only (disable signed response)**, or **Sign response only (disable signed assertion)**.
```yaml theme={null}
apps:
- name: unsigned-assertion-app
type: saml
signature:
disableSignedAssertion: true
# ... other fields
```
**Request verification from the SP side:**
When a service provider signs its `AuthnRequest` messages, the Orchestrator verifies the signature using the SP's certificate. If the SP does not sign requests, set `skipVerification: true`:
In the Console, request verification is set on the application's **Protocol & Assertion Settings** card under **Request Verification**. Upload the SP's **Certificate File** (PEM) to verify signed `AuthnRequest` messages, or enable **Skip Request Verification** if the SP does not sign its requests.
```yaml theme={null}
apps:
# SP that sends signed AuthnRequests
- name: saml-signed
type: saml
requestVerification:
certificate:
# ...
# SP that does not sign AuthnRequests
- name: saml-unverified
type: saml
requestVerification:
skipVerification: true
# ...
```
## IdP-Initiated Login
IdP-initiated login allows users to start a SAML flow from the identity provider rather than from the service provider. When configured, the Orchestrator exposes a login URL that generates a SAML response and sends it directly to the SP's assertion consumer service.
| Key | Type | Required | Default | Description |
| ------------------------------------- | ------ | -------- | ------- | -------------------------------------------------------------------------------------------------------------- |
| `idpInitiatedLogin.loginURL` | string | Yes | -- | URL that triggers the IdP-initiated flow. Users or portals navigate to this URL to start the login. |
| `idpInitiatedLogin.relayStateURL` | string | No | -- | URL included as the SAML `RelayState` parameter. The SP redirects the user here after consuming the assertion. |
| `idpInitiatedLogin.buildRelayStateSE` | object | No | -- | Service Extension for dynamically building the relay state value. |
**Example:**
In the Console, IdP-initiated login is set on the application's **Protocol & Assertion Settings** card under **IdP-Initiated Login**. Enter a **Login URL** to enable the flow (e.g., `https://auth.example.com/saml/sso/portal-app`), and optionally a **Relay State URL** for where the user lands after authentication.
```yaml theme={null}
apps:
- name: portal-app
type: saml
idpInitiatedLogin:
loginURL: https://auth.example.com/saml/sso/portal-app
relayStateURL: https://portal.example.com/
# ...
```
When a user navigates to `https://auth.example.com/saml/sso/portal-app`, the Orchestrator authenticates them (if not already authenticated), builds a SAML assertion, and POSTs it to the app's assertion consumer service URL with the relay state set to `https://portal.example.com/`.
## Assertion Encryption
SAML assertion encryption protects assertion content during transit by encrypting the assertion XML before embedding it in the SAML response. The SP decrypts the assertion using its private key.
| Key | Type | Required | Default | Description |
| ------------------------------ | ------ | -------- | ------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `encryption.keyEncryptMethod` | string | Yes | -- | Key encryption algorithm. Accepted values: `RSA_OAEP`, `RSA-1_5`. |
| `encryption.dataEncryptMethod` | string | Yes | -- | Data encryption algorithm. Accepted values: `AES128CBC`, `AES192CBC`, `AES256CBC`. |
| `encryption.digestMethod` | string | Yes | -- | Digest algorithm for key encryption. Accepted values: `SHA256`, `SHA512`. |
| `encryption.certificate` | string | Yes | -- | PEM-encoded SP certificate (public key) used to encrypt the assertion. The SP holds the corresponding private key for decryption. |
**Example:**
Assertion encryption settings are configured per-app via YAML only. The Console UI does not currently expose encryption fields. See the Configuration tab for the full reference.
```yaml theme={null}
apps:
- name: encrypted-app
type: saml
encryption:
keyEncryptMethod: RSA_OAEP
dataEncryptMethod: AES256CBC
digestMethod: SHA256
certificate:
# ...
```
## Troubleshooting
**Symptoms:** The SP rejects the SAML response with "invalid signature", "signature verification failed", or "unable to validate assertion".
**Causes:**
* The signing certificate configured in the Orchestrator (`samlProvider.signature.certificate`) does not match the certificate the SP has on file.
* The signing certificate has expired.
* A signing algorithm mismatch between the Orchestrator and the SP's expected algorithm.
**Resolution:**
1. Export the `samlProvider.signature.certificate` and provide it to the SP via metadata exchange or manual upload.
2. Verify the certificate is not expired by checking its `Not After` date.
3. If using per-app signature overrides, ensure the app-level certificate is the one provided to the SP.
**Symptoms:** The SP accepts the assertion but cannot identify the user, or rejects the assertion with "invalid NameID format" or "unrecognized subject".
**Causes:**
* The `nameID.format` does not match what the SP expects (e.g., the SP expects `emailAddress` but the Orchestrator sends `unspecified`).
* The `nameID.attrMapping` references an attribute that is empty or not returned by the upstream IdP.
**Resolution:**
1. Check the SP's metadata or documentation for the required NameID format.
2. Set `nameID.format` to the matching URN (e.g., `urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress`).
3. Verify that `nameID.attrMapping` points to an attribute that is populated for all users (e.g., `upstream-idp.email`).
**Symptoms:** The SP receives the assertion but expected attributes (e.g., email, groups, department) are empty or absent.
**Causes:**
* The `claimsMapping` references a wrong connector name or an attribute that does not exist on the upstream identity.
* Attribute providers (`attrProviders`) are not configured, so enrichment attributes are not loaded.
* The upstream IdP does not return the expected claims in its response.
**Resolution:**
1. Verify that connector names in `claimsMapping` match the `connectors[].name` values exactly.
2. If enrichment is needed, confirm `attrProviders` entries are configured with the correct connector names and `usernameMapping`.
3. Test the upstream IdP directly to confirm it returns the expected attributes.
**Symptoms:** The login flow fails immediately after the SP redirect, with an error about request verification or signature validation.
**Causes:**
* The SP signs its AuthnRequest, but the Orchestrator does not have the SP's signing certificate for verification.
* The SP's certificate in `requestVerification.certificate` is expired or does not match the key the SP uses.
**Resolution:**
1. If the SP signs its AuthnRequests, provide the SP's signing certificate in `requestVerification.certificate`.
2. If the SP does not sign requests, set `requestVerification.skipVerification: true`.
3. If the SP recently rotated its signing key, update the certificate in the app configuration.
**Symptoms:** Navigating to the IdP-initiated login URL returns an error about an unknown or unregistered service provider.
**Causes:**
* The `idpInitiatedLogin.loginURL` path does not match any configured app.
* The app's `entityIDs` are missing or do not match what the SP expects.
**Resolution:**
1. Verify the login URL matches the configured app name in the URL path (e.g., `/saml/sso/my-app` for an app named `my-app`).
2. Confirm that `entityIDs` contains at least one entry with `default: true`.
3. Check that the `consumerServiceURLs` are correctly configured for the target SP.
**Symptoms:** The SP cannot decrypt the assertion, reporting errors like "unable to decrypt", "decryption failed", or "invalid key".
**Causes:**
* The `encryption.certificate` is not the SP's encryption certificate (it might be the signing cert instead).
* An algorithm mismatch -- `keyEncryptMethod` or `dataEncryptMethod` does not match the SP's supported algorithms.
**Resolution:**
1. Verify that `encryption.certificate` is the SP's **public encryption certificate** (not its signing certificate -- these are often different).
2. Confirm that `keyEncryptMethod` and `dataEncryptMethod` match the algorithms the SP supports (check SP metadata or documentation).
3. If the SP specifies a `digestMethod`, ensure it is also set in the app configuration.
## Related Pages
Overview of application types, route patterns, and shared configuration
SAML Provider mode configuration for SAML app deployments
Configure the identity providers referenced in app policies
Configure Single Logout for SAML applications
# Authorization
Source: https://docs.strata.io/reference/orchestrator/authorization
Authorization rules determine whether an authenticated user is allowed to access a resource. These rules apply whether configured via Console UI or Configuration (YAML). Rules support nested `and`/`or` conditions with four comparison operators.
Authorization approaches vary by Orchestrator mode. The declarative rules documented on this page (`allowAll`, `rules` array, operators) apply to **HTTP Proxy**, **OIDC Provider**, and **SAML Provider** modes. These three modes also support programmatic authorization via Service Extensions ([`isAuthorizedSE`](#service-extension-hooks)) as an alternative or supplement to declarative rules. **AI Identity Gateway** uses OPA (Rego) policies for per-tool authorization instead of declarative rules. **LDAP Provider** handles authorization entirely through Service Extensions -- there is no declarative authorization layer. See [Per-Mode Authorization Differences](#per-mode-authorization-differences) for a full comparison.
## How Authorization Works
Authorization in the Maverics Orchestrator follows a pipeline that evaluates after authentication completes. Understanding this pipeline helps you design effective authorization rules and troubleshoot access issues.
1. **Authentication completes** -- The user's identity is established through the configured identity provider(s). At this point, the Orchestrator has the user's claims and attributes available for evaluation.
2. **Orchestrator evaluates authorization rules** -- The Orchestrator checks the authorization configuration for the matched application or policy location. If `allowAll: true` is set, no further evaluation occurs and the user is authorized.
3. **Rules reference connector attributes** -- Each rule operand uses template syntax `{{ connector.attribute }}` to reference claims from named connectors (e.g., `{{ azure.groups }}`, `{{ ldap.role }}`). The Orchestrator resolves these templates against the authenticated user's attributes.
4. **Rules are aggregated** -- Individual rule results are combined according to `rulesAggregationMethod`. With `"and"`, all rules must pass. With `"or"`, any single rule passing is sufficient.
5. **Service Extension runs (if configured)** -- If `isAuthorizedSE` is configured, the Service Extension executes after declarative rule evaluation and can override or supplement the result.
6. **Access decision is applied** -- If authorized, the request proceeds to the application. If denied, the behavior depends on the mode (see [Enforcement Behavior](#enforcement-behavior) below).
## Simple Authorization
Allow all authenticated users access to a resource:
```yaml theme={null}
authorization:
allowAll: true
```
When `allowAll` is set to `true`, any user who has successfully authenticated through the configured identity providers is granted access. No further rule evaluation occurs.
## Rule-Based Authorization
Rules are defined as an array of conditions. Each rule contains either an `and` block (all conditions must match) or an `or` block (any condition may match).
```yaml theme={null}
authorization:
rules:
- and:
- equals: ["{{ ldap.role }}", "admin"]
- contains: ["{{ ldap.memberOf }}", "cn=managers"]
- or:
- equals: ["{{ http.request.method }}", "GET"]
- notContains: ["{{ ldap.department }}", "restricted"]
rulesAggregationMethod: "and"
```
In this example, the first rule requires the user to be an admin AND a member of the managers group. The second rule allows GET requests OR users not in the restricted department. Both rules must pass (`rulesAggregationMethod: "and"`).
## Operators
| Operator | Description | Operands |
| ------------- | ---------------------------------- | ------------------ |
| `equals` | Exact string match | Exactly 2 operands |
| `notEquals` | Inverse exact match | Exactly 2 operands |
| `contains` | Substring or membership check | Exactly 2 operands |
| `notContains` | Inverse substring/membership check | Exactly 2 operands |
## Operand Formats
Each operator takes exactly two operands. Operands can be:
* **Template variable:** `{{ connector.attribute }}` -- references a claim from a named connector (e.g., `{{ azure.groups }}`, `{{ ldap.role }}`)
* **HTTP request:** `{{ http.request.method }}` -- references the HTTP request method
* **Literal string:** `"admin"` -- a static comparison value
## Rule Aggregation
The `rulesAggregationMethod` field controls how top-level rules in the array are combined:
* `"and"` -- All rules must pass for the user to be authorized
* `"or"` -- Any single rule passing is sufficient for authorization
When not specified, the default behavior treats each top-level rule independently.
## Example
A complete policy configuration with nested authorization rules:
```yaml maverics.yaml theme={null}
policies:
- location: "/"
authentication:
idps: ["azure", "ldap"]
authorization:
rules:
- and:
- equals: ["{{ ldap.role }}", "admin"]
- contains: ["{{ ldap.memberOf }}", "cn=managers"]
- or:
- equals: ["{{ http.request.method }}", "GET"]
- notContains: ["{{ ldap.department }}", "restricted"]
rulesAggregationMethod: "and"
```
## Enforcement Behavior
What happens when authorization denies a request depends on the Orchestrator mode. Understanding denial behavior helps you design appropriate error handling and user experiences.
* **HTTP Proxy mode** -- Returns a 403 Forbidden response to the client. The request never reaches the upstream application. If `unauthorizedPage` is configured on the policy, the user is redirected to that URL instead of receiving a 403. Alternatively, `handleUnauthorizedSE` can provide custom denial handling via a Service Extension.
* **OIDC Provider mode** -- Authorization rules are evaluated at the policy level. Denial prevents token issuance -- the user receives an error response at the authorization endpoint. The client application's redirect URI is not called with valid tokens.
* **SAML Provider mode** -- Similar to OIDC -- denial prevents SAML assertion generation. The user receives an error at the SSO endpoint. The service provider's assertion consumer service URL does not receive a valid assertion.
* **AI Identity Gateway** -- OPA policies evaluate per-tool invocations. Denial returns an error to the AI agent for that specific tool call. Other tools the agent is authorized to use remain accessible.
* **LDAP Provider** -- Authorization is typically handled within Service Extensions rather than declarative rules. The `authenticateSE` controls bind success/failure, and the `searchSE` controls which entries are returned. There is no separate declarative authorization layer.
When `allowAll: true` is set, no rule evaluation occurs and all authenticated users are authorized. This is the simplest configuration and is useful for applications where authentication alone is sufficient access control.
## Per-Mode Authorization Differences
Authorization works differently across modes. This table summarizes the key differences to help you configure authorization correctly for your deployment pattern.
| Aspect | HTTP Proxy | OIDC Provider | SAML Provider | LDAP Provider | AI Identity Gateway |
| -------------------------- | --------------------------------- | ------------------------------- | -------------------------- | ---------------------------------------- | ------------------------------------ |
| **Rule location** | `apps[].policies[].authorization` | `apps[].authorization` | `apps[].authorization` | Service Extension (no declarative rules) | `apps[].authorization.inbound.opa` |
| **Granularity** | Location-based (per URL path) | Per-app (per OIDC client) | Per-app (per SAML SP) | Per-operation (SE-controlled) | Per-tool invocation |
| **Dynamic checks** | `isAuthorizedSE` available | `isAuthorizedSE` available | `isAuthorizedSE` available | All logic is SE-driven | OPA policies with rich input context |
| **External policy engine** | Declarative rules or SE | Declarative rules or SE | Declarative rules or SE | SE only | OPA (Rego-based policies) |
| **Denial behavior** | 403 Forbidden or redirect | Error at authorization endpoint | Error at SSO endpoint | Bind failure or empty search results | Error on specific tool call |
## Service Extension Hooks
The `isAuthorizedSE` Service Extension hook provides programmatic authorization control beyond what declarative rules can express. It is available in HTTP Proxy, OIDC Provider, and SAML Provider modes.
**How it works:**
* Runs after declarative rule evaluation (if rules are also configured)
* Can override or supplement declarative rule results
* Has access to the full Orchestrator API through the `api` parameter -- including sessions, caches, connectors, secret providers, and logging
* Receives the HTTP request context, enabling authorization decisions based on request path, headers, method, or body content
**Configuration:**
```yaml theme={null}
authorization:
isAuthorizedSE:
funcName: CustomAuthorize
file: /etc/maverics/extensions/authorize.go
```
For implementation details, function signatures, and the full SDK interface, see [Service Extensions](/reference/orchestrator/service-extensions).
## Authorization Patterns
The following examples demonstrate common real-world authorization configurations.
### Role-Based Access Control (RBAC)
Check user group membership from Microsoft Entra ID to grant access based on role. This is the most common authorization pattern.
```yaml theme={null}
authorization:
rules:
- and:
- contains: ["{{ azure.groups }}", "app-admins"]
```
### Multi-Source Authorization
Combine attributes from multiple identity connectors to make authorization decisions. This is useful when identity data is spread across multiple systems.
```yaml theme={null}
authorization:
rules:
- and:
- equals: ["{{ okta.department }}", "engineering"]
- contains: ["{{ ldap.memberOf }}", "cn=developers"]
rulesAggregationMethod: "and"
```
### Path-Based Access Tiers (HTTP Proxy)
Apply different authorization rules to different URL paths within the same application. This enables tiered access where public areas require only authentication while sensitive areas require specific roles.
```yaml theme={null}
policies:
- location: "/"
authentication:
idps: ["azure"]
authorization:
allowAll: true
- location: "/admin"
authentication:
idps: ["azure"]
authorization:
rules:
- and:
- equals: ["{{ azure.role }}", "admin"]
```
## Related Pages
Application configuration including authentication policies and authorization rules
Identity connector configuration referenced in authorization rule operands
Custom authorization logic via the isAuthorizedSE hook and the SE SDK
Session management that works alongside authorization decisions
Understand the full authentication and authorization flow
Compare all 5 Orchestrator modes and their authorization models
# Caches
Source: https://docs.strata.io/reference/orchestrator/caches
Caches in the Maverics Orchestrator provide named key-value storage that multiple modes and features can share. Define a cache once, reference it by name from any mode that supports caching, and swap the underlying implementation without changing any mode configuration. This page covers how caches work, which modes use them, data protection features, and how to get started.
**Production support status:**
* **Redis cache** -- Supported for production. Use Redis caches for shared data across Orchestrator instances in multi-node deployments.
**Console terminology:** In the Maverics Console, Orchestrator instances and
configuration delivery are managed through **Deployments**. When working directly
with YAML, configuration is managed as files delivered via the `-config` flag or
`MAVERICS_CONFIG` environment variable.
## How Caches Work
Caches are defined by name and referenced by any mode or feature that supports caching. All cache types work the same way from the perspective of any mode that uses them, so you can swap the underlying implementation without changing the rest of your configuration. Caches are configured independently of session stores -- sessions persist user authentication state, while caches provide general-purpose key-value storage for mode-specific data like tokens, authorization state, and provider metadata.
The Orchestrator includes a built-in local cache named `local_default` that works out of the box with no configuration. This cache is in-memory and single-node only -- it does not share data across Orchestrator instances. For multi-node deployments, configure an external cache so all instances share the same cached data.
Do not use the name `local_default` for custom caches -- it is reserved for the built-in local cache.
## Caches and Orchestrator Modes
Different Orchestrator modes use caches for different purposes. Modes reference caches by name via their `cache` field:
* **OIDC Provider** -- Stores token and authorization server state. A shared cache is required for multi-node deployments so any Orchestrator instance can validate tokens and continue authorization flows started on another node.
* **SAML Provider** -- Stores request data and provider state. A shared cache is recommended for multi-node deployments to ensure SAML authentication flows complete correctly regardless of which node receives the response.
* **LDAP Provider** -- Stores shared credentials for facade deployments. When multiple Orchestrator instances serve LDAP traffic, a shared cache ensures consistent credential state.
* **HTTP Proxy** -- Does not use caches directly. HTTP Proxy mode uses [sessions](/reference/orchestrator/sessions) for user authentication state.
```yaml maverics.yaml theme={null}
# Modes reference caches by name
oidcProvider:
cache: my-cache
# ... other oidcProvider config
samlProvider:
cache: my-cache
# ... other samlProvider config
```
## Key Concepts
### Data Protection
External caches support client-side data protection so sensitive values are secured before leaving the Orchestrator. These features are configured per cache and apply to all data stored in that cache.
* **Client-side encryption** -- Values are encrypted using AES-256-GCM before being sent to the cache service. The encryption key never leaves the Orchestrator.
* **Key hashing** -- Cache keys are hashed before storage so the cache service never sees sensitive key names.
* **Key rotation** -- Configure both a current key and old keys. The Orchestrator encrypts new data with the current key and decrypts existing data with either the current or old keys, enabling seamless key rotation without data loss.
* **Key prefix** -- Feature-specific prefixes are added to cache keys by default. Disable prefixing (`keys.disablePrefix: true`) when [Service Extensions](/reference/orchestrator/service-extensions) need to read data written by external systems.
[Service Extensions](/reference/orchestrator/service-extensions) can read and write cache entries directly using the `api.Cache()` interface, which exposes `GetBytes` and `SetBytes` methods with TTL support. This is useful for caching expensive lookups (e.g., external API calls) so they are not repeated on every request.
See the cache detail pages below for the full set of encryption, hashing, and connection fields for each cache type.
### Built-in Local Cache
Every Orchestrator ships with a built-in cache named `local_default`. This cache is in-memory, requires no configuration, and is used automatically when a mode does not specify a `cache` field. Because it is local to each Orchestrator instance, it does not share data across nodes -- for multi-node deployments, configure an external cache instead.
## Setup
Each cache type has its own setup guide and configuration reference. See the cache detail pages below to get started:
Production-ready distributed caching backed by Redis
## Related Pages
Read and write cache entries from Service Extensions via the api.Cache() interface
Session storage for user authentication state
Secure cache connections with named TLS profiles
# Redis Cache
Source: https://docs.strata.io/reference/orchestrator/caches/redis
The Redis cache provides distributed key-value storage across multiple Orchestrator nodes. When configured, the Orchestrator stores cached data in Redis rather than in local memory, enabling multiple instances behind a load balancer to share the same cached data. Modes and features that support caching reference named caches -- because all cache types share the same interface, you can use Redis without changing any mode configuration.
Redis caching is **supported for production** use. It is the recommended approach for sharing cached data across multiple Orchestrator instances.
Redis is used for **caching**, not for session storage. These are configured separately. See [Sessions](/reference/orchestrator/sessions) for session store configuration.
## Use Cases
* **Multi-node deployments** -- share cached data across multiple Orchestrator instances behind a load balancer so any node can serve any request
* **External durability** -- persist cached data in Redis so it survives Orchestrator restarts
## Standalone vs. Cluster Mode
**Use standalone Redis by default.** A standalone Redis is a single primary that holds all the data. It is still fully highly available: run replicas (typically across availability zones) that automatically take over if the primary fails. Standalone gives you redundancy without the added complexity of sharding, and is the recommended topology for Orchestrator caching, including the OIDC Provider (Auth Provider).
Cluster mode shards (splits) data across multiple primary nodes and is rarely needed for Orchestrator caching. **If you do run Redis in cluster mode, you must list the addresses of all cluster nodes** in `redis.addresses`. If the Orchestrator knows about only some nodes, Redis returns `MOVED` errors whenever a requested key lives on a shard it cannot reach.
Seeing `MOVED` errors? Your Redis is running in cluster mode but not all node addresses are configured. Either add every cluster node address to `redis.addresses`, or reconfigure the Redis instance to run in standalone mode.
For more on Redis topologies, see the [Redis cluster documentation](https://redis.io/docs/latest/operate/oss_and_stack/management/scaling/).
## Setup
Redis caches are configured per deployment under **Orchestrator Settings**.
Navigate to **Deployments**, select a deployment, and click **Add** in the **Redis Caches** section.
Enter a **Name** to identify this cache. Modes that support caching reference the cache by this name. Do not use `local_default` -- it is reserved for the built-in local cache.
Leave **Disable Prefix** off for normal use. By default, the Orchestrator prepends a feature-specific namespace prefix to every cache key. Enable this toggle only when [Service Extensions](/reference/orchestrator/service-extensions) need to read and write data in this cache that is not owned by the Orchestrator -- disabling the prefix lets the keys match those used by the external system.
Enter at least one **Address** in `host:port` format (e.g., `redis.example.com:6379`). Click **Add Redis Address** to add additional servers.
Optionally enter a **Redis Cache Username** and **Redis Cache Password**. These must match credentials generated via Redis access control lists (ACL).
The Orchestrator authenticates to Redis using **Redis username and password (ACL) credentials only**. Cloud-provider-specific authentication mechanisms (such as IAM-based or managed-identity token authentication) are not supported -- enable Redis ACL credentials on your Redis instance and reference them here.
Store passwords and other secrets in a [secret provider](/reference/orchestrator/configuration/secret-providers) rather than entering them directly in the Console. Use the secret reference syntax (e.g., ``) so the Orchestrator resolves the value at runtime.
TLS is enabled by default. Set the **Min Version** (default: 1.2) and optionally provide a **CA Path** for self-signed certificates. Disable the **Enable TLS** toggle if your Redis server does not use TLS.
**Encryption** is enabled by default. The Orchestrator encrypts cached values client-side using AES-256-GCM before sending them to Redis, so data is protected at rest in the external cache. Enter a **Current Key** -- a 64-character hex string (generate one with `openssl rand -hex 32`). To rotate keys, add the previous key to **Old Keys** -- the Orchestrator will use old keys to decrypt existing data while encrypting new data with the current key. Use the **Disable Encryption** toggle only if your Redis instance already provides encryption at rest.
**Hashing** is enabled by default. The Orchestrator hashes cache keys before storing or looking up data, ensuring that key names in Redis do not contain sensitive information. Use the **Disable Hashing** toggle only if you need to inspect raw cache keys in Redis (e.g., for debugging).
Use [secret references](/reference/orchestrator/configuration/secret-providers) (e.g., ``) for all key values rather than entering them directly. See [Secret Providers](/reference/orchestrator/configuration/secret-providers) for setup.
Click **Add** to save the cache configuration.
Redis caches are defined with a name, type, and Redis connection details:
```yaml maverics.yaml theme={null}
caches:
- name: my-redis
type: redis
redis:
addresses:
- "redis.example.com:6379"
username: "maverics"
password:
tls: redis-tls
keys:
disablePrefix: false
encryption:
disabled: false
keys:
current:
old:
-
hashing:
keys:
disabled: false
```
Modes that support caching reference the cache by name. For example:
```yaml maverics.yaml theme={null}
oidcProvider:
cache: my-redis
# ... other oidcProvider config
samlProvider:
cache: my-redis
# ... other samlProvider config
```
Do not use `local_default` as a cache name -- it is reserved for the built-in local cache.
#### Configuration Reference
##### Redis Fields
| Key | Type | Default | Required | Description |
| -------------------------- | ------ | ------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `caches[].name` | string | -- | Yes | Unique cache name |
| `caches[].type` | string | -- | Yes | Must be `"redis"` |
| `caches[].redis.addresses` | array | -- | Yes | Redis server addresses (at least one required) |
| `caches[].redis.username` | string | -- | No | Redis username for authentication. Only Redis ACL username/password authentication is supported -- cloud-provider-specific mechanisms (e.g., IAM or managed-identity token auth) are not supported. |
| `caches[].redis.password` | string | -- | No | Redis password. Use a [secret reference](/reference/orchestrator/configuration/secret-providers), e.g., ``. |
| `caches[].redis.tls` | string | -- | No | TLS profile name for the Redis connection (references a named profile under `tls`) |
##### Encryption, Hashing, and Key Options
The following options control client-side encryption, key hashing, and key prefixing for external caches. Encryption encrypts cached values before they are sent to the external cache service. Hashing ensures cache keys do not contain sensitive data -- before reading or writing, keys are hashed and the hash is used for storage and lookup.
| Key | Type | Default | Description |
| ---------------------------------- | ------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `caches[].keys.disablePrefix` | boolean | `false` | Disable feature-specific key prefix (useful for Service Extensions reading non-Orchestrator data) |
| `caches[].encryption.disabled` | boolean | `false` | Disable client-side encryption of cached values (encryption is enabled by default) |
| `caches[].encryption.keys.current` | string | -- | AES-256-GCM encryption key: a 64-character hex string (32 bytes). Generate with `openssl rand -hex 32`. Use a [secret reference](/reference/orchestrator/configuration/secret-providers). |
| `caches[].encryption.keys.old` | array | `[]` | Previous encryption keys, used during key rotation to decrypt data encrypted with an older key. Use [secret references](/reference/orchestrator/configuration/secret-providers). |
| `caches[].hashing.keys.disabled` | boolean | `false` | Disable cache key hashing (hashing is enabled by default) |
## Examples
A single Redis server with client-side encryption and key hashing enabled. This is the simplest production-ready configuration for sharing cached data across Orchestrator instances.
```yaml maverics.yaml theme={null}
caches:
- name: my-redis
type: redis
redis:
addresses:
- "redis.example.com:6379"
encryption:
keys:
current:
hashing:
keys:
disabled: false
```
Secure the Redis connection with a named TLS profile and authenticate with username and password. The TLS profile references a CA certificate for verifying the Redis server's certificate.
```yaml maverics.yaml theme={null}
caches:
- name: my-redis
type: redis
redis:
addresses:
- "redis.example.com:6379"
username: "maverics"
password:
tls: redis-tls
encryption:
keys:
current:
hashing:
keys:
disabled: false
tls:
"redis-tls":
caFile: "/etc/maverics/certs/redis-ca.pem"
minVersion: "1.2"
```
When Redis runs in [cluster mode](#standalone-vs-cluster-mode), list the addresses of **all** cluster nodes. The Orchestrator needs every node address to route requests to the correct shard; otherwise Redis returns `MOVED` errors. (For a standalone primary with replicas, a single endpoint is sufficient.)
```yaml maverics.yaml theme={null}
caches:
- name: my-redis
type: redis
redis:
addresses:
- "redis-1.example.com:6379"
- "redis-2.example.com:6379"
- "redis-3.example.com:6379"
password:
tls: redis-tls
encryption:
keys:
current:
hashing:
keys:
disabled: false
tls:
"redis-tls":
caFile: "/etc/maverics/certs/redis-ca.pem"
```
Rotate encryption keys without downtime by adding the old key to the `old` list. The Orchestrator encrypts new data with the current key and decrypts existing data with either the current or old keys. Once all data encrypted with the old key has expired or been rewritten, remove the old key.
```yaml maverics.yaml theme={null}
caches:
- name: my-redis
type: redis
redis:
addresses:
- "redis.example.com:6379"
encryption:
keys:
current:
old:
-
hashing:
keys:
disabled: false
```
By default, the Orchestrator prepends a feature-specific namespace prefix to every cache key. Set `keys.disablePrefix: true` when a [Service Extension](/reference/orchestrator/service-extensions) reads and writes data in this cache that is not owned by the Orchestrator -- for example, sharing entries with an external system that writes keys without the Orchestrator's prefix. With the prefix disabled, keys written by the extension match the keys the external system expects.
```yaml maverics.yaml theme={null}
caches:
- name: shared-redis
type: redis
redis:
addresses:
- "redis.example.com:6379"
password:
tls: redis-tls
keys:
disablePrefix: true
encryption:
keys:
current:
hashing:
keys:
disabled: false
```
## Troubleshooting
* **Connection refused** -- verify Redis is accessible from the Orchestrator host. Check that the address and port are correct and that firewalls allow the connection.
* **`MOVED` errors** -- your Redis is running in [cluster mode](#standalone-vs-cluster-mode) but not all node addresses are configured. Add every cluster node address to `redis.addresses`, or reconfigure the Redis instance to run in standalone mode.
* **Authentication errors** -- confirm the username and password are correct. If using a secret reference, ensure the secret provider is configured and the secret resolves.
* **TLS handshake failures** -- for Redis with TLS, ensure the named TLS profile includes the correct CA certificate. Verify the Redis server's certificate is trusted.
* **Encryption key errors** -- check that the encryption key secret reference resolves correctly. The key must be a 64-character hex string (32 bytes). Generate a valid key with `openssl rand -hex 32`.
## Related Pages
Overview of cache types and production support status
Read and write cache entries from Service Extensions via the api.Cache() interface
Store passwords and encryption keys securely with secret references
Secure Redis connections with named TLS profiles
# Configuration
Source: https://docs.strata.io/reference/orchestrator/configuration
Configuration defines what the Orchestrator does -- which identity providers it connects to, which applications it protects, how it routes authentication traffic, and what policies it enforces. Every Orchestrator deployment starts with configuration.
## How Configuration Is Delivered
There are two paths to configuring the Orchestrator, and they produce the same result:
* **Console** -- Build configuration visually in the [Maverics Console](/reference/console/overview), then publish it as a signed [config bundle](/reference/console/config-publishing) that the Orchestrator downloads and applies. This is the recommended path for teams managing multiple deployments.
* **YAML file** -- Write a configuration file directly and point the Orchestrator at it with the `-config` flag or `MAVERICS_CONFIG` environment variable. This path is common for GitOps workflows where configuration lives in version control.
Both paths feed the same configuration model, so the concepts on this page apply regardless of how you deliver configuration. Bundles differ in format (the Console emits JSON rather than YAML) and include extras like cryptographic signatures and bundled service extension files -- see [Config Publishing](/reference/console/config-publishing) for bundle-specific details.
**Environment variables** complement either path. Use `{{ env.VAR_NAME }}` syntax in your configuration to inject values at runtime -- addresses, non-sensitive IDs, and other values that change between environments. Environment variables are resolved when the Orchestrator loads configuration, so the same config file (or bundle) can serve dev, staging, and production.
## Secret Providers
Sensitive values -- client secrets, API keys, TLS private keys, database passwords -- should never appear in configuration files or bundles. Instead, the Orchestrator retrieves them at runtime from an external [secret provider](/reference/orchestrator/configuration/secret-providers).
Secret providers are configured via the `MAVERICS_SECRET_PROVIDER` environment variable or the `-secretProvider` CLI flag, not in YAML. Once configured, reference secrets anywhere in your configuration using angle bracket syntax:
```yaml theme={null}
oauthClientSecret:
```
The Orchestrator resolves all secret references during startup by fetching values from the configured provider. Supported providers include HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, CyberArk, Conjur, and Delinea. See the [Secret Providers reference](/reference/orchestrator/configuration/secret-providers) for setup and provider-specific options.
## Key Concepts
* **Connectors bridge identity** -- Connectors define connections to your [identity fabric](/reference/orchestrator/identity-fabric) -- the identity providers, directories, and attribute sources your organization uses. Connectors are referenced by name from applications and policies.
* **Applications handle traffic** -- Each [application](/reference/orchestrator/applications) defines how the Orchestrator handles requests for a specific workload -- its upstream target, authentication requirements, and route patterns.
* **Modes define protocol** -- The Orchestrator's [mode](/reference/modes/ai-identity-gateway) determines which identity protocol it speaks to applications: [AI Identity Gateway](/reference/modes/ai-identity-gateway), [OIDC Provider](/reference/modes/oidc-provider), [SAML Provider](/reference/modes/saml-provider), [HTTP Proxy](/reference/modes/http-proxy), or [LDAP Provider](/reference/modes/ldap-provider). A single Orchestrator can run multiple modes simultaneously.
* **Policies enforce rules** -- [Authorization policies](/reference/orchestrator/authorization) determine who can access what, using identity provider connectors, authorization rules, claims enrichment, or custom Service Extensions.
The [Field Reference](/reference/orchestrator/configuration/reference) maps each concept to its corresponding configuration keys and links to detailed pages.
## Config Sources
The Orchestrator can load configuration from multiple [sources](/reference/orchestrator/configuration/config-sources) beyond the local filesystem:
* **Local file** -- A YAML file on disk, specified via `MAVERICS_CONFIG` or the `-config` CLI flag. The Orchestrator reads the file at startup and watches for changes.
* **Console** -- The Maverics Console publishes signed config bundles that the Orchestrator downloads automatically.
* **Remote storage** -- S3, Azure Blob, GCS, GitHub, and GitLab repositories, each selected via its own environment variable.
Remote sources support automatic hot-reload via ETag-based change detection when `MAVERICS_RELOAD_CONFIG` is enabled. Only one config source can be active at a time.
## Environment Variables
Key environment variables for Orchestrator configuration:
| Variable | Purpose |
| -------------------------- | ---------------------------------------------------------------------------------------------------------- |
| `MAVERICS_CONFIG` | Path to the YAML configuration file (defaults to `/etc/maverics/maverics.yaml`) |
| `MAVERICS_SECRET_PROVIDER` | [Secret provider](/reference/orchestrator/configuration/secret-providers) URL for runtime secret retrieval |
| `MAVERICS_HTTP_ADDRESS` | Override the HTTP server bind address |
| `MAVERICS_DEBUG_MODE` | Enable debug-level logging (`true`/`false`) |
| `MAVERICS_RELOAD_CONFIG` | Enable automatic hot-reload for remote config sources |
Environment variables follow the `MAVERICS_` prefix convention. The [Installation reference](/reference/orchestrator/installation) documents all CLI flags and environment variables.
## Runtime Behavior
* **Startup** -- The Orchestrator loads configuration, validates its structure, resolves secret references, initializes connectors and modes, and begins serving traffic.
* **Hot-reload** -- Remote config sources and local file changes trigger automatic reload without restarting the process (when enabled).
* **Graceful shutdown** -- The Orchestrator handles shutdown signals gracefully, allowing in-flight requests to complete before exiting.
## Related Pages
Every top-level config key with field tables and links to detailed pages
Runtime secret retrieval from Vault, AWS, Azure, CyberArk, and others
Load configuration from Console, S3, Azure Blob, GCS, GitHub, or GitLab
CLI flags, environment variables, and deployment options
# Config Sources
Source: https://docs.strata.io/reference/orchestrator/configuration/config-sources
The Maverics Orchestrator loads its configuration from exactly one source at a time. The source is selected via an environment variable (or CLI flag for local file). Remote sources support hot-reload through ETag-based change detection when enabled.
**Console terminology:** In the Maverics Console, Orchestrator instances and
configuration delivery are managed through **Deployments**. When working directly
with configuration files, delivery is managed via the `-config` flag or
`MAVERICS_CONFIG` environment variable.
## How Config Sources Work
The Orchestrator selects its config source at startup using the following precedence:
1. **CLI flag** -- if `-config` is passed, the Orchestrator reads from the local filesystem at that path.
2. **Environment variable** -- if a config source environment variable is set (e.g., `MAVERICS_AWS_CONFIG`, `MAVERICS_GCP_CONFIG`), the Orchestrator fetches configuration from that remote location.
3. **Default** -- if no flag or environment variable is set, the Orchestrator reads from `/etc/maverics/maverics.yaml`.
Remote config sources deliver configuration as signed bundles (`maverics.tar.gz`). The Orchestrator downloads the bundle, verifies its signature using the public key specified by `MAVERICS_BUNDLE_PUBLIC_KEY_FILE`, and applies the configuration. The `MAVERICS_BUNDLE_PUBLIC_KEY_FILE` environment variable must be set when using a remote config source.
Only one config source may be active at a time. If multiple config source environment variables are set, the Orchestrator will fail to start with a `multiple config providers defined` error. Ensure only one config source environment variable is set.
## Available Sources
| Source | Environment Variable / Flag | Use Case |
| ------------------------------------------------------------------------------- | ----------------------------------- | ------------------------------------------------ |
| [File](/reference/orchestrator/configuration/config-sources/file) | `MAVERICS_CONFIG` or `-config` flag | Local configuration file on disk |
| [Environment](/reference/orchestrator/configuration/config-sources/environment) | N/A (substitution syntax) | Override values via `{{ env.VAR }}` substitution |
| [S3](/reference/orchestrator/configuration/config-sources/s3) | `MAVERICS_AWS_CONFIG` | AWS S3 bucket |
| [Azure Blob](/reference/orchestrator/configuration/config-sources/azure-blob) | `MAVERICS_AZURE_CONFIG` | Azure Blob Storage |
| [GCS](/reference/orchestrator/configuration/config-sources/gcs) | `MAVERICS_GCP_CONFIG` | Google Cloud Storage |
| [GitHub](/reference/orchestrator/configuration/config-sources/github) | `MAVERICS_GITHUB_CONFIG` | GitHub repository |
| [GitLab](/reference/orchestrator/configuration/config-sources/gitlab) | `MAVERICS_GITLAB_CONFIG` | GitLab.com repository |
## ETag-Based Change Detection
Remote config sources (S3, Azure Blob, GCS, GitHub, GitLab) can periodically check for configuration changes using ETag headers. When a change is detected, the Orchestrator reloads the configuration automatically. Hot-reload is disabled by default -- enable it by setting the `MAVERICS_RELOAD_CONFIG` environment variable:
```bash theme={null}
export MAVERICS_RELOAD_CONFIG=true
export MAVERICS_POLLING_INTERVAL_SECONDS=30 # default is 30 seconds
```
During a successful configuration reload, user sessions and tokens issued on
behalf of resource owners are invalidated to ensure policy updates take effect
immediately. Plan reload timing accordingly in production environments.
## Source Pages
Load config from a local file via MAVERICS\_CONFIG or -config flag
Substitute environment variables in config with \{\{ env.VAR }} syntax
Load config from an AWS S3 bucket via MAVERICS\_AWS\_CONFIG
Load config from Azure Blob Storage via MAVERICS\_AZURE\_CONFIG
Load config from Google Cloud Storage via MAVERICS\_GCP\_CONFIG
Load config from a GitHub repository via MAVERICS\_GITHUB\_CONFIG
Load config from a GitLab.com repository via MAVERICS\_GITLAB\_CONFIG
## Related Pages
Session configuration and storage options
Identity provider integrations
How the Orchestrator retrieves secrets at runtime
Complete configuration field reference
# Azure Blob Storage
Source: https://docs.strata.io/reference/orchestrator/configuration/config-sources/azure-blob
The Azure Blob Storage config source loads Orchestrator configuration from a blob stored in an Azure Storage container. The source is configured entirely through the `MAVERICS_AZURE_CONFIG` environment variable.
**Console terminology:** In the Maverics Console, Orchestrator instances and
configuration delivery are managed through **Deployments**. When working directly
with YAML, configuration is managed as files delivered via the `-config` flag or
`MAVERICS_CONFIG` environment variable.
## Prerequisites
* **An active Azure account** -- with access to the storage account and container where configuration is stored
* **A storage account and container** -- already provisioned in Azure (see the [Console Azure Blob Storage](/reference/console/config-publishing/azure-blob#azure-setup) setup guide)
* **A SAS token with read access** -- generated with List and Read permissions on the container (see steps below)
## Overview
When the `MAVERICS_AZURE_CONFIG` environment variable is set, the Orchestrator fetches its YAML configuration from the specified Azure storage account, container, and blob path. The variable contains a JSON payload with connection details and SAS token authentication. The Orchestrator supports ETag-based change detection for automatic hot-reload.
## Use Cases
* **Azure-native deployments** -- store configuration in Azure Storage alongside other Azure infrastructure resources
* **Azure DevOps pipelines** -- publish validated configuration to Blob Storage as part of Azure DevOps CI/CD workflows
* **Multi-region with Azure** -- leverage Azure Storage geo-replication to distribute configuration across regions
## Generating a SAS Token
In the Azure portal, go to your storage account and select **Containers** under **Data storage**.
Select the container that holds (or will hold) Orchestrator configuration.
Click the three-dot menu (or right-click) on the container and select **Generate SAS**.
Set **Signing method** to **Account key** and **Signing key** to **Key 1**.
Under **Permissions**, select **List** and **Read** only (the Orchestrator only needs to read configuration, not write it).
Set an appropriate expiry date.
Click **Generate SAS token and URL**.
Copy the **Blob SAS token** value (starts with `sv=`) -- use this as the `token` value in `MAVERICS_AZURE_CONFIG`.
## Configuration
The Azure Blob config source is configured via the `MAVERICS_AZURE_CONFIG` environment variable with a JSON payload:
```bash theme={null}
export MAVERICS_AZURE_CONFIG='{
"account": "mystorageaccount",
"container": "config",
"token": "",
"configurationFilePath": "path/to/config"
}'
maverics
```
## Configuration Reference
The `MAVERICS_AZURE_CONFIG` JSON payload supports the following fields:
| Field | Type | Required | Description |
| ----------------------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `account` | string | Yes | Azure storage account name |
| `container` | string | Yes | Blob container name |
| `token` | string | Yes | SAS token for authentication |
| `configurationFilePath` | string | No | Directory path prefix within the container where the config bundle is stored. The Orchestrator appends `maverics.tar.gz` to this path. If omitted, the bundle is expected at the container root. |
| `storageDomain` | string | No | Storage domain suffix (default: `core.windows.net`). The Orchestrator constructs URLs as `https://{account}.blob.{storageDomain}/...`. For Azure Government, use `core.usgovcloudapi.net`. |
**ETag-based hot-reload:** When `MAVERICS_RELOAD_CONFIG=true` is set, the Orchestrator periodically checks the blob's ETag. When the ETag changes (indicating the blob was updated), the Orchestrator reloads the configuration automatically.
## Full Environment Example
A complete `maverics.env` file for an Orchestrator using Azure Blob Storage as its config source:
```bash maverics.env theme={null}
MAVERICS_DEBUG_MODE=true
MAVERICS_HTTP_ADDRESS=:443
MAVERICS_TLS_SERVER_CERT_FILE=your-cert.pem
MAVERICS_TLS_SERVER_KEY_FILE=your-private_key.pem
MAVERICS_RELOAD_CONFIG=true
MAVERICS_POLLING_INTERVAL_SECONDS=30
MAVERICS_BUNDLE_PUBLIC_KEY_FILE=./public_key.pem
MAVERICS_AZURE_CONFIG='{"token": "sv=2021-...", "account": "exampleStorage", "container": "exampleContainer", "configurationFilePath": "folder1/folder2"}'
```
Replace the placeholder values with your actual certificate paths, storage account name, container name, and SAS token.
## Troubleshooting
* **Authentication failed** -- verify the SAS token has not expired. SAS tokens have a configurable expiration time. Generate a new token with read access to the blob.
* **Container not found** -- confirm the `account` and `container` values are correct. Container names are case-sensitive and must be lowercase.
* **Custom domain** -- if using Azure Government or a custom storage domain, set the `storageDomain` field (e.g., `core.usgovcloudapi.net`). The Orchestrator prepends `blob.` automatically in the URL.
* **Config not reloading** -- ensure `MAVERICS_RELOAD_CONFIG=true` is set. Check Orchestrator logs for ETag change detection messages.
## Related Pages
Overview of all configuration sources
Load config from AWS S3
Complete configuration field reference
Console-side Azure Blob Storage setup and SAS token generation
# Environment Variable Substitution
Source: https://docs.strata.io/reference/orchestrator/configuration/config-sources/environment
Environment variable substitution allows you to reference host environment variables inside YAML configuration files using the `{{ env.VAR }}` syntax. Values are resolved at configuration load time regardless of which config source is used.
**Console terminology:** In the Maverics Console, Orchestrator instances and
configuration delivery are managed through **Deployments**. When working directly
with YAML, configuration is managed as files delivered via the `-config` flag or
`MAVERICS_CONFIG` environment variable.
## Overview
The `{{ env.VAR }}` syntax lets you externalize sensitive values and deployment-specific settings from your YAML configuration. This works with any config source -- local file, S3, GitHub, or any other remote source. The Orchestrator replaces `{{ env.VAR }}` with the value of the named environment variable when loading configuration.
Environment variable substitution works with any config source. The `{{ env.VAR }}` syntax is resolved at configuration load time regardless of whether the config comes from a local file, S3, GitHub, or any other source.
## Use Cases
* **Container deployments** -- inject deployment-specific values (client IDs, tenant IDs, hostnames) via Kubernetes ConfigMaps or Docker environment variables
* **CI/CD pipelines** -- set deployment-specific values during automated builds without modifying base configuration files
* **Secret injection** -- reference credentials set in the environment rather than hardcoding them in YAML (for production, use a [secret provider](/reference/orchestrator/configuration/secret-providers) instead)
## Configuration
Reference environment variables in your YAML configuration using the `{{ env.VAR_NAME }}` syntax (spaces inside braces are optional):
```yaml theme={null}
# In maverics.yaml, reference environment variables:
connectors:
- name: azure
type: azure
oauthClientID: "{{ env.AZURE_CLIENT_ID }}"
oidcWellKnownURL: "https://login.microsoftonline.com/{{ env.AZURE_TENANT_ID }}/v2.0/.well-known/openid-configuration"
oauthClientSecret: "{{ env.AZURE_CLIENT_SECRET }}"
http:
address: "{{ env.LISTEN_ADDRESS }}"
```
Set the environment variables before starting the Orchestrator:
```bash theme={null}
# Set the environment variables
export AZURE_CLIENT_ID="my-client-id"
export AZURE_TENANT_ID="my-tenant-id"
export AZURE_CLIENT_SECRET="my-client-secret"
export LISTEN_ADDRESS="0.0.0.0:9443"
# Start the Orchestrator
maverics -config maverics.yaml
```
Lines starting with `#` (YAML comments) are not processed for substitution.
## Syntax Reference
| Syntax | Description |
| -------------------- | -------------------------------------------------------- |
| `{{ env.VAR_NAME }}` | Substitutes the value of `VAR_NAME` from the environment |
| `{{env.VAR_NAME}}` | Also valid -- spaces inside braces are optional |
The substitution happens at configuration load time. If the referenced environment variable is not set, the Orchestrator will use an empty string.
## Troubleshooting
* **Empty values at runtime** -- verify the environment variable is set in the same shell or process where the Orchestrator runs. Use `printenv VAR_NAME` to confirm.
* **Substitution not working** -- check that the syntax uses `env.` prefix (not just the variable name). The correct format is `{{ env.MY_VAR }}`, not `{{ MY_VAR }}` or `$MY_VAR`.
* **Values with special characters** -- wrap the substitution in quotes in YAML to prevent parsing issues: `"{{ env.MY_VAR }}"`.
## Related Pages
Overview of all configuration sources
Load config from a local YAML file
Secure secret injection via dedicated secret providers
# File
Source: https://docs.strata.io/reference/orchestrator/configuration/config-sources/file
The File config source reads Orchestrator configuration from a YAML file on the local filesystem. This is the simplest configuration source and the default for most deployments.
**Console terminology:** In the Maverics Console, Orchestrator instances and
configuration delivery are managed through **Deployments**. When working directly
with YAML, configuration is managed as files delivered via the `-config` flag or
`MAVERICS_CONFIG` environment variable.
## Overview
When using the File config source, the Orchestrator reads its configuration from a YAML file on disk at startup. The file path is specified via the `-config` CLI flag or the `MAVERICS_CONFIG` environment variable.
## Use Cases
* **Development and testing** -- load configuration from a local file during development without requiring external services
* **Single-node deployments** -- simple deployments where a single Orchestrator instance reads from a local config file
* **Air-gapped environments** -- deployments without network access to remote config sources
## Configuration
The File config source is configured via a CLI flag or environment variable, not in the YAML file itself.
```bash theme={null}
# Via CLI flag (recommended)
maverics -config /etc/maverics/maverics.yaml
# Via environment variable
export MAVERICS_CONFIG=/etc/maverics/maverics.yaml
maverics
```
The file path can be absolute or relative to the Orchestrator's working directory. If neither `-config` nor `MAVERICS_CONFIG` is set, the Orchestrator defaults to `/etc/maverics/maverics.yaml`.
The Orchestrator also supports loading configuration from a `.tar.gz` bundle:
```bash theme={null}
# Load from a config bundle
maverics -config /etc/maverics/config-bundle.tar.gz
# Optionally verify bundle signature
export MAVERICS_BUNDLE_PUBLIC_KEY_FILE=/etc/maverics/bundle-key.pem
maverics -config /etc/maverics/config-bundle.tar.gz
```
The File source does not support hot-reload. To apply configuration changes, restart the Orchestrator. For automatic config updates, use a [remote config source](/reference/orchestrator/configuration/config-sources) such as S3, Azure Blob, GCS, GitHub, or GitLab.
## Console Download-Only Workflow
The Maverics Console supports a download-only workflow where no cloud storage service is configured. Instead, you build your deployment in the Console, download the config bundle, and point the Orchestrator to it locally.
In the Console, go to **Deployments**. Create a new deployment or select an existing one. Under **Host Environment**, click **Edit** next to **Configuration Storage**. Select **No cloud storage service configured** (download only). Click **Save**.
Publish your deployment configuration. Download the config bundle (`maverics.tar.gz`) and the public key file from the Console.
Start the Orchestrator with the downloaded bundle:
```bash theme={null}
export MAVERICS_BUNDLE_PUBLIC_KEY_FILE=/path/to/bundle-key.pem
maverics -config /path/to/maverics.tar.gz
```
This workflow is useful when you want to use the Console UI for configuration authoring but manage config delivery yourself, such as in air-gapped environments or when integrating with existing deployment pipelines.
## Configuration Reference
| Setting | Type | Default | Description |
| ----------------------------------------- | ------ | ----------------------------- | ---------------------------------------------------------------- |
| `-config` flag | string | `/etc/maverics/maverics.yaml` | Path to the YAML configuration file or `.tar.gz` bundle |
| `MAVERICS_CONFIG` env var | string | `/etc/maverics/maverics.yaml` | Environment variable alternative to the `-config` flag |
| `MAVERICS_BUNDLE_PUBLIC_KEY_FILE` env var | string | -- | Path to a public key file for verifying config bundle signatures |
**Precedence:** The `-config` CLI flag takes priority over the `MAVERICS_CONFIG` environment variable.
## Troubleshooting
* **File not found** -- verify the file path is correct and the Orchestrator process has read permissions. Check with `ls -la /path/to/config.yaml`.
* **YAML parsing errors** -- validate YAML syntax before starting. Ensure indentation uses spaces (not tabs) and all keys are properly nested.
* **Config not updating** -- the File source does not support hot-reload. Restart the Orchestrator after changing the configuration file.
## Related Pages
Overview of all configuration sources
Substitute environment variables in YAML config
Complete configuration field reference
Bundle format, signing, and deployment lifecycle
# Google Cloud Storage
Source: https://docs.strata.io/reference/orchestrator/configuration/config-sources/gcs
The Google Cloud Storage (GCS) config source loads Orchestrator configuration from an object stored in a GCS bucket. The source is configured entirely through the `MAVERICS_GCP_CONFIG` environment variable.
**Console terminology:** In the Maverics Console, Orchestrator instances and
configuration delivery are managed through **Deployments**. When working directly
with YAML, configuration is managed as files delivered via the `-config` flag or
`MAVERICS_CONFIG` environment variable.
## Prerequisites
* **A Google Cloud account** -- with a Cloud Storage bucket containing Orchestrator configuration
* **A service account key JSON** -- with `storage.objects.get` permission (see the [GCS deployment provider](/reference/console/config-publishing/gcs) page for detailed setup steps), or workload identity configured for GCP-hosted deployments
## Overview
When the `MAVERICS_GCP_CONFIG` environment variable is set, the Orchestrator fetches its YAML configuration from the specified GCS bucket and object path. The variable contains a JSON payload with connection details and optional service account credentials. The Orchestrator supports ETag-based change detection for automatic hot-reload.
## Use Cases
* **GCP-native deployments** -- store configuration in GCS alongside other GCP resources with native IAM authentication
* **GCP CI/CD** -- publish validated configuration to GCS as part of Cloud Build or other GCP CI/CD pipelines
* **Multi-cloud with GCS as config store** -- use GCS as a centralized config store accessible from any cloud environment
## Service Account Setup
Follow the same steps described in the [Console GCS setup guide](/reference/console/config-publishing/gcs#create-a-service-account-and-key), but assign the **Storage Object Viewer** role instead of Storage Object Admin. The Orchestrator only needs to read configuration, not write it.
Alternatively, if running on GCE or GKE, configure workload identity to avoid managing service account keys entirely.
Copy the entire JSON body of the downloaded key file and use it as the `key` value in the `MAVERICS_GCP_CONFIG` environment variable (see Configuration below).
## Configuration
The GCS config source is configured via the `MAVERICS_GCP_CONFIG` environment variable with a JSON payload:
```bash theme={null}
export MAVERICS_GCP_CONFIG='{
"bucketName": "my-config-bucket",
"configurationFilePath": "path/to/config",
"key": { ... }
}'
maverics
```
When running on GCE or GKE with workload identity, omit the `key` field. The Orchestrator uses the default GCP credential chain (Application Default Credentials).
**Workload identity example (recommended for GCP-hosted deployments):**
```bash theme={null}
export MAVERICS_GCP_CONFIG='{
"bucketName": "my-config-bucket",
"configurationFilePath": "path/to/config"
}'
maverics
```
## Configuration Reference
The `MAVERICS_GCP_CONFIG` JSON payload supports the following fields:
| Field | Type | Required | Description |
| ----------------------- | ------ | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `bucketName` | string | Yes | GCS bucket name |
| `configurationFilePath` | string | No | Directory path prefix within the bucket where the config bundle is stored. The Orchestrator appends `maverics.tar.gz` to this path. If omitted, the bundle is expected at the bucket root. |
| `key` | object | Conditional | GCP service account key JSON (not needed with workload identity) |
**ETag-based hot-reload:** When `MAVERICS_RELOAD_CONFIG=true` is set, the Orchestrator periodically checks the object's ETag. When the ETag changes (indicating the file was updated), the Orchestrator reloads the configuration automatically.
## Full Environment Example
A complete `maverics.env` file for an Orchestrator using Google Cloud Storage as its config source:
```bash maverics.env theme={null}
MAVERICS_DEBUG_MODE=true
MAVERICS_HTTP_ADDRESS=:443
MAVERICS_TLS_SERVER_CERT_FILE=your-cert.pem
MAVERICS_TLS_SERVER_KEY_FILE=your-private_key.pem
MAVERICS_RELOAD_CONFIG=true
MAVERICS_POLLING_INTERVAL_SECONDS=30
MAVERICS_BUNDLE_PUBLIC_KEY_FILE=./public_key.pem
MAVERICS_GCP_CONFIG='{"bucketName":"", "configurationFilePath":"", "key": }'
```
Replace the placeholder values with your actual certificate paths, bucket name, config file path, and service account key JSON.
## Troubleshooting
* **Permission denied** -- verify the service account (or workload identity) has `storage.objects.get` permission on the bucket. Check IAM bindings in the GCP Console.
* **Bucket not found** -- confirm the `bucketName` is correct. GCS bucket names are globally unique and case-sensitive.
* **Service account key issues** -- if using a `key` object, ensure it is a valid GCP service account key JSON. The key must have the `storage.objects.get` permission.
* **Config not reloading** -- ensure `MAVERICS_RELOAD_CONFIG=true` is set. Check Orchestrator logs for ETag change detection messages.
## Related Pages
Overview of all configuration sources
Load config from AWS S3
Complete configuration field reference
Console-side GCS setup and service account key generation
# GitHub
Source: https://docs.strata.io/reference/orchestrator/configuration/config-sources/github
The GitHub config source loads Orchestrator configuration directly from a GitHub repository. The source is configured entirely through the `MAVERICS_GITHUB_CONFIG` environment variable.
**Console terminology:** In the Maverics Console, Orchestrator instances and
configuration delivery are managed through **Deployments**. When working directly
with YAML, configuration is managed as files delivered via the `-config` flag or
`MAVERICS_CONFIG` environment variable.
## Prerequisites
* **A GitHub account** -- with a repository containing Orchestrator configuration
* **A fine-grained personal access token** -- with Contents read access (see the [GitHub deployment provider](/reference/console/config-publishing/github#generate-a-fine-grained-personal-access-token) page for detailed token generation steps)
## Overview
When the `MAVERICS_GITHUB_CONFIG` environment variable is set, the Orchestrator fetches its YAML configuration from the specified GitHub repository and file path. The variable contains a JSON payload with repository details and a personal access token for authentication. The Orchestrator supports ETag-based change detection for automatic hot-reload when the configuration file changes in the repository.
## Use Cases
* **GitOps workflows** -- manage Orchestrator configuration in Git with full version history, branching, and merge controls
* **Version-controlled config** -- track every configuration change with commit history and blame annotations
* **PR-based config review** -- require peer review of configuration changes before they reach production
## Generating a Personal Access Token
Follow the same steps described in the [Console GitHub setup guide](/reference/console/config-publishing/github#generate-a-fine-grained-personal-access-token), but set **Contents** to **Read-only** instead of Read and write. The Orchestrator only needs to read configuration, not write it.
Copy the generated token value and use it as the `token` field in the `MAVERICS_GITHUB_CONFIG` environment variable (see Configuration below).
## Configuration
The GitHub config source is configured via the `MAVERICS_GITHUB_CONFIG` environment variable with a JSON payload:
```bash theme={null}
export MAVERICS_GITHUB_CONFIG='{
"owner": "my-org",
"repo": "orchestrator-config",
"token": "ghp_...",
"configurationFilePath": "path/to/config"
}'
maverics
```
## Configuration Reference
The `MAVERICS_GITHUB_CONFIG` JSON payload supports the following fields:
| Field | Type | Required | Description |
| ----------------------- | ------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `owner` | string | Yes | GitHub repository owner (user or organization) |
| `repo` | string | Yes | Repository name |
| `token` | string | Yes | Fine-grained personal access token with Contents read access |
| `configurationFilePath` | string | No | Directory path prefix within the repository where the config bundle is stored. The Orchestrator appends `maverics.tar.gz` to this path. If omitted, the bundle is expected at the repository root. |
**ETag-based hot-reload:** When `MAVERICS_RELOAD_CONFIG=true` is set, the Orchestrator periodically checks the file's ETag via the GitHub API. When the file is updated (via commit), the Orchestrator detects the ETag change and reloads the configuration automatically.
## Full Environment Example
A complete `maverics.env` file for an Orchestrator using GitHub as its config source:
```bash maverics.env theme={null}
MAVERICS_DEBUG_MODE=true
MAVERICS_HTTP_ADDRESS=:443
MAVERICS_TLS_SERVER_CERT_FILE=your-cert.pem
MAVERICS_TLS_SERVER_KEY_FILE=your-private_key.pem
MAVERICS_RELOAD_CONFIG=true
MAVERICS_POLLING_INTERVAL_SECONDS=30
MAVERICS_BUNDLE_PUBLIC_KEY_FILE=./public_key.pem
MAVERICS_GITHUB_CONFIG='{"token":"", "owner":"", "repo":"", "configurationFilePath": ""}'
```
Replace the placeholder values with your actual certificate paths, GitHub organization or username, repository name, and personal access token.
## Troubleshooting
* **Authentication failed (401)** -- verify the personal access token is valid and has not expired. The token needs read access to the repository contents.
* **Repository not found (404)** -- confirm the `owner` and `repo` values are correct. For private repositories, ensure the token has the `repo` scope.
* **File not found** -- check the `configurationFilePath` matches the actual directory path in the repository (case-sensitive, relative to the repo root). The Orchestrator looks for `maverics.tar.gz` at this path.
* **Config not reloading** -- ensure `MAVERICS_RELOAD_CONFIG=true` is set. Note that GitHub API rate limits may affect polling frequency.
## Related Pages
Overview of all configuration sources
Load config from a GitLab repository
Complete configuration field reference
Console-side GitHub setup and personal access token generation
# GitLab
Source: https://docs.strata.io/reference/orchestrator/configuration/config-sources/gitlab
The GitLab config source loads Orchestrator configuration directly from a GitLab.com repository. The source is configured entirely through the `MAVERICS_GITLAB_CONFIG` environment variable.
**Console terminology:** In the Maverics Console, Orchestrator instances and
configuration delivery are managed through **Deployments**. When working directly
with YAML, configuration is managed as files delivered via the `-config` flag or
`MAVERICS_CONFIG` environment variable.
## Prerequisites
* **A GitLab account** -- with a project containing Orchestrator configuration
* **A personal access token** -- with `read_repository` scope (see the [GitLab deployment provider](/reference/console/config-publishing/gitlab#generate-a-personal-access-token) page for detailed token generation steps)
## Overview
When the `MAVERICS_GITLAB_CONFIG` environment variable is set, the Orchestrator fetches its YAML configuration from the specified GitLab project and file path. The variable contains a JSON payload with project details, authentication token, and optional branch selection. The Orchestrator supports ETag-based change detection for automatic hot-reload.
## Use Cases
* **GitOps with GitLab** -- manage Orchestrator configuration in GitLab with full version history and merge request workflows
* **CI/CD pipeline integration** -- publish validated configuration as part of GitLab CI/CD pipelines
* **Merge request workflows** -- require peer review of configuration changes through GitLab merge requests before they reach production
## Generating a Personal Access Token
Follow the same steps described in the [Console GitLab setup guide](/reference/console/config-publishing/gitlab#generate-a-personal-access-token), but only check **`read_repository`** instead of both scopes. The Orchestrator only needs to read configuration, not write it.
Copy the generated token value and use it as the `token` field in the `MAVERICS_GITLAB_CONFIG` environment variable (see Configuration below).
## Configuration
The GitLab config source is configured via the `MAVERICS_GITLAB_CONFIG` environment variable with a JSON payload:
```bash theme={null}
export MAVERICS_GITLAB_CONFIG='{
"namespace": "my-group",
"repo": "orchestrator-config",
"branch": "main",
"token": "glpat-...",
"configurationFilePath": "path/to/config"
}'
maverics
```
## Configuration Reference
The `MAVERICS_GITLAB_CONFIG` JSON payload supports the following fields:
| Field | Type | Required | Description |
| ----------------------- | ------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `namespace` | string | Yes | GitLab namespace (group or user) |
| `repo` | string | Yes | Project name |
| `branch` | string | No | Branch to read from (default: the project's default branch) |
| `token` | string | Yes | Personal access token with `read_repository` scope |
| `configurationFilePath` | string | No | Directory path prefix within the repository where the config bundle is stored. The Orchestrator appends `maverics.tar.gz` to this path. If omitted, the bundle is expected at the repository root. |
**ETag-based hot-reload:** When `MAVERICS_RELOAD_CONFIG=true` is set, the Orchestrator periodically checks the file's ETag via the GitLab API. When the file is updated (via commit), the Orchestrator detects the ETag change and reloads the configuration automatically.
## Full Environment Example
A complete `maverics.env` file for an Orchestrator using GitLab as its config source:
```bash maverics.env theme={null}
MAVERICS_DEBUG_MODE=true
MAVERICS_HTTP_ADDRESS=:443
MAVERICS_TLS_SERVER_CERT_FILE=your-cert.pem
MAVERICS_TLS_SERVER_KEY_FILE=your-private_key.pem
MAVERICS_RELOAD_CONFIG=true
MAVERICS_POLLING_INTERVAL_SECONDS=30
MAVERICS_BUNDLE_PUBLIC_KEY_FILE=./public_key.pem
MAVERICS_GITLAB_CONFIG='{"token":"", "namespace":"", "repo":"", "branch":"", "configurationFilePath": ""}'
```
Replace the placeholder values with your actual certificate paths, GitLab namespace, project name, branch, and personal access token.
## Troubleshooting
* **Authentication failed (401)** -- verify the personal access token is valid and has not expired. The token needs the `read_repository` scope.
* **Project not found (404)** -- confirm the `namespace` and `repo` values are correct. For private projects, ensure the token has appropriate access.
* **Wrong branch** -- if `branch` is omitted, the project's default branch is used. Set `branch` explicitly if the config file is on a different branch.
* **GitLab.com only** -- the Orchestrator connects to `gitlab.com`. Self-hosted GitLab instances are not currently supported as a config source.
* **Config not reloading** -- ensure `MAVERICS_RELOAD_CONFIG=true` is set. Check Orchestrator logs for ETag change detection messages.
## Related Pages
Overview of all configuration sources
Load config from a GitHub repository
Complete configuration field reference
Console-side GitLab setup and personal access token generation
# Amazon S3
Source: https://docs.strata.io/reference/orchestrator/configuration/config-sources/s3
The Amazon S3 config source loads Orchestrator configuration from an object stored in an AWS S3 bucket. The source is configured entirely through the `MAVERICS_AWS_CONFIG` environment variable.
**Console terminology:** In the Maverics Console, Orchestrator instances and
configuration delivery are managed through **Deployments**. When working directly
with YAML, configuration is managed as files delivered via the `-config` flag or
`MAVERICS_CONFIG` environment variable.
## Prerequisites
* **An active AWS account** -- with an S3 bucket containing Orchestrator configuration
* **An IAM user or role with read access** -- with `s3:GetObject` permission on the bucket (see the [S3 deployment provider](/reference/console/config-publishing/s3) page for detailed IAM setup steps), or an EC2/EKS instance role configured for S3 access
## Overview
When the `MAVERICS_AWS_CONFIG` environment variable is set, the Orchestrator fetches its YAML configuration from the specified S3 bucket and object path. The variable contains a JSON payload with connection details and credentials. The Orchestrator supports ETag-based change detection for automatic hot-reload of configuration changes.
## Use Cases
* **AWS-native deployments** -- store configuration alongside other AWS infrastructure artifacts using native IAM authentication
* **CI/CD config delivery** -- push validated configuration to S3 from any CI/CD pipeline (Jenkins, GitHub Actions, CodePipeline) and let the Orchestrator pick it up automatically
* **Multi-region config distribution** -- leverage S3 cross-region replication to distribute configuration globally
## Configuration
The S3 config source is configured via the `MAVERICS_AWS_CONFIG` environment variable with a JSON payload:
```bash theme={null}
export MAVERICS_AWS_CONFIG='{
"region": "us-west-2",
"accessKeyID": "AKIA...",
"secretAccessKey": "...",
"bucketName": "my-config-bucket",
"configurationFilePath": "path/to/config"
}'
maverics
```
When running on EC2 or ECS with an IAM role, omit `accessKeyID` and `secretAccessKey`. The Orchestrator uses the default AWS credential chain.
**IAM role example (recommended for AWS-hosted deployments):**
```bash theme={null}
export MAVERICS_AWS_CONFIG='{
"region": "us-west-2",
"bucketName": "my-config-bucket",
"configurationFilePath": "path/to/config"
}'
maverics
```
## Configuration Reference
The `MAVERICS_AWS_CONFIG` JSON payload supports the following fields:
| Field | Type | Required | Description |
| ----------------------- | ------ | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `region` | string | Yes | AWS region (e.g., `us-west-2`) |
| `accessKeyID` | string | Conditional | AWS access key ID (not needed with IAM role) |
| `secretAccessKey` | string | Conditional | AWS secret access key (not needed with IAM role) |
| `bucketName` | string | Yes | S3 bucket name |
| `configurationFilePath` | string | No | Directory path prefix within the bucket where the config bundle is stored. The Orchestrator appends `maverics.tar.gz` to this path. If omitted, the bundle is expected at the bucket root. |
**ETag-based hot-reload:** When `MAVERICS_RELOAD_CONFIG=true` is set, the Orchestrator periodically checks the S3 object's ETag. When the ETag changes (indicating the file was updated), the Orchestrator reloads the configuration automatically.
## IAM Permissions
The Orchestrator requires read-only access to the S3 bucket. Attach the following IAM policy to the IAM role or user that the Orchestrator uses:
```json theme={null}
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::YOUR-BUCKET-NAME/*"
}
]
}
```
Replace `YOUR-BUCKET-NAME` with your actual bucket name. If you use a `configurationFilePath`, you can further restrict the `Resource` to the specific object path (e.g., `arn:aws:s3:::my-bucket/path/to/config/maverics.tar.gz`).
If the Maverics Console publishes bundles to the same S3 bucket, the Console's IAM role requires additional permissions (`s3:PutObject`, `s3:ListBucket`, `s3:DeleteObject`). See [Publishing Deployment Configs overview](/reference/console/config-publishing) for Console-side setup.
**EKS and EC2 deployments:** When running on Amazon EKS or EC2, you can use an IAM role attached to the instance or pod instead of embedding access keys. Omit `accessKeyID` and `secretAccessKey` from `MAVERICS_AWS_CONFIG` and the Orchestrator uses the default AWS credential chain. See [IAM roles for Amazon EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html) and [IAM roles for service accounts on EKS](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html) for setup details.
## Full Environment Example
A complete `maverics.env` file for an Orchestrator using Amazon S3 as its config source:
```bash maverics.env theme={null}
MAVERICS_DEBUG_MODE=true
MAVERICS_HTTP_ADDRESS=:443
MAVERICS_TLS_SERVER_CERT_FILE=your-cert.pem
MAVERICS_TLS_SERVER_KEY_FILE=your-private_key.pem
MAVERICS_RELOAD_CONFIG=true
MAVERICS_POLLING_INTERVAL_SECONDS=30
MAVERICS_BUNDLE_PUBLIC_KEY_FILE=./public_key.pem
MAVERICS_AWS_CONFIG='{"region":"", "accessKeyID":"", "secretAccessKey":"", "bucketName":"", "configurationFilePath":""}'
```
Replace the placeholder values with your actual certificate paths, AWS region, access key credentials, bucket name, and config file path. When using IAM roles (EC2/EKS), omit `accessKeyID` and `secretAccessKey`.
## Troubleshooting
* **Access denied** -- verify the IAM role or access key has `s3:GetObject` permission on the bucket and object path. Check the bucket policy as well.
* **Bucket not found** -- confirm the `region` matches the bucket's actual region. S3 bucket names are globally unique but region-specific for access.
* **Config not reloading** -- ensure `MAVERICS_RELOAD_CONFIG=true` is set. Check the Orchestrator logs for ETag change detection messages.
## Related Pages
Overview of all configuration sources
Load config from Azure Blob Storage
Complete configuration field reference
Console-side S3 setup, IAM policies, and cross-account role creation
# Field Reference
Source: https://docs.strata.io/reference/orchestrator/configuration/reference
Quick reference for every top-level key in the Orchestrator's YAML configuration file. Keys that have dedicated reference pages link out to avoid duplication -- keys documented only here include their full field tables.
For a conceptual overview of how configuration works, see the [Configuration overview](/reference/orchestrator/configuration).
## `version`
Required. Specifies the configuration format version.
| Key | Type | Required | Description |
| --------- | ------ | -------- | ------------------------------------------------ |
| `version` | string | Yes | Configuration version -- currently accepts `"1"` |
```yaml theme={null}
version: "1"
```
## `features`
Optional. Enables experimental or gated behavior via feature flags.
| Key | Type | Required | Description |
| ---------- | ------------------ | -------- | --------------------------------------------------------------------------------------------------------------------- |
| `features` | map\[string]string | No | Feature flag map -- values `"true"` or `"enabled"` (case-insensitive) turn a feature on; any other value turns it off |
**Parsing rules:** Only `"true"` and `"enabled"` (case-insensitive) are recognized as enabled. Any other value, or a missing flag, is treated as disabled.
## `http`
Optional. Controls the HTTP server -- bind address, TLS, timeouts, and access logging.
| Key | Type | Default | Description |
| ------------------------------- | ------- | ---------------- | -------------------------------------------------------------------------------------------------- |
| `http.address` | string | `"0.0.0.0:9443"` | Network address and port to bind to |
| `http.tls` | string | -- | Name of a TLS profile defined under the top-level `tls` key (mutually exclusive with `http.hosts`) |
| `http.readTimeoutSeconds` | integer | `20` | Maximum seconds to read the full request |
| `http.readHeaderTimeoutSeconds` | integer | `5` | Maximum seconds to read request headers |
| `http.writeTimeoutSeconds` | integer | `20` | Maximum seconds to write the response |
| `http.idleTimeoutSeconds` | integer | `60` | Maximum seconds to keep idle connections open |
| `http.endpointTimeoutSeconds` | integer | `15` | Maximum seconds for an endpoint handler to complete |
| `http.accessLog.disabled` | boolean | `false` | Disable HTTP access logging |
| `http.accessLog.level` | string | `"info"` | Access log level -- `"debug"`, `"info"`, or `"error"` |
| `http.hosts` | array | -- | SNI-based virtual host configurations (mutually exclusive with `http.tls`) |
| `http.hosts[].serverName` | string | -- | Server name indicator (SNI) used for matching incoming TLS connections |
| `http.hosts[].default` | boolean | `false` | Use this host as the fallback when no SNI match is found; only one entry may set this to `true` |
| `http.hosts[].tls` | string | -- | Name of the TLS profile to use for this host (required) |
Single TLS profile:
```yaml maverics.yaml theme={null}
http:
address: "0.0.0.0:9443"
tls: "default"
readTimeoutSeconds: 20
writeTimeoutSeconds: 20
```
SNI-based virtual hosts (mutually exclusive with `http.tls`):
```yaml maverics.yaml theme={null}
http:
address: "0.0.0.0:443"
hosts:
- serverName: "app.example.com"
tls: "app-cert"
- serverName: "api.example.com"
tls: "api-cert"
- default: true
tls: "app-cert"
tls:
"app-cert":
certFile: /etc/maverics/certs/app.pem
keyFile: /etc/maverics/certs/app-key.pem
"api-cert":
certFile: /etc/maverics/certs/api.pem
keyFile: /etc/maverics/certs/api-key.pem
```
See the [TLS Security guide](/guides/security/tls) for full details on SNI-based certificate selection.
## `tls`
Optional. Named TLS profiles for server certificates, cipher suites, mTLS, and certificate revocation checking.
See the [TLS Security reference](/reference/orchestrator/tls-security) for the full field table, mTLS configuration, OCSP/CRL settings, and Windows Certificate Store support.
```yaml theme={null}
tls:
"default":
certFile: /etc/maverics/certs/server.pem
keyFile: /etc/maverics/certs/server-key.pem
minVersion: "1.2"
maxVersion: "1.3"
```
## `connectors`
Optional. Identity provider connections -- OIDC, SAML, LDAP, and attribute providers.
See the [Identity Fabric reference](/reference/orchestrator/identity-fabric) for all supported connector types, protocol details, and per-provider configuration.
```yaml theme={null}
connectors:
- name: azure
type: azure
oauthClientID: "{{ env.AZURE_CLIENT_ID }}"
oauthClientSecret:
oidcWellKnownURL: "https://login.microsoftonline.com/{{ env.TENANT_ID }}/v2.0/.well-known/openid-configuration"
```
## `apps`
Optional. Application definitions with routes, authentication policies, and upstream targets.
See the [Applications reference](/reference/orchestrator/applications) for app types (Proxy, OIDC, SAML, MCP Bridge, MCP Proxy) and route configuration.
```yaml theme={null}
apps:
- name: my-app
type: proxy
upstream: "https://internal-app.example.com"
routePatterns:
- "app.example.com/"
```
## `oidcProvider`
Optional. OIDC Provider mode settings -- token signing, claim mapping, and client registration.
See the [OIDC Provider reference](/reference/modes/oidc-provider) for the full configuration.
## `samlProvider`
Optional. SAML Provider mode settings -- assertion signing, attribute mapping, and metadata.
See the [SAML Provider reference](/reference/modes/saml-provider) for the full configuration.
## `ldapProvider`
Optional. LDAP Provider mode settings -- virtual directory, attribute mapping, and backend routing.
See the [LDAP Provider reference](/reference/modes/ldap-provider) for the full configuration.
## `mcpProvider`
Optional. AI Identity Gateway mode settings -- MCP Bridge and MCP Proxy configuration.
See the [AI Identity Gateway reference](/reference/modes/ai-identity-gateway) for the full configuration.
## `session`
Optional. Session cookie, lifetime, and store configuration.
See the [Sessions reference](/reference/orchestrator/sessions) for session types, cookie settings, and lifetime configuration.
```yaml theme={null}
session:
cookie:
name: "__Host-maverics"
secure: true
lifetime: "8h"
```
## `caches`
Optional. Named cache stores for session data, tokens, and IdP metadata.
See the [Caches reference](/reference/orchestrator/caches) for Redis configuration and connection settings.
```yaml theme={null}
caches:
- name: shared-redis
type: redis
redis:
addresses:
- "redis.example.com:6379"
```
## `logger`
Optional. Structured logging configuration.
See the [Logging reference](/reference/orchestrator/telemetry/logging) for verbosity levels, JSON output, and filtering.
```yaml theme={null}
logger:
level: "info"
jsonOutput: true
```
## `health`
Optional. Health check endpoint and heartbeat monitoring.
See the [Telemetry reference](/reference/orchestrator/telemetry) for health endpoint configuration.
```yaml theme={null}
health:
location: "/status"
heartbeat:
interval: "60s"
```
## `telemetry`
Optional. OpenTelemetry metrics and traces via OTLP.
See the [Telemetry reference](/reference/orchestrator/telemetry) for metrics, traces, and OTLP exporter configuration.
## `singleLogout`
Optional. Single logout endpoint and post-logout redirect behavior.
See the [Single Logout guide](/guides/authentication/single-logout) for configuration and flow details.
## `apis`
Optional. Custom API endpoints powered by Service Extensions.
See the [Custom APIs](/reference/orchestrator/service-extensions/custom-apis) reference for custom API configuration.
## Related Pages
Conceptual overview, environment variables, and runtime behavior
CLI flags, environment variables, and deployment options
# Secret Providers
Source: https://docs.strata.io/reference/orchestrator/configuration/secret-providers
Secret providers allow the Maverics Orchestrator to retrieve sensitive values -- such as API keys, certificates, and database credentials -- from external secret management systems at runtime. This keeps secrets out of configuration files and ensures they are managed according to your organization's security policies.
**Console terminology:** In the Maverics Console, Orchestrator instances and
configuration delivery are managed through **Deployments**. When working directly
with YAML, configuration is managed as files delivered via the `-config` flag or
`MAVERICS_CONFIG` environment variable.
## How Secret Providers Work
Secret providers are configured via the `MAVERICS_SECRET_PROVIDER` environment variable or the `-secretProvider` CLI flag -- not in YAML configuration. Only one secret provider may be active at a time.
```bash theme={null}
# Configure via environment variable
export MAVERICS_SECRET_PROVIDER="hashivault://vault.example.com:8200/secret/data/maverics?token="
# Or via CLI flag
maverics -config maverics.yaml -secretProvider "hashivault://vault.example.com:8200/secret/data/maverics?token="
```
Once a secret provider is configured, you reference secrets in your YAML configuration using angle bracket syntax:
```yaml theme={null}
connectors:
- name: my-idp
oauthClientSecret:
```
At startup (and on config reloads), the Orchestrator resolves `` by fetching it from the configured secret provider. The namespace (`maverics`) and key (`client_secret`) map to the secret path and key in the provider.
### Using Secret References in the Console
The same angle bracket syntax works in the Maverics Console. When configuring connectors, apps, or other resources in the Console, use secret references (e.g., ``) in any field that accepts a sensitive value. The Orchestrator resolves them at runtime just as it does with YAML.
Never enter actual secret values into the Console. Always use secret provider
references instead. Configuration entered in the Console is stored as a
deployment config -- secret references ensure that sensitive values remain in
your secret management system and are never persisted in the configuration
itself.
This applies even during testing. While you could enter plaintext values for local testing against non-production resources, we recommend using secret references from the start to build good habits. The [Secret File](/reference/orchestrator/configuration/secret-providers/environment) provider makes this easy -- point the Orchestrator at a local YAML file and reference those secrets in the Console the same way you would in production.
## Available Providers
| Provider | URL Scheme | Use Case |
| ------------------------------------------------------------------------------------------------- | ---------------------- | ------------------------------------------------- |
| [AWS Secrets Manager](/reference/orchestrator/configuration/secret-providers/aws-secrets-manager) | `awssecretsmanager://` | AWS-native secret storage |
| [Azure Key Vault](/reference/orchestrator/configuration/secret-providers/azure-key-vault) | `azurekeyvault://` | Azure-native secret and certificate management |
| [CyberArk CCP](/reference/orchestrator/configuration/secret-providers/cyberark-ccp) | `cyberarkccp://` | CyberArk Central Credential Provider |
| [CyberArk Conjur](/reference/orchestrator/configuration/secret-providers/conjur) | `conjur://` | DevOps-oriented secrets for CI/CD and containers |
| [Delinea Secret Server](/reference/orchestrator/configuration/secret-providers/delinea) | `delinea://` | Enterprise privileged access management |
| [HashiCorp Vault](/reference/orchestrator/configuration/secret-providers/hashicorp-vault) | `hashivault://` | Enterprise secret management with dynamic secrets |
| [Secret File](/reference/orchestrator/configuration/secret-providers/environment) | `secretfile://` | Local file-based secrets for testing |
## Provider Pages
AWS-native secret storage
Azure-native secret and certificate management
CyberArk Central Credential Provider
DevOps-oriented secrets for CI/CD and containers
Enterprise privileged access management
Enterprise secret management with dynamic secrets
Local file-based secrets for testing
## Related Pages
Identity provider integrations
Where the Orchestrator reads its configuration
# AWS Secrets Manager
Source: https://docs.strata.io/reference/orchestrator/configuration/secret-providers/aws-secrets-manager
The AWS Secrets Manager secret provider connects the Orchestrator to AWS Secrets Manager for cloud-native secrets management. This provider integrates natively with AWS IAM, making it ideal for Orchestrator deployments running on AWS infrastructure.
**Console terminology:** In the Maverics Console, Orchestrator instances and
configuration delivery are managed through **Deployments**. When working directly
with YAML, configuration is managed as files delivered via the `-config` flag or
`MAVERICS_CONFIG` environment variable.
## Overview
When configured with the AWS Secrets Manager provider, the Orchestrator authenticates to AWS using the SDK default configuration and retrieves secrets on demand as they are referenced in the Orchestrator configuration. The provider supports AWS SDK credential resolution (IAM roles, environment variables, shared credentials) as well as explicit access key credentials provided in the URL. Secrets can be referenced by name or by ARN, and JSON secrets support individual key extraction.
## Use Cases
* **AWS-native deployments** -- retrieve Orchestrator secrets from AWS Secrets Manager when running on AWS infrastructure, using IAM for authentication
* **Existing AWS Secrets Manager deployments** -- use an existing Secrets Manager setup without duplicating credentials into another system
* **Centralized credential rotation** -- rotate secrets in AWS and pick up new values on Orchestrator restart or config reload
## Configuration
Secret providers are not configured in YAML. They are set via the `MAVERICS_SECRET_PROVIDER` environment variable or the `-secretProvider` CLI flag.
### Configuration via Environment Variable
```bash theme={null}
# Using default AWS SDK credentials (IAM role, env vars, etc.)
export MAVERICS_SECRET_PROVIDER="awssecretsmanager://amazonaws.com?region=us-west-2"
# Using explicit access key credentials
export MAVERICS_SECRET_PROVIDER="awssecretsmanager://amazonaws.com?region=us-west-2&accessKeyID=&secretAccessKey="
```
### Configuration via CLI Flag
```bash theme={null}
maverics -config maverics.yaml -secretProvider "awssecretsmanager://amazonaws.com?region=us-west-2"
```
### Referencing Secrets in YAML
Once the secret provider is configured, reference secrets in your Orchestrator YAML configuration using angle bracket syntax. The secret name in the angle brackets maps directly to the secret name in AWS Secrets Manager:
```yaml theme={null}
connectors:
- name: my-idp
# Retrieve the entire secret value (plaintext or full JSON string)
oauthClientSecret:
# Retrieve a specific key from a JSON secret
oauthClientID:
```
For JSON secrets stored in AWS Secrets Manager, use the `secretName:jsonKey` format to retrieve a specific key from the JSON object. You can also reference secrets by ARN:
```yaml theme={null}
connectors:
- name: my-idp
oauthClientSecret:
```
## Configuration Reference
### URL Structure
```
awssecretsmanager://{host}?{parameters}
```
### URL Parameters
| Parameter | Required | Description |
| ----------------- | -------- | --------------------------------------------------------------------------------------- |
| `region` | No | AWS region for Secrets Manager (e.g., `us-west-2`). Overrides region from SDK defaults. |
| `accessKeyID` | No | AWS access key ID. Must be used with `secretAccessKey`. |
| `secretAccessKey` | No | AWS secret access key. Must be used with `accessKeyID`. |
The URL host (e.g., `amazonaws.com`) is required by URL syntax but is not used
by the provider. The provider connects to AWS Secrets Manager using the AWS SDK
configuration.
### Authentication
The provider loads the default AWS SDK configuration, then optionally overrides the region and credentials with values from the URL query parameters. When `accessKeyID` and `secretAccessKey` are not specified, the SDK resolves credentials from the standard chain (environment variables, shared credentials file, IAM roles, etc.).
For production deployments, use IAM roles instead of static access keys. IAM
roles automatically rotate credentials and do not require secrets to be stored
on the host.
## Troubleshooting
**"AccessDeniedException" when starting the Orchestrator**
Verify that the IAM role or access keys have the `secretsmanager:GetSecretValue` permission for the configured secret ARN. Check the IAM policy attached to the role or user.
**"ResourceNotFoundException" for the secret name**
Confirm the secret name and region are correct. The secret must exist in the specified AWS region. Secret names are case-sensitive.
**Secrets not resolving in YAML configuration**
Ensure the angle bracket reference matches the secret name in AWS Secrets Manager. For JSON secrets, use the `` format to retrieve a specific key. Secret names are case-sensitive.
## Related Pages
Overview of all secret providers
Cloud-native secrets for Azure deployments
# Azure Key Vault
Source: https://docs.strata.io/reference/orchestrator/configuration/secret-providers/azure-key-vault
The Azure Key Vault secret provider connects the Orchestrator to Azure Key Vault for cloud-native secrets and certificate management. This provider authenticates using Microsoft Entra ID service principal credentials, making it suitable for Orchestrator deployments in any environment with Microsoft Entra ID access.
**Console terminology:** In the Maverics Console, Orchestrator instances and
configuration delivery are managed through **Deployments**. When working directly
with YAML, configuration is managed as files delivered via the `-config` flag or
`MAVERICS_CONFIG` environment variable.
## Overview
When configured with the Azure Key Vault provider, the Orchestrator authenticates to Azure using OAuth 2.0 Client Credentials with a service principal and pre-populates all enabled secrets from the specified Key Vault instance at startup. Azure Key Vault stores secrets, certificates, and cryptographic keys -- all accessible through the same provider configuration.
## Use Cases
* **Azure-native secret and certificate storage** -- store and manage Orchestrator secrets and TLS certificates in Key Vault with native Azure integration
* **Centralized secret management** -- manage all Orchestrator secrets in a single Key Vault with access policies and audit logging
* **Key rotation** -- leverage Azure Key Vault's versioning to rotate secrets and pick up new versions on Orchestrator restart
## Configuration
Secret providers are not configured in YAML. They are set via the `MAVERICS_SECRET_PROVIDER` environment variable or the `-secretProvider` CLI flag.
### Configuration via Environment Variable
```bash theme={null}
export MAVERICS_SECRET_PROVIDER="azurekeyvault://my-vault.vault.azure.net?clientID=&clientSecret=&tenantID="
```
### Configuration via CLI Flag
```bash theme={null}
maverics -config maverics.yaml -secretProvider "azurekeyvault://my-vault.vault.azure.net?clientID=&clientSecret=&tenantID="
```
### Referencing Secrets in YAML
Once the secret provider is configured, reference secrets in your Orchestrator YAML configuration using angle bracket syntax. The key in the angle brackets maps to the secret name in the Key Vault:
```yaml theme={null}
connectors:
- name: my-idp
oauthClientSecret:
```
At startup, the provider pre-populates all enabled secrets from the Key Vault. Secret names in the angle brackets must match the secret names stored in Azure Key Vault.
## Configuration Reference
### URL Structure
```
azurekeyvault://{vault-name}.vault.azure.net?clientID={id}&clientSecret={secret}&tenantID={tenant}
```
### URL Parameters
| Parameter | Required | Description |
| -------------- | -------- | -------------------------------------------------------------------------------- |
| Vault hostname | Yes | The full hostname of the Azure Key Vault (e.g., `my-vault.vault.azure.net`) |
| `clientID` | Yes | Microsoft Entra ID application (service principal) client ID |
| `clientSecret` | Yes | Microsoft Entra ID application client secret |
| `tenantID` | Yes | Microsoft Entra ID tenant ID |
| `entraIDHost` | No | Microsoft Entra ID authentication host. Defaults to `login.microsoftonline.com`. |
### Authentication
The provider authenticates to Azure using the OAuth 2.0 Client Credentials flow with the service principal credentials provided in the URL query parameters. It requests a token from the Entra ID token endpoint (`https://{entraIDHost}/{tenantID}/oauth2/v2.0/token`) scoped to the Key Vault.
## Troubleshooting
**"Unauthorized" or "403 Forbidden" when starting the Orchestrator**
Verify that the `clientID`, `clientSecret`, and `tenantID` query parameters are correct. Ensure the service principal has the `Get` and `List` permissions for secrets in the Key Vault access policy (or the `Key Vault Secrets User` RBAC role if using Azure RBAC).
**OAuth token errors**
Check that the `tenantID` is correct and that the service principal has not expired. If using a custom `entraIDHost`, verify it is reachable from the Orchestrator host.
**"VaultNotFound" error**
Confirm the vault hostname is correct and that the Key Vault exists in the expected Azure subscription. The hostname must include `.vault.azure.net`.
**Secrets not resolving in YAML configuration**
Ensure the angle bracket syntax matches the secret names in the Key Vault. The provider pre-populates all enabled secrets at startup -- only enabled secrets are available.
## Related Pages
Overview of all secret providers
Cloud-native secrets for AWS deployments
# CyberArk Conjur
Source: https://docs.strata.io/reference/orchestrator/configuration/secret-providers/conjur
The CyberArk Conjur secret provider connects the Orchestrator to [CyberArk Conjur](https://www.conjur.org/), a secrets management solution designed for DevOps, CI/CD pipelines, and containerized environments. Conjur provides machine identity, secrets management, and fine-grained access control through policy-as-code.
**Console terminology:** In the Maverics Console, Orchestrator instances and
configuration delivery are managed through **Deployments**. When working directly
with YAML, configuration is managed as files delivered via the `-config` flag or
`MAVERICS_CONFIG` environment variable.
## Overview
When configured with the Conjur provider, the Orchestrator authenticates to your Conjur server and retrieves secrets as they are referenced in configuration. Conjur uses its own authentication model based on machine identities and policy definitions, providing granular access control over which hosts and services can access specific secret variables.
## Use Cases
* **Existing Conjur deployments** -- retrieve Orchestrator secrets from an existing Conjur instance without duplicating credentials into another system
* **Policy-as-code access control** -- manage which Orchestrator instances can access which secrets through Conjur's policy definitions
* **Centralized credential rotation** -- rotate secrets in Conjur and pick up new values on Orchestrator restart or config reload
## Configuration
Secret providers are not configured in YAML. They are set via the `MAVERICS_SECRET_PROVIDER` environment variable or the `-secretProvider` CLI flag.
### Configuration via Environment Variable
```bash theme={null}
# With credentials in the URL
export MAVERICS_SECRET_PROVIDER="conjur://conjur.example.com/myaccount/host%2Fmaverics?apikey="
# With credentials from Conjur environment variables
export MAVERICS_SECRET_PROVIDER="conjur://conjur.example.com"
```
The login value may contain `/` characters (e.g., `host/maverics`). These must
be URL-encoded as `%2F` in the provider URL.
### Configuration via CLI Flag
```bash theme={null}
maverics -config maverics.yaml -secretProvider "conjur://conjur.example.com/myaccount/host%2Fmaverics?apikey="
```
### Referencing Secrets in YAML
Once the secret provider is configured, reference secrets in your Orchestrator YAML configuration using angle bracket syntax. The key in the angle brackets maps to the Conjur variable ID:
```yaml theme={null}
connectors:
- name: my-idp
oauthClientSecret:
```
## Configuration Reference
### URL Structure
```
conjur://{host}/{account}/{login}?apikey={apikey}
```
### URL Parameters
| Parameter | Required | Description |
| --------- | ----------- | ---------------------------------------------------------------------------------------------------------------- |
| Host | Conditional | Hostname of the Conjur server (e.g., `conjur.example.com`). Falls back to Conjur configuration if not specified. |
| Account | Conditional | Conjur account name (URL path segment). Falls back to Conjur configuration if not specified. |
| Login | Conditional | Conjur login identity (URL path segment, e.g., `host%2Fmaverics`). Required when `apikey` is provided. |
| `apikey` | No | Conjur API key. When provided with login, authenticates using the key pair. |
### Authentication
The provider first loads the Conjur API configuration from the standard Conjur configuration sources (environment variables, configuration files). If the URL includes a host, account, login, and API key, those values take precedence.
When `login` and `apikey` are provided in the URL, the provider authenticates directly with those credentials. Otherwise, it falls back to credentials from the Conjur environment (e.g., `CONJUR_AUTHN_LOGIN`, `CONJUR_AUTHN_API_KEY`).
## Troubleshooting
**Authentication failures when starting the Orchestrator**
If using URL-based authentication, verify the account, login, and API key are correct in the provider URL. If using environment-based authentication, check that the Conjur environment variables (`CONJUR_ACCOUNT`, `CONJUR_AUTHN_LOGIN`, `CONJUR_AUTHN_API_KEY`) are correctly set.
**"Forbidden" or "403" when retrieving secrets**
Confirm that the Conjur policy grants the Orchestrator host identity `read` and `execute` permissions on the required secret variables.
**Secrets not resolving in YAML configuration**
Ensure the angle bracket syntax matches the variable names in Conjur. The namespace and key in `` must correspond to the Conjur variable path.
## Related Pages
Overview of all secret providers
CyberArk Central Credential Provider
# CyberArk CCP
Source: https://docs.strata.io/reference/orchestrator/configuration/secret-providers/cyberark-ccp
The CyberArk CCP (Central Credential Provider) secret provider connects the Orchestrator to CyberArk Vault via the CCP REST API. CCP provides agentless credential retrieval, allowing the Orchestrator to fetch privileged credentials without requiring a local agent installation.
**Console terminology:** In the Maverics Console, Orchestrator instances and
configuration delivery are managed through **Deployments**. When working directly
with YAML, configuration is managed as files delivered via the `-config` flag or
`MAVERICS_CONFIG` environment variable.
## Overview
When configured with the CyberArk CCP provider, the Orchestrator authenticates to the CCP web service and retrieves credentials from the CyberArk Vault. CCP is the agentless component of CyberArk's Privileged Access Security solution -- it exposes a REST API that applications call to retrieve credentials without needing the CyberArk Application Identity Manager agent installed locally.
## Use Cases
* **Existing CyberArk deployments** -- retrieve Orchestrator secrets from an existing CyberArk Vault without duplicating credentials into another system
* **Agentless retrieval** -- fetch credentials via the CCP REST API without installing a CyberArk agent on the Orchestrator host
* **Separation of duties** -- CyberArk administrators manage credential policies and rotations; Orchestrator operators consume credentials via CCP
## Configuration
Secret providers are not configured in YAML. They are set via the `MAVERICS_SECRET_PROVIDER` environment variable or the `-secretProvider` CLI flag.
### Configuration via Environment Variable
```bash theme={null}
# Certificate file authentication
export MAVERICS_SECRET_PROVIDER="cyberarkccp://ccp.example.com?appID=MyApp&safe=MySafe&certFile=/path/to/cert.pem&keyFile=/path/to/key.pem"
# With optional CA certificate and folder
export MAVERICS_SECRET_PROVIDER="cyberarkccp://ccp.example.com?appID=MyApp&safe=MySafe&certFile=/path/to/cert.pem&keyFile=/path/to/key.pem&caFile=/path/to/ca.pem&folder=Root"
```
### Configuration via CLI Flag
```bash theme={null}
maverics -config maverics.yaml -secretProvider "cyberarkccp://ccp.example.com?appID=MyApp&safe=MySafe&certFile=/path/to/cert.pem&keyFile=/path/to/key.pem"
```
### Referencing Secrets in YAML
Once the secret provider is configured, reference secrets in your Orchestrator YAML configuration using angle bracket syntax. The key in the angle brackets maps to the account object name in the CyberArk Vault:
```yaml theme={null}
connectors:
- name: my-idp
oauthClientSecret:
```
## Configuration Reference
### URL Structure
```
cyberarkccp://{ccp-server-address}?appID={appID}&safe={safe}&certFile={certFile}&keyFile={keyFile}
```
### URL Parameters
| Parameter | Required | Description |
| --------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------- |
| Server address | Yes | Hostname of the CyberArk CCP web service (e.g., `ccp.example.com`) |
| `appID` | Yes | CyberArk Application ID configured in PVWA |
| `safe` | Yes | CyberArk Safe containing the credentials |
| `certFile` | Conditional | Path to client certificate file for CCP authentication. Required when not using Windows certificate store. |
| `keyFile` | Conditional | Path to client private key file. Required when `certFile` is provided. |
| `caFile` | No | Path to CA certificate file for verifying the CCP server |
| `folder` | No | Folder within the Safe to retrieve credentials from |
| `newLineDelim` | No | Delimiter string to replace with newline characters in secret values (useful for multi-line secrets like certificates) |
| `winCertThumbprint` | No | Windows certificate store thumbprint for client authentication (Windows only) |
| `winCertSubject` | No | Windows certificate store subject for client authentication (Windows only) |
| `winRootCAThumbprint` | No | Windows certificate store thumbprint for CA certificate (Windows only) |
| `winRootCASubject` | No | Windows certificate store subject for CA certificate (Windows only) |
### Authentication
CCP requires client certificate authentication. Provide certificates using one of two methods:
* **File-based certificates** -- set `certFile` and `keyFile` (and optionally `caFile`)
* **Windows certificate store** -- set `winCertThumbprint` or `winCertSubject` (and optionally `winRootCAThumbprint` or `winRootCASubject`)
The CCP web service must be configured in CyberArk to allow the Orchestrator
host to retrieve credentials. Ensure the appropriate Application ID and Safe
permissions are configured in the CyberArk PVWA (Password Vault Web Access).
## Troubleshooting
**"Unauthorized" or authentication errors**
Verify that the CyberArk Application ID is configured to allow access from the Orchestrator host's IP address or certificate. Check the CyberArk PVWA audit log for denied requests.
**"Connection refused" when starting the Orchestrator**
Confirm the CCP server address is correct and that the Orchestrator host has network access to the CCP REST API endpoint (typically port 443).
**Secrets not resolving in YAML configuration**
Ensure the angle bracket syntax matches the account names in the CyberArk Vault. The namespace and key in `` must correspond to the Safe and account object stored in CyberArk.
## Related Pages
Overview of all secret providers
DevOps-oriented secrets for CI/CD and containers
# Delinea Secret Server
Source: https://docs.strata.io/reference/orchestrator/configuration/secret-providers/delinea
The Delinea Secret Server secret provider connects the Orchestrator to [Delinea Secret Server](https://delinea.com/products/secret-server), a privileged access management (PAM) solution. Delinea Secret Server provides enterprise-grade credential vaulting, privileged session management, and audit-ready compliance reporting for sensitive access.
**Console terminology:** In the Maverics Console, Orchestrator instances and
configuration delivery are managed through **Deployments**. When working directly
with YAML, configuration is managed as files delivered via the `-config` flag or
`MAVERICS_CONFIG` environment variable.
## Overview
When configured with the Delinea Secret Server provider, the Orchestrator authenticates to your Delinea Secret Server instance and retrieves privileged credentials as needed. The provider supports the Delinea Secret Server REST API for retrieving secrets. Credentials are fetched at startup and cached for the duration of the Orchestrator process.
## Use Cases
* **Existing Delinea deployments** -- retrieve Orchestrator secrets from an existing Delinea Secret Server without duplicating credentials into another system
* **Organizational compliance** -- satisfy security policies that require all credentials to be sourced from the PAM platform
* **Centralized credential rotation** -- rotate secrets in Delinea and pick up new values on Orchestrator restart or config reload
## Configuration
Secret providers are not configured in YAML. They are set via the `MAVERICS_SECRET_PROVIDER` environment variable or the `-secretProvider` CLI flag.
### Configuration via Environment Variable
```bash theme={null}
export MAVERICS_SECRET_PROVIDER="delinea://server.example.com?username=svc-maverics&password=&folder=Maverics"
```
### Configuration via CLI Flag
```bash theme={null}
maverics -config maverics.yaml -secretProvider "delinea://server.example.com?username=svc-maverics&password=&folder=Maverics"
```
### Referencing Secrets in YAML
Once the secret provider is configured, reference secrets in your Orchestrator YAML configuration using angle bracket syntax. The reference uses the format `secretName.fieldSlug`, where `secretName` is the name of the secret in Delinea and `fieldSlug` is the template field slug:
```yaml theme={null}
connectors:
- name: my-idp
oauthClientSecret:
```
At startup, the provider authenticates to Delinea and pre-populates all secrets from the specified folder.
## Configuration Reference
### URL Structure
```
delinea://{server-address}?username={username}&password={password}&folder={folder}
```
### URL Parameters
| Parameter | Required | Description |
| -------------- | -------- | --------------------------------------------------------------------------- |
| Server address | Yes | Hostname of the Delinea Secret Server instance (e.g., `server.example.com`) |
| `username` | Yes | Delinea Secret Server username for authentication |
| `password` | Yes | Delinea Secret Server password for authentication |
| `folder` | Yes | Folder path in Delinea Secret Server containing the secrets to retrieve |
### Authentication
The provider authenticates to Delinea Secret Server using the OAuth 2.0 password grant with the provided `username` and `password`.
## Troubleshooting
**"Unauthorized" or authentication errors**
Verify that the Delinea credentials configured on the host are valid and have permission to access the required secrets. Check the Delinea Secret Server audit log for denied requests.
**"Connection refused" when starting the Orchestrator**
Confirm the Delinea Secret Server address is correct and that the Orchestrator host has network access to the Delinea REST API endpoint.
**Secrets not resolving in YAML configuration**
Ensure the angle bracket syntax matches the secret names in Delinea Secret Server. The namespace and key in `` must correspond to the secret path and field stored in Delinea.
## Related Pages
Overview of all secret providers
External vault for secrets management
# Secret File
Source: https://docs.strata.io/reference/orchestrator/configuration/secret-providers/environment
The Secret File provider reads secrets from a local YAML file on disk. This is the simplest secret provider and is useful for development and testing where an external secret management system is not available.
**Console terminology:** In the Maverics Console, Orchestrator instances and
configuration delivery are managed through **Deployments**. When working directly
with YAML, configuration is managed as files delivered via the `-config` flag or
`MAVERICS_CONFIG` environment variable.
## Overview
When configured with the Secret File provider, the Orchestrator reads secret values from a YAML file at startup. Each key in the file maps to a secret that can be referenced in the Orchestrator configuration using angle bracket syntax. The file is read once at startup -- changes to the file require restarting the Orchestrator.
The Secret File provider stores secrets in plaintext on disk. Use it only for
local development and testing. For production deployments, use a dedicated
secret management system like
[HashiCorp Vault](/reference/orchestrator/configuration/secret-providers/hashicorp-vault),
[AWS Secrets Manager](/reference/orchestrator/configuration/secret-providers/aws-secrets-manager),
or [Azure Key Vault](/reference/orchestrator/configuration/secret-providers/azure-key-vault).
## Use Cases
* **Local development** -- use a secrets file during development without requiring an external vault or cloud credentials
* **Testing and CI/CD** -- provide test secrets via a file for automated test runs
* **Quick prototyping** -- get started with the Orchestrator quickly before configuring a production secret provider
## Configuration
Secret providers are not configured in YAML. They are set via the `MAVERICS_SECRET_PROVIDER` environment variable or the `-secretProvider` CLI flag.
### Configuration via Environment Variable
```bash theme={null}
export MAVERICS_SECRET_PROVIDER="secretfile:////path/to/secrets.yaml"
```
The `secretfile://` URL uses four forward slashes for an absolute path:
`secretfile://` (scheme) + `//path/to/file` (absolute path). For example,
`secretfile:////etc/maverics/secrets.yaml`. This is because the Orchestrator
trims a leading `/` from the parsed path, so the extra slash ensures the
absolute path is preserved.
### Configuration via CLI Flag
```bash theme={null}
maverics -config maverics.yaml -secretProvider "secretfile:////path/to/secrets.yaml"
```
### Secrets File Format
The secrets file is a YAML file with a top-level `secrets` key containing flat key-value pairs:
```yaml theme={null}
# secrets.yaml
secrets:
azureClientSecret: "my-client-secret-value"
oktaClientSecret: "another-secret-value"
tlsPrivateKey: |
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA...
-----END RSA PRIVATE KEY-----
```
### Referencing Secrets in YAML
Once the secret provider is configured, reference secrets in your Orchestrator YAML configuration using angle bracket syntax. The key in the angle brackets maps directly to the key name under the `secrets` key in the file:
```yaml theme={null}
connectors:
- name: azure
oauthClientSecret:
- name: okta
oauthClientSecret:
```
## Configuration Reference
### URL Structure
```
secretfile://{absolute-path-to-file}
Example: `secretfile:////etc/maverics/secrets.yaml`
```
### URL Parameters
| Parameter | Required | Description |
| --------- | -------- | --------------------------------------------------------------------------- |
| File path | Yes | Absolute path to the YAML secrets file (e.g., `/etc/maverics/secrets.yaml`) |
## Troubleshooting
**"file not found" when starting the Orchestrator**
Verify the file path is correct and uses an absolute path. The `secretfile://` URL requires four forward slashes for absolute paths (e.g., `secretfile:////etc/maverics/secrets.yaml`). Using only three slashes causes the leading `/` to be stripped, resulting in a relative path.
**Secrets not resolving in YAML configuration**
Ensure the angle bracket syntax matches the key names under the `secrets` key in the file. The key in `` must match exactly.
**Permission denied reading the secrets file**
Ensure the Orchestrator process has read access to the secrets file. Check file permissions with `ls -la /path/to/secrets.yaml`.
## Related Pages
Overview of all secret providers
Enterprise secret management for production
# HashiCorp Vault
Source: https://docs.strata.io/reference/orchestrator/configuration/secret-providers/hashicorp-vault
The HashiCorp Vault secret provider connects the Orchestrator to a Vault server for centralized secrets management. Vault provides encrypted storage, dynamic secret generation, and a comprehensive audit trail for all secret access.
**Console terminology:** In the Maverics Console, Orchestrator instances and
configuration delivery are managed through **Deployments**. When working directly
with YAML, configuration is managed as files delivered via the `-config` flag or
`MAVERICS_CONFIG` environment variable.
## Overview
When configured with the HashiCorp Vault provider, the Orchestrator authenticates to Vault at startup and retrieves secrets on demand as they are referenced in configuration. The provider supports multiple authentication methods including token-based, AppRole (for machine-to-machine), and TLS certificate authentication. Secrets are read from Vault's KV secrets engine using configurable mount paths and secret paths.
## Use Cases
* **Existing Vault deployments** -- retrieve Orchestrator secrets from an existing Vault instance without duplicating credentials into another system
* **Audit trail** -- every secret access is logged in Vault's audit log for compliance and troubleshooting
* **Centralized credential rotation** -- rotate secrets in Vault and pick up new values on Orchestrator restart or config reload
## Configuration
Secret providers are not configured in YAML. They are set via the `MAVERICS_SECRET_PROVIDER` environment variable or the `-secretProvider` CLI flag.
### Configuration via Environment Variable
```bash theme={null}
# Token authentication (HTTPS by default)
export MAVERICS_SECRET_PROVIDER="hashivault://vault.example.com:8200/secret/data/maverics?token="
# AppRole authentication
export MAVERICS_SECRET_PROVIDER="hashivault://vault.example.com:8200/secret/data/maverics?role_id=&secret_id="
# TLS certificate authentication
export MAVERICS_SECRET_PROVIDER="hashivault://vault.example.com:8200/secret/data/maverics?client_cert=/path/to/cert&client_key=/path/to/key&cert_name="
# With Vault namespace (for Vault Enterprise)
export MAVERICS_SECRET_PROVIDER="hashivault://vault.example.com:8200/secret/data/maverics?token=&namespace=my-namespace"
# Explicit HTTP connection (for development only)
export MAVERICS_SECRET_PROVIDER="hashivault+http://vault.example.com:8200/secret/data/maverics?token="
```
### Configuration via CLI Flag
```bash theme={null}
maverics -config maverics.yaml -secretProvider "hashivault://vault.example.com:8200/secret/data/maverics?token="
```
Both `hashivault://` and `hashivaults://` connect over HTTPS by default. To
connect over plain HTTP (for development only), use `hashivault+http://`.
### Referencing Secrets in YAML
Once the secret provider is configured, reference secrets in your Orchestrator YAML configuration using angle bracket syntax:
```yaml theme={null}
connectors:
- name: my-idp
oauthClientSecret:
apps:
- name: my-app
tls:
keyFile:
```
The namespace (`maverics`) maps to the secret path configured in the URL, and the key (`client_secret`) maps to the key within that secret.
## Configuration Reference
### URL Structure
```
hashivault://{host}:{port}/{engine-path}/{secret-path}?{parameters}
```
Supported schemes: `hashivault://` (HTTPS), `hashivaults://` (HTTPS),
`hashivault+https://` (HTTPS), `hashivault+http://` (HTTP).
### URL Parameters
| Parameter | Required | Description |
| ------------------------ | ----------- | ------------------------------------------------------------------------ |
| URL host + port | Yes | Vault server address (e.g., `vault.example.com:8200`) |
| URL path | Yes | Secret engine mount path and secret path (e.g., `/secret/data/maverics`) |
| `token` | Conditional | Vault token for token authentication |
| `role_id` | Conditional | AppRole role ID (requires `secret_id`) |
| `secret_id` | Conditional | AppRole secret ID (requires `role_id`) |
| `namespace` | No | Vault Enterprise namespace |
| `ca_cert` | No | Path to CA certificate file for Vault TLS verification |
| `client_cert` | No | Path to client certificate for mutual TLS |
| `client_key` | No | Path to client key for mutual TLS |
| `cert_name` | No | Certificate name for TLS cert authentication |
| `win_cert_thumbprint` | No | Windows certificate store thumbprint |
| `win_cert_subject` | No | Windows certificate store subject |
| `win_root_ca_thumbprint` | No | Windows root CA thumbprint |
| `win_root_ca_subject` | No | Windows root CA subject |
Provide **one** of the following authentication methods: `token`, `role_id` +
`secret_id`, or `client_cert` + `client_key` + `cert_name`. AppRole is
recommended for production machine-to-machine authentication.
## Troubleshooting
**"permission denied" errors from Vault**
Verify that the token or AppRole credentials have a Vault policy granting `read` access to the configured secret path. Check the Vault audit log for the denied request.
**"connection refused" when starting the Orchestrator**
Confirm the Vault server address and port are correct. If using `hashivaults://`, ensure the Vault server has TLS enabled and the CA certificate is trusted (use `ca_cert` if needed).
**Secrets not resolving in YAML configuration**
Ensure the angle bracket syntax matches the key names stored in Vault. The namespace in `` must match the path segment in the secret provider URL, and the key must exist in that Vault secret.
## Related Pages
Overview of all secret providers
Cloud-native secrets for AWS deployments
# Client ID Metadata Documents
Source: https://docs.strata.io/reference/orchestrator/experimental/client-id-metadata-documents
Client ID Metadata Documents are an experimental feature -- see [Experimental Features](/reference/orchestrator/experimental/overview) for important caveats.
Traditional OAuth requires every client to be registered ahead of time -- an operator creates a `clientID`, issues credentials, and records redirect URIs before the client can authenticate. This works for a fixed set of applications, but breaks down for the growing population of AI agents and MCP clients that appear dynamically and cannot be pre-provisioned.
Client ID Metadata Documents (CIMD) solve this by letting a client identify itself with an `https` URL instead of a pre-registered ID. The client's `client_id` **is** a URL that serves a JSON metadata document describing the client. When the Orchestrator receives an authorization request from an unknown URL `client_id`, it fetches that document, validates it, caches it, and builds a client from it on the fly -- no manual registration required. This implements [draft-ietf-oauth-client-id-metadata-document](https://datatracker.ietf.org/doc/draft-ietf-oauth-client-id-metadata-document/).
CIMD is the mechanism modern AI agents use to authenticate. For example, [Claude Code](/guides/ai-identity/connect/claude) presents its published metadata URL as its `client_id` and requests no scope -- the Orchestrator resolves it to a public client and issues tokens without any per-client setup. See the [AI Identity Gateway](/reference/modes/ai-identity-gateway) and [MCP Proxy](/guides/ai-identity/mcp-proxy) guides for related patterns.
This page covers the Orchestrator as the **authorization server**, accepting CIMD clients that present a URL `client_id`. The Orchestrator can also act as a **CIMD client** in the other direction -- the [Generic OAuth](/reference/orchestrator/identity-fabric/oauth#client-id-metadata-document) connector publishes its own metadata document and presents that URL as its `client_id` to an upstream authorization server.
## How it works
An operator enables CIMD by adding one or more `oidcCimd` apps to an Orchestrator that already runs an OIDC Provider (the top-level `oidcProvider` configuration). Each app is a **domain-scoped policy**: it lists the domains whose metadata URLs it will resolve, and the authentication, authorization, and token settings to apply to clients from those domains.
```mermaid theme={null}
sequenceDiagram
participant Client as CIMD Client
participant Orch as Orchestrator (OIDC Provider)
participant Doc as client_id URL
Client->>Orch: authorize (client_id=https://app.example.com/oauth-client)
Orch->>Orch: match host against oidcCimd allowedDomains
Orch->>Doc: GET metadata document (SSRF-safe, no redirects)
Doc-->>Orch: JSON metadata (redirect_uris, grant_types, ...)
Orch->>Orch: validate + cache metadata, build client
Orch->>Client: run authorization code + PKCE flow
Client->>Orch: token request
Orch-->>Client: access token (+ refresh token)
```
Once resolved, a CIMD client behaves like any other public or confidential OIDC client: it completes the authorization code flow (with PKCE) and receives tokens signed by the OIDC Provider. Resolved metadata is cached so subsequent requests from the same client skip the fetch.
## The metadata document
The document served at the `client_id` URL is a JSON object using the client metadata fields defined by [OAuth Dynamic Client Registration (RFC 7591)](https://datatracker.ietf.org/doc/html/rfc7591#section-2) and profiled by [draft-ietf-oauth-client-id-metadata-document](https://datatracker.ietf.org/doc/draft-ietf-oauth-client-id-metadata-document/). Refer to those specifications for the full field registry and semantics.
The Orchestrator reads a subset of those fields -- `client_id`, `redirect_uris`, `grant_types`, `response_types`, `token_endpoint_auth_method`, `jwks_uri`, `scope`, and `client_name` -- and applies the constraints described in [Client requirements](#client-requirements) below.
A minimal metadata document for a public client looks like:
```json theme={null}
{
"client_id": "https://app.example.com/oauth-client",
"client_name": "Example Agent",
"redirect_uris": ["https://app.example.com/callback"],
"grant_types": ["authorization_code", "refresh_token"],
"response_types": ["code"],
"token_endpoint_auth_method": "none"
}
```
## Client requirements
The Orchestrator enforces the following rules. A metadata document that violates any of them makes the client unresolvable, and the authorization request is rejected as an invalid client.
**`client_id` URL** -- must use the `https` scheme, include a path, and must not contain dot-segments (`.` / `..`), a fragment, userinfo, or a query string. The host must match one of the configured `allowedDomains`.
**`redirect_uris`** -- at least one is required. Each must use `https`, except that `http` is permitted for loopback hosts (`localhost`, `127.0.0.1`, `::1`) per [RFC 8252](https://datatracker.ietf.org/doc/html/rfc8252). Loopback redirects may use any port.
**`grant_types`** -- only `authorization_code` and `refresh_token` are supported, and the field defaults to `authorization_code` when omitted. Declaring `refresh_token` requires `authorization_code` as well. Implicit, hybrid, client credentials, and other grants are rejected.
**`response_types`** -- only `code` (authorization code flow) is supported, and the field defaults to `code` when omitted.
**`token_endpoint_auth_method`** -- defaults to `none` when omitted:
* `none` -- the client is **public** and MUST use PKCE.
* `private_key_jwt` -- the client is **confidential**; its `jwks_uri` must be an `https` URL sharing the same origin (scheme + host + port) as the `client_id`. The Orchestrator fetches the JWKS to verify the client's signed authentication assertions.
**`scope`** -- optional. When present, requestable scopes are restricted to this set; when omitted, scopes are unrestricted (like a static client).
Declaring `refresh_token` in a client's `grant_types` does **not** automatically issue a refresh token. The operator must explicitly enable refresh token issuance via `refreshToken.allowOfflineAccess` in the CIMD app configuration. See [Refresh tokens](#refresh-tokens) below.
## Configuration
CIMD is configured as one or more apps of type `oidcCimd` alongside the top-level `oidcProvider` configuration. Each `oidcCimd` app registers a single domain-scoped policy.
| Field | Type | Required | Description |
| -------------------------- | ----------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `allowedDomains` | string\[] | yes | Domains whose metadata URLs this policy resolves. Each entry is an exact hostname (`app.example.com`) or a wildcard prefix (`*.example.com`). A wildcard is only valid as the leftmost label. |
| `authentication` | object | yes | How users are authenticated -- an `idps` list, or `isAuthenticatedSE` + `authenticateSE` service extensions. Same shape as an `oidc` app. |
| `authorization` | object | no | Authorization policy applied to resolved clients. Defaults to allow-all. |
| `allowedAudiences` | string\[] | no | Audiences CIMD clients may request in access tokens. |
| `claimsMapping` | map | no | Maps user attributes to token claims, namespaced by connector (e.g. `email: azure.email`). |
| `accessToken` | object | no | Access token `type` (`jwt` / `opaque`), `length`, and `lifetimeSeconds`. |
| `refreshToken` | object | no | Refresh token settings. See [Refresh tokens](#refresh-tokens) for field details. |
| `attrProviders` | object\[] | no | Connectors used to load attributes for resolved clients. |
| `loadAttrsSE` | service extension | no | Customizes attribute loading. |
| `buildIDTokenClaimsSE` | service extension | no | Adds custom claims to the ID token. |
| `buildAccessTokenClaimsSE` | service extension | no | Adds custom claims to the access token. |
### Refresh tokens
Refresh tokens are long-lived credentials, so OIDC CIMD apps do not issue them by default. An operator must explicitly opt each CIMD app in, ensuring that persistent offline access is a deliberate policy decision rather than a consequence of client metadata.
The `refreshToken` object supports the following fields:
| Field | Type | Required | Description |
| -------------------- | ---- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `allowOfflineAccess` | bool | no | When `true`, permits clients to receive a refresh token. The client must request the `offline_access` scope in the authorization request. Defaults to `false`. |
| `autoGrant` | bool | no | When `true`, the Orchestrator automatically injects the `offline_access` scope for clients that do not request it. Requires `allowOfflineAccess: true`. Use for clients like Claude Code that omit scopes entirely but still need refresh tokens. Defaults to `false`. |
| `length` | int | no | Length of the refresh token in characters (22–256). |
| `lifetimeSeconds` | int | no | How long a refresh token is valid. |
### Example
An OIDC Provider with a single CIMD policy that resolves any client under `*.example.com` and authenticates users against an Azure connector:
```yaml maverics.yaml theme={null}
# The OIDC Provider is configured under the top-level `oidcProvider` key.
oidcProvider:
discovery:
issuer: https://sso.company.com
endpoints:
wellKnown: /.well-known/openid-configuration
auth: /oauth2/authorize
token: /oauth2/token
jwks: /oauth2/jwks
userinfo: /oauth2/userinfo
jwks:
- algorithm: RSA256
privateKey:
# CIMD policies are registered as apps of type `oidcCimd`.
apps:
- name: partner-agents
type: oidcCimd
# Resolve CIMD client_id URLs under these domains.
allowedDomains:
- "*.example.com"
authentication:
idps:
- azure
allowedAudiences:
- "https://api.company.com"
accessToken:
type: jwt
lifetimeSeconds: 3600
refreshToken:
allowOfflineAccess: true
lifetimeSeconds: 2592000
```
### Multiple policies
You can register several `oidcCimd` apps to apply different templates to different domains. When more than one policy could match a host, the **most specific** domain pattern wins: an exact hostname outranks any wildcard, and a wildcard with more labels outranks one with fewer. Exact-duplicate domain strings across policies are rejected at startup.
```yaml maverics.yaml theme={null}
apps:
# Broad policy for all partner subdomains.
- name: partner-agents
type: oidcCimd
allowedDomains:
- "*.example.com"
authentication:
idps:
- azure
# More specific policy that wins for this exact host, with stricter settings.
- name: privileged-agent
type: oidcCimd
allowedDomains:
- "agent.example.com"
authentication:
idps:
- azure
# Stricter authorization: only members of the privileged group may use this client.
authorization:
rules:
- and:
- contains: ["{{ azure.groups }}", "privileged-agents"]
accessToken:
lifetimeSeconds: 300
```
## Security and caching
Because the Orchestrator fetches a client-supplied URL, CIMD metadata retrieval is hardened against server-side request forgery (SSRF):
* **Special-use IP blocking** -- resolved IPs are checked against [RFC 6890](https://datatracker.ietf.org/doc/html/rfc6890) special-use ranges (loopback, private, link-local, etc.) and rejected. The connection is made to the validated IP to prevent DNS rebinding.
* **No redirects** -- the metadata fetch does not follow HTTP redirects.
* **Bounded requests** -- a 5-second timeout and a \~5 KB response size cap, and the response must be `application/json`.
* **Domain allowlist** -- only hosts matching a policy's `allowedDomains` are fetched at all.
Resolved metadata is cached to avoid re-fetching on every request:
* The cache TTL is derived from the response's `Cache-Control: max-age`, clamped to a minimum of **5 minutes** and a maximum of **24 hours**.
* Up to **1000** metadata documents are cached per policy.
* When a cached document is refreshed and a security-relevant field changes (`token_endpoint_auth_method`, `jwks_uri`, or `redirect_uris`), the change is logged.
## Discovery
When at least one `oidcCimd` policy is registered, the OIDC Provider advertises CIMD support in its discovery (well-known) document:
* `client_id_metadata_document_supported` is set to `true`.
* `token_endpoint_auth_methods_supported` gains `none` and `private_key_jwt` (the methods CIMD honors) alongside the static `client_secret_post`.
With no CIMD policies configured, the discovery document is unchanged and `client_id_metadata_document_supported` is `false`.
## Examples
The following `oidcCimd` app configurations allow common AI clients to authenticate using CIMD without pre-registering a client ID. In each case, the client presents an `https` URL as its `client_id`; the Orchestrator matches the host against `allowedDomains`, fetches the metadata document, and completes the authorization code flow automatically.
Both Claude Code and Claude Desktop present a metadata URL on `claude.ai` as the `client_id`. A single `oidcCimd` policy covers both.
```yaml maverics.yaml theme={null}
apps:
- name: claude
type: oidcCimd
allowedDomains:
- claude.ai
authentication:
idps:
- upstream-idp
accessToken:
type: jwt
lifetimeSeconds: 3600
refreshToken:
allowOfflineAccess: true
# autoGrant injects offline_access automatically because Claude Code
# does not request scopes explicitly.
autoGrant: true
lifetimeSeconds: 86400
claimsMapping:
email: upstream-idp.email
name: upstream-idp.name
sub: upstream-idp.sub
```
When Claude Desktop connects via [`mcp-remote`](https://github.com/geelen/mcp-remote) as a local stdio proxy, CIMD does not apply — the client ID is a plain string, not a URL, and must be registered as a standard OIDC app. See [Connect Claude to the Gateway](/guides/ai-identity/connect/claude) for mcp-remote configuration.
ChatGPT presents a metadata URL on `chatgpt.com` as its `client_id`.
```yaml maverics.yaml theme={null}
apps:
- name: chatgpt
type: oidcCimd
allowedDomains:
- chatgpt.com
authentication:
idps:
- upstream-idp
accessToken:
type: jwt
lifetimeSeconds: 3600
refreshToken:
allowOfflineAccess: true
lifetimeSeconds: 86400
claimsMapping:
email: upstream-idp.email
name: upstream-idp.name
sub: upstream-idp.sub
```
Verify the actual `client_id` URL ChatGPT presents during the authorization
flow — the host determines which `allowedDomains` entry applies. If the host
differs from `chatgpt.com` (for example, `openai.com`), update `allowedDomains`
accordingly. You can find the `client_id` in the Orchestrator's authorization
logs on the first connection attempt.
***
## Related Pages
Overview of all experimental features and important caveats
Configure the Orchestrator as an OIDC authorization server
Secure AI agent-to-tool communication via MCP
Connect Claude Code and other Anthropic clients
Present a CIMD client ID to an upstream authorization server
# FIPS 140-3 Builds
Source: https://docs.strata.io/reference/orchestrator/experimental/fips
FIPS 140-3 builds are an experimental feature -- see [Experimental Features](/reference/orchestrator/experimental/overview) for important caveats.
## Overview
FIPS 140-3 (Federal Information Processing Standard 140-3) is a cryptographic module validation standard published by NIST (National Institute of Standards and Technology). It certifies that a software module's cryptographic implementations -- encryption algorithms, key generation, hashing, and random number generation -- meet federal security requirements for protecting sensitive information. FIPS 140-3 is the current version of the standard, superseding FIPS 140-2.
The Maverics Orchestrator will offer FIPS-compliant builds that use a FIPS 140-3 validated cryptographic module, ensuring that all cryptographic operations meet federal standards.
## Current Status
The cryptographic module used by the Maverics Orchestrator is currently under review by NIST CMVP for FIPS 140-3 validation. FIPS-compliant builds are expected to be available in 2026.
## Who Needs FIPS 140-3
FIPS 140-3 compliant cryptography is typically required by:
* **Federal and government agencies** -- Required by FISMA (Federal Information Security Modernization Act) for all federal information systems
* **Defense contractors** -- Organizations handling classified or sensitive government data under contracts that mandate FIPS-validated cryptographic modules
* **Healthcare organizations** -- Those handling CUI (Controlled Unclassified Information) under NIST SP 800-171 requirements
* **Financial institutions** -- Organizations with specific regulatory requirements mandating FIPS-validated cryptography for data protection
## Feature Parity
FIPS-compliant builds of the Orchestrator have a reduced feature set compared to standard builds. Certain features may be unavailable or limited because FIPS compliance restricts the Orchestrator to using only the validated module's approved cryptographic algorithms. Features that depend on non-FIPS-validated cryptographic operations are excluded from FIPS-compliant builds.
## Recommendation
Unless your organization specifically requires FIPS 140-3 compliant cryptography, use the standard Orchestrator builds for the most complete feature set. The standard builds include the same security best practices -- TLS encryption, secure key management, and strong cryptographic defaults -- without the algorithm restrictions imposed by FIPS compliance requirements.
## Contact
If you need FIPS-compliant builds or have questions about compliance requirements, contact your Strata account representative or reach out to [sales@strata.io](mailto:sales@strata.io).
## Related Pages
Overview of all experimental features and important caveats
Compliance frameworks and audit logging
Orchestrator installation and build options
# Experimental Features
Source: https://docs.strata.io/reference/orchestrator/experimental/overview
Experimental features are **not production-ready** and are **not covered by Strata support**. Do **not** contact Strata support for issues with experimental features.
This section documents Orchestrator features currently in experimental status. These features are made available for evaluation and testing purposes only.
## Important Caveats
* **No support** -- Experimental features are not covered by any Strata support agreement. Do not open support tickets for experimental feature issues.
* **Subject to removal** -- Experimental features can be removed from the product at any time without prior notice.
* **Subject to change** -- Experimental features can be changed in breaking ways at any time without prior notice or migration path.
* **No timeline** -- There is no timeline or commitment for when (or if) experimental features will reach general availability.
* **No guarantees** -- Strata makes no commitments regarding the stability, completeness, or future availability of experimental features.
## Experimental Features
* **[Client ID Metadata Documents](/reference/orchestrator/experimental/client-id-metadata-documents)** -- Let OAuth clients (such as AI agents and MCP clients) authenticate with an `https` URL `client_id` instead of a pre-registered client, resolving client metadata dynamically.
* **[FIPS 140-3 Builds](/reference/orchestrator/experimental/fips)** -- Orchestrator builds using a FIPS 140-3 validated cryptographic module.
* **[Token Brokering](/reference/orchestrator/experimental/token-brokering)** -- RFC 8693 token exchange that lets the Orchestrator acquire upstream tokens on behalf of clients.
## Providing Feedback
If you have feedback on experimental features, contact your Strata account representative or reach out to [sales@strata.io](mailto:sales@strata.io).
# Token Brokering
Source: https://docs.strata.io/reference/orchestrator/experimental/token-brokering
Token brokering is an experimental feature -- see [Experimental Features](/reference/orchestrator/experimental/overview) for important caveats.
Modern applications often need tokens from multiple services -- a GitHub token for repository access, a Databricks token for compute, a GCP token for cloud resources. Without token brokering, each client must independently manage credentials and token lifecycles for every upstream service, spreading sensitive token logic across the application landscape.
Token brokering solves this by letting the Orchestrator act as a single token endpoint. Clients exchange their Maverics access token for upstream tokens using standard [RFC 8693](https://datatracker.ietf.org/doc/html/rfc8693) token exchange, and the Orchestrator handles acquiring the right token from each upstream service. The Orchestrator determines how to fulfill each request based on the `tokenBrokering` configuration on the OIDC app.
The [AI Identity Gateway](/guides/ai-identity/overview) can act as the token exchange client, brokering tokens on behalf of AI agents. This pattern ensures agents never receive third-party access tokens directly -- the gateway makes a just-in-time token exchange and injects the upstream tokens into outbound requests.
## Flows
Token brokering supports three flows, determined by the mapping's `type` field and whether a `tokenSource` is set.
| Type | tokenSource | Flow | Description |
| ------------- | ----------- | ------------------- | ------------------------------------------------------------- |
| `passthrough` | required | Session Passthrough | Return an upstream token from the user's session |
| `exchange` | omitted | Federated Exchange | Orchestrator mints a JWT and exchanges it with an upstream AS |
| `exchange` | set | Brokered Exchange | Forward the user's IdP token to an upstream AS for exchange |
### Session Passthrough
The simplest flow. The user authenticated to an upstream IdP during login, and the Orchestrator cached their access token in the session. When the client requests a token for that audience, the Orchestrator returns the cached token directly.
The Orchestrator will refresh the cached access token when needed, using the refresh token returned during the initial login. This requires the upstream IdP connector to request the `offline_access` scope so the AS includes a refresh token in the login response.
```mermaid theme={null}
sequenceDiagram
participant Client
participant Orch as Orch AS
participant Upstream as Upstream IdP
Client->>Orch: token exchange (audience=atlassian)
Orch->>Orch: lookup session token for "atlassian" IdP
opt token needs refresh
Orch->>Upstream: refresh token grant
Upstream-->>Orch: new access token + refresh token
Orch->>Orch: update session cache
end
Orch-->>Client: upstream access token
```
**Trust model:** The upstream IdP issued the token to the user during an interactive OAuth consent flow. The Orchestrator returns it from cache -- the upstream doesn't know the Orchestrator exists.
**When to use:** The upstream service accepts standard OAuth tokens but does not support RFC 8693 token exchange. The user must have authenticated to the upstream IdP during their session.
**Examples:** GitHub OAuth Apps, Atlassian 3LO, Google Workspace APIs (Drive, Calendar).
### Federated Exchange
The Orchestrator mints a short-lived JWT (signed with its own key) and exchanges it with the upstream authorization server via RFC 8693. The upstream AS trusts the Orchestrator as an IdP through a federation policy that validates the JWT signature via the Orchestrator's OIDC discovery/JWKS endpoints.
```mermaid theme={null}
sequenceDiagram
participant Client
participant Orch as Orch AS
participant Upstream as Upstream AS
Client->>Orch: token exchange (audience=databricks)
Orch->>Orch: mint JWT (iss=orch)
Orch->>Upstream: token exchange (subject_token=JWT, type=jwt)
Upstream-->>Orch: upstream access token
Orch-->>Client: upstream access token
```
**Trust model:** The upstream AS trusts the Orchestrator's issuer. A federation policy on the upstream maps the Orchestrator's JWT claims to an upstream identity.
**When to use:** The upstream supports RFC 8693 token exchange with external JWTs. No user interaction with the upstream is required -- the trust is configured between the Orchestrator and the upstream AS.
**Examples:** Databricks Workload Identity Federation, GCP Workload Identity Federation.
### Brokered Exchange
The Orchestrator retrieves the user's IdP token from the session (like Session Passthrough) and then uses it as the `subject_token` in an RFC 8693 exchange with the upstream AS (like Federated Exchange). The upstream AS trusts the customer's IdP directly -- the Orchestrator is not in the trust chain.
```mermaid theme={null}
sequenceDiagram
participant Client
participant Orch as Orch AS
participant Upstream as Upstream AS
Client->>Orch: token exchange (audience=gcp)
Orch->>Orch: lookup session token for "okta" IdP
Orch->>Upstream: token exchange (subject_token=okta_jwt, type=jwt)
Upstream-->>Orch: upstream access token
Orch-->>Client: upstream access token
```
**Trust model:** The upstream AS trusts the customer's IdP (e.g., Okta, Entra) directly. The Orchestrator is invisible to the upstream -- it forwards the customer's IdP token.
**When to use:** The upstream supports RFC 8693 with external JWTs, and the customer's IdP is already configured as a trusted issuer on the upstream. This avoids adding the Orchestrator to the trust chain.
**Examples:** GCP Workload Identity Federation with Okta/Entra as the trusted issuer, Databricks federation with a customer's IdP.
## Client Request Format
From the client's perspective, token brokering is transparent -- it uses standard RFC 8693 token exchange against the Orchestrator's token endpoint with an `audience` parameter.
```
POST /oauth2/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&client_id=my-client
&client_secret=
&subject_token=
&subject_token_type=urn:ietf:params:oauth:token-type:access_token
&audience=https://api.github.com
&scope=read:user repo
```
The response follows the standard token exchange format:
```json theme={null}
{
"access_token": "",
"issued_token_type": "urn:ietf:params:oauth:token-type:access_token",
"token_type": "Bearer",
"expires_in": 3600
}
```
## Configuration
Token brokering is configured on an OIDC app under the `tokenBrokering` field. Each mapping associates an audience with a brokering action.
### Mapping Fields
| Field | Type | Required | Description |
| ----------------------------- | ------ | ----------- | ------------------------------------------------------------------------------------------------------ |
| `audience` | string | yes | The audience value that triggers this mapping. Must also be listed in the client's `allowedAudiences`. |
| `type` | string | yes | The brokering flow: `passthrough` or `exchange`. |
| `passthrough` | object | conditional | Required when type is `passthrough`. |
| `passthrough.tokenSource.idp` | string | yes | The IdP whose access token is stored in the user's session. |
| `exchange` | object | conditional | Required when type is `exchange`. |
| `exchange.idp` | string | yes | The upstream IdP/AS to exchange with. |
| `exchange.type` | string | no | Token exchange semantics: `delegation` or `impersonation`. Defaults to `delegation`. |
| `exchange.scope` | string | no | Scope to request from the upstream AS. If omitted, client-requested scopes pass through. |
| `exchange.tokenSource.idp` | string | no | The IdP whose session token to use as the subject. If omitted, the Orchestrator mints its own JWT. |
### Session Passthrough Example
The user authenticates to Atlassian during login. The client exchanges its Maverics token for the user's Atlassian access token. The connector includes `offline_access` so the Orchestrator receives a refresh token and can renew the cached token when needed.
```yaml maverics.yaml theme={null}
apps:
- name: ai-identity-gateway
type: oidc
clientID: ai-identity-gateway
clientSecret:
grantTypes:
- urn:ietf:params:oauth:grant-type:token-exchange
authentication:
idps:
- atlassian
accessToken:
type: jwt
allowedAudiences:
- "https://api.atlassian.com"
tokenBrokering:
mappings:
- audience: "https://api.atlassian.com"
type: passthrough
passthrough:
tokenSource:
idp: "atlassian"
connectors:
- name: atlassian
type: oauth
clientID:
clientSecret:
wellKnownURL: https://auth.atlassian.com/.well-known/openid-configuration
scopes: read:jira-work offline_access
```
## Authorization
Token brokering integrates with the existing token exchange authorization pipeline. Before any brokering action is taken, the Orchestrator:
1. Validates client-requested scopes against the client's `customScopes` configuration.
2. Evaluates OPA token minting policies configured on the client's `authorization.tokenMinting.accessToken.policies`.
3. Only if authorized, proceeds with the brokering action.
OPA policies remain the single control point for authorization decisions regardless of the brokering flow.
## Prerequisites
### For Passthrough
* The `passthrough.tokenSource.idp` must reference a configured connector.
* The user must complete an interactive OAuth login flow with that IdP during their session so the access token is cached.
* The connector must include `offline_access` in its `scopes` configuration. The Orchestrator uses the refresh token returned during login to renew the cached access token when needed. Without `offline_access`, the upstream AS does not issue a refresh token and expired tokens cannot be renewed.
### For Exchange (without tokenSource)
* The Orchestrator's OIDC well-known endpoint and JWKS must be publicly reachable so the upstream AS can validate the minted JWT's signature.
* The upstream AS must have a federation policy that trusts the Orchestrator's issuer and maps its JWT claims to an upstream identity.
* The `exchange.idp` must reference a configured connector that supports RFC 8693 token exchange.
* A pure machine-to-machine client (one whose `grantTypes` are limited to `client_credentials` and/or `urn:ietf:params:oauth:grant-type:token-exchange`) may omit the `authentication` block entirely.
### For Exchange (with tokenSource)
* The `exchange.tokenSource.idp` must reference a configured connector, and the user must have authenticated to it during their session.
* The tokenSource IdP's access token must be a JWT (the upstream validates it via that IdP's OIDC discovery/JWKS).
* The upstream AS must have a federation policy that trusts the tokenSource IdP's issuer directly.
* The `exchange.idp` must reference a configured connector that supports RFC 8693 token exchange.
## Related Pages
Overview of all experimental features and important caveats
Configure the Orchestrator as an OIDC Provider
OPA authorization policies for token minting
# Identity Fabric
Source: https://docs.strata.io/reference/orchestrator/identity-fabric
Every organization has an identity fabric -- it's the collection of identity providers, directories, and authentication systems that together determine who can access what. For most enterprises, this fabric is not a single system. It's Entra ID for cloud apps, Active Directory for on-prem resources, an LDAP directory for legacy systems, maybe Okta or PingFederate from an acquisition. Different protocols, different vendors, different eras of technology -- all serving the same fundamental purpose.
The Maverics Orchestrator connects to your identity fabric through **connectors**. Each connector integrates with one identity provider or attribute source, abstracting the protocol details (OIDC, SAML, LDAP) behind a uniform interface. This means the Orchestrator can authenticate users against any provider, pull attributes from any directory, and translate between protocols -- without your applications knowing or caring which systems are involved upstream.
**Console terminology:** In the Maverics Console, this section is called
**Identity Fabric**. The YAML configuration uses the `connectors` key to define
identity provider integrations.
## Available Connectors
The Orchestrator ships with connectors for the identity providers and directories enterprises use most.
| Connector | Protocol | Use Case |
| ---------------------------------------------------------------------------------------------- | -------------------- | ------------------------------------------------- |
| [1Kosmos (SAML)](/reference/orchestrator/identity-fabric/onekosmos) | SAML | 1Kosmos passwordless MFA |
| [Amazon Cognito (OIDC)](/reference/orchestrator/identity-fabric/cognito) | OIDC | Cognito user pool SSO, AWS identity |
| [Auth0 (OIDC)](/reference/orchestrator/identity-fabric/auth0) | OIDC | Auth0 SSO federation, tenant migration |
| [Continuity](/reference/orchestrator/identity-fabric/continuity) | Failover aggregation | IdP failover, zero-downtime migration |
| [Generic OIDC](/reference/orchestrator/identity-fabric/custom-oidc) | OIDC | Any OIDC-compliant provider |
| [Generic SAML](/reference/orchestrator/identity-fabric/custom-saml) | SAML 2.0 | Any SAML-compliant provider |
| [CyberArk (OIDC)](/reference/orchestrator/identity-fabric/cyberark) | OIDC | CyberArk Identity SSO |
| [CyberArk (SAML)](/reference/orchestrator/identity-fabric/cyberark-saml) | SAML 2.0 | CyberArk Identity SAML federation |
| [Duo (SAML)](/reference/orchestrator/identity-fabric/duo) | SAML 2.0 | Duo Security MFA federation |
| [Google Workspace (OIDC)](/reference/orchestrator/identity-fabric/google-workspace) | OIDC | Google Workspace SSO (uses generic OIDC) |
| [HYPR](/reference/orchestrator/identity-fabric/hypr) | HYPR | HYPR passwordless authentication |
| [Keycloak (OIDC)](/reference/orchestrator/identity-fabric/keycloak) | OIDC | Keycloak SSO federation |
| [LDAP Authentication](/reference/orchestrator/identity-fabric/ldap) | LDAP/LDAPS | LDAP bind authentication for end users |
| [LDAP Attribute Provider](/reference/orchestrator/identity-fabric/ldap-attr) | LDAP/LDAPS | LDAP attribute lookups for enrichment |
| [Microsoft Active Directory](/reference/orchestrator/identity-fabric/activedirectory) | LDAP (via AD) | Active Directory integration |
| [Microsoft ADFS (SAML)](/reference/orchestrator/identity-fabric/adfs) | SAML 2.0 | ADFS-to-cloud migration, hybrid federation |
| [Microsoft Entra ID (OIDC)](/reference/orchestrator/identity-fabric/azure-ad) | OIDC | Entra ID SSO, hybrid identity |
| [Microsoft Entra ID (SAML)](/reference/orchestrator/identity-fabric/entra-id-saml) | SAML 2.0 | Entra ID SAML-based federation |
| [Microsoft Entra ID Attribute Provider](/reference/orchestrator/identity-fabric/entra-id-attr) | Graph API | Entra ID attribute enrichment via Microsoft Graph |
| [Microsoft Windows Client Authenticator](/reference/orchestrator/identity-fabric/wca) | Windows auth | Windows desktop credential authentication via IIS |
| [Okta (OIDC)](/reference/orchestrator/identity-fabric/okta) | OIDC | Okta SSO consolidation, legacy app bridging |
| [Okta (SAML)](/reference/orchestrator/identity-fabric/okta-saml) | SAML 2.0 | Okta SAML-based federation |
| [Okta Attribute Provider](/reference/orchestrator/identity-fabric/okta-attr) | Okta API | Okta attribute enrichment via API |
| [Oracle Identity Cloud Service (OIDC)](/reference/orchestrator/identity-fabric/oracle-ics) | OIDC | Oracle IDCS SSO |
| [Oracle Universal Directory (LDAP)](/reference/orchestrator/identity-fabric/oracle-oud) | LDAP/LDAPS | Oracle OUD directory integration |
| [PingFederate (OIDC)](/reference/orchestrator/identity-fabric/pingone) | OIDC | PingFederate on-premises federation |
| [PingFederate (SAML)](/reference/orchestrator/identity-fabric/pingfederate-saml) | SAML 2.0 | PingFederate SAML-based federation |
| [Trusona (OIDC)](/reference/orchestrator/identity-fabric/trusona) | OIDC | Trusona identity verification |
| [WSO2 Identity Server (OIDC)](/reference/orchestrator/identity-fabric/wso2) | OIDC | WSO2 Identity Server SSO |
## Mode Compatibility
Identity Fabric connectors work with all five Orchestrator modes. The connector determines which protocol the Orchestrator uses to communicate with your **identity provider**. The mode determines which protocol the Orchestrator uses to communicate with your **application**. These are independent -- an OIDC connector can feed a SAML Provider mode app, and a SAML connector can feed an OIDC Provider mode app. The Orchestrator handles all protocol translation.
* **OIDC connectors** (Microsoft Entra ID, Okta, Auth0, PingFederate, Amazon Cognito, Generic OIDC) -- Used with all modes. Most common for OIDC Provider and HTTP Proxy.
* **SAML connectors** (Generic SAML, Microsoft ADFS, Entra ID SAML, Okta SAML, PingFederate SAML, CyberArk SAML, Duo) -- Used primarily with SAML Provider and HTTP Proxy. The Orchestrator translates SAML upstream to any downstream protocol.
* **LDAP connectors** (LDAP, Microsoft Active Directory, Oracle Universal Directory) -- Used primarily as attribute providers (enriching claims with directory data). Most common with HTTP Proxy and LDAP Provider modes.
* **Continuity connector** -- Mode-agnostic. Wraps other connectors to provide IdP failover.
See the [connector compatibility matrix](/guides/authentication/choosing-a-mode#connector-compatibility) for the full matrix showing which connectors are commonly paired with which modes.
Most connectors authenticate to the identity provider with a client ID and secret you provision ahead of time. The [Generic OAuth](/reference/orchestrator/identity-fabric/oauth) connector additionally supports two credential-less modes for authorization servers that accept them: [Dynamic Client Registration](/reference/orchestrator/identity-fabric/oauth#dynamic-client-registration), where the Orchestrator registers its own client at startup, and [Client ID Metadata Document](/reference/orchestrator/identity-fabric/oauth#client-id-metadata-document) mode, where the Orchestrator identifies itself by a URL it publishes.
## Setup
To create an Identity Fabric connector in the Maverics Console:
1. Navigate to **Identity Fabric** in the Console sidebar.
2. Click **Create** to open the connector type selection dialog.
3. Select the connector type that matches your identity provider (e.g., **Microsoft Entra ID (OIDC)**, **Okta (OIDC)**, **Generic SAML**).
4. Fill in the required fields for your selected connector type -- see the individual connector pages for field-by-field instructions.
5. Click **Save**.
Each connector type has its own configuration form. See the individual connector pages linked below for detailed Console UI walkthroughs specific to each provider.
```yaml maverics.yaml theme={null}
connectors:
- name: azure
type: azure
oauthClientID: "{{ env.AZURE_CLIENT_ID }}"
oauthClientSecret:
oidcWellKnownURL: "https://login.microsoftonline.com/{{ env.AZURE_TENANT_ID }}/v2.0/.well-known/openid-configuration"
oauthRedirectURL: "https://app.example.com/callback"
scopes: "openid profile email"
tls: "idp-tls"
healthCheck:
enabled: true
interval: "30s"
timeout: "5s"
healthyThreshold: 3
unhealthyThreshold: 3
- name: corporate-ldap
type: ldap
url:
- "ldaps://ldap.example.com:636"
serviceAccountUsername: "cn=maverics,ou=services,dc=example,dc=com"
serviceAccountPassword:
baseDN: "dc=example,dc=com"
usernameSearchKey: "uid"
userAttributes:
- "cn"
- "mail"
- "memberOf"
attributeMapping:
email: "mail"
name: "cn"
tls: "ldap-tls"
```
## Connector Pages
1Kosmos passwordless MFA
OIDC connector for AWS Cognito user pools
OIDC connector for Auth0 by Okta
Failover connector for IdP high availability
Generic OpenID Connect connector
Generic SAML 2.0 connector
CyberArk Identity OIDC SSO
CyberArk Identity SAML federation
Duo Security MFA federation
Google Workspace SSO using generic OIDC
HYPR passwordless authentication
Keycloak SSO federation
LDAP bind authentication for end users
LDAP attribute lookups for enrichment
Active Directory connector via LDAP
ADFS federation via SAML
OIDC connector for Microsoft Entra ID
SAML connector for Microsoft Entra ID
Entra ID attribute enrichment via Microsoft Graph
Windows desktop credential authentication via IIS
OIDC connector for Okta
SAML connector for Okta
Okta attribute enrichment via API
Oracle IDCS SSO
Oracle OUD directory integration
OIDC connector for PingFederate
SAML connector for PingFederate
Trusona identity verification
WSO2 Identity Server SSO
## Related Pages
Where the Orchestrator reads its configuration
How the Orchestrator retrieves secrets at runtime
Session storage options and production support status
# Microsoft Active Directory
Source: https://docs.strata.io/reference/orchestrator/identity-fabric/activedirectory
The Active Directory connector integrates the Maverics Orchestrator with on-premises Microsoft Active Directory environments -- providing LDAP-based authentication and attribute lookup for SSO with AD-connected applications.
**Console terminology:** In the Maverics Console, this section is called
**Identity Fabric**. The YAML configuration uses the `connectors` key to define
identity provider integrations.
## Overview
The Active Directory connector uses the LDAP protocol internally to communicate with AD domain controllers. It shares the same configuration field set as the [LDAP connector](/reference/orchestrator/identity-fabric/ldap) with defaults and conventions optimized for Active Directory environments. The key difference is the connector type, which determines internal handling specific to Active Directory.
## Use Cases
* **Unify SSO for AD-dependent applications** -- Extend single sign-on to applications that rely on AD domain credentials, Kerberos, or NTLM without rewriting the application or migrating users out of Active Directory
* **Consolidate AD with cloud IdPs** -- Route AD-bound applications through the Orchestrator alongside cloud IdP applications, reducing the number of standalone identity integrations and simplifying licensing
* **AD-to-cloud failover** -- Pair with the [Continuity connector](/reference/orchestrator/identity-fabric/continuity) to fail over between Active Directory and a cloud IdP, ensuring authentication continues during outages on either side
* **AD attribute enrichment** -- Retrieve AD user attributes (display name, group memberships, email, department) for header injection, claim enrichment, or policy evaluation in legacy and modern applications
## Setup
To create a Microsoft Active Directory connector in the Maverics Console:
1. Navigate to **Identity Fabric** in the Console sidebar.
2. Click **Create** and select **Microsoft Active Directory**.
3. Enter a **Name** for the connector.
4. Enter one or more **URLs** for the Active Directory server (e.g., `ldaps://dc1.corp.example.com:636`). Multiple URLs enable domain controller failover.
5. Enter the **Service Account Username** (bind DN used to connect to the server).
6. Enter the **Service Account Password**.
7. Enter the **Base DN** for LDAP searches (e.g., `dc=corp,dc=example,dc=com`).
8. Enter the **OUD Search Key** -- the attribute used to filter on during query and bind operations. For Active Directory, use `sAMAccountName`.
The Console labels this field **OUD Search Key**. It maps to the `usernameSearchKey` field in the YAML configuration.
9. Optionally select an **Authentication Search Scope** from the dropdown.
10. Optionally set a **Login URL** for a custom endpoint for posting user credentials.
11. Optionally set **Custom Login HTML** to present a custom page for authentication.
12. Optionally set a **CA Path** for the certificate authority when using self-signed certificates.
13. Click **Save**.
```yaml maverics.yaml theme={null}
connectors:
- name: ad
type: activedirectory
url:
- "ldaps://dc1.corp.example.com:636"
- "ldaps://dc2.corp.example.com:636"
serviceAccountUsername: "cn=svc-maverics,ou=Service Accounts,dc=corp,dc=example,dc=com"
serviceAccountPassword:
baseDN: "dc=corp,dc=example,dc=com"
usernameSearchKey: sAMAccountName
enableAuthentication: true
userAttributes:
- sAMAccountName
- mail
- displayName
- memberOf
attributeMapping:
email: mail
name: displayName
username: sAMAccountName
tls: ad-tls
```
## Configuration Reference
The Active Directory connector uses the same field set as the LDAP connector. All fields documented on the [LDAP connector page](/reference/orchestrator/identity-fabric/ldap) apply to `type: activedirectory`.
| Key | Type | Required | Description |
| --------------------------- | --------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `name` | string | Yes | Unique connector identifier referenced by app policies and attribute providers |
| `type` | string | Yes | Must be `activedirectory` |
| `url` | string\[] | Yes | AD domain controller URLs -- supports `ldap://` (port 389) and `ldaps://` (port 636); multiple URLs enable domain controller failover |
| `serviceAccountUsername` | string | Yes | Bind DN for the service account (e.g., `cn=svc-maverics,ou=Service Accounts,dc=corp,dc=example,dc=com`) |
| `serviceAccountPassword` | string | Yes | Service account password -- use secret reference syntax `` |
| `baseDN` | string | Yes | Base DN for LDAP searches (e.g., `dc=corp,dc=example,dc=com`) |
| `usernameSearchKey` | string | No | LDAP attribute used for username lookup -- use `sAMAccountName` for AD environments |
| `userRDNKey` | string | No | Relative Distinguished Name key for user entries |
| `enableAuthentication` | boolean | No | Enable LDAP bind authentication for end users |
| `loginUrl` | string | No | URL for the LDAP login form |
| `authenticationSearchScope` | string | No | LDAP search scope for authentication queries |
| `userAttributes` | string\[] | No | AD attributes to retrieve during searches (e.g., `["sAMAccountName", "mail", "displayName", "memberOf"]`) |
| `objectClasses` | string\[] | No | Object classes for the LDAP search filter |
| `attributeMapping` | map | No | Map Orchestrator attribute names to AD attribute names (e.g., `email: "mail"`) |
| `attributeDelimiter` | string | No | Delimiter for multi-valued attributes (default: `","`) |
| `customLogin.templateFile` | string | No | Path to a custom HTML login form template |
| `tls` | string | No | Named TLS profile for AD connection |
| `healthCheck` | object | No | Health check monitoring configuration (see [Identity Fabric Configuration Reference](/reference/orchestrator/identity-fabric#configuration-reference)) |
For the complete connector field reference including health check details, see [Identity Fabric Configuration Reference](/reference/orchestrator/identity-fabric#configuration-reference).
The `activedirectory` connector type uses the LDAP protocol internally. It shares the same configuration fields as the [LDAP connector](/reference/orchestrator/identity-fabric/ldap). The key difference is the `type` value, which determines internal handling specific to Active Directory environments.
## AD-Specific Notes
* **Use `sAMAccountName` as the `usernameSearchKey`** -- In Active Directory environments, users typically log in with their `sAMAccountName` (e.g., `jsmith`), not the `uid` attribute used by generic LDAP directories.
* **Multiple `url` entries support domain controller failover** -- List multiple domain controller URLs to ensure authentication continues if a DC becomes unavailable. The Orchestrator will try each URL in order.
* **For LDAPS, ensure the TLS profile includes AD's root CA** -- Active Directory Certificate Services (AD CS) often uses an internal CA. The TLS profile referenced by the `tls` field must include this CA certificate via `caFile`.
* **Common AD attributes** -- `sAMAccountName` (login name), `mail` (email), `displayName` (full name), `memberOf` (group memberships), `department`, `title`, `manager`.
## Troubleshooting
* **Service account permissions** -- The service account must have read access to the `baseDN` subtree. In AD, this typically means the account needs "Read all properties" permission on user objects in the target OU.
* **LDAPS certificate trust** -- AD domain controllers use certificates issued by AD CS. Export the root CA certificate and include it in the TLS profile. Without it, LDAPS connections will fail with certificate verification errors.
* **Distinguished Name format** -- AD uses a specific DN format with OUs (e.g., `cn=svc-maverics,ou=Service Accounts,dc=corp,dc=example,dc=com`). Verify the exact DN using `dsquery` or Active Directory Users and Computers.
* **Group membership depth** -- The `memberOf` attribute only shows direct group memberships, not nested groups. For nested group resolution, consider using a group search filter or a Service Extension.
## Related Pages
Generic LDAP connector for non-AD directories
Overview of all identity providers
Complete field reference for all connector types
IdP failover connector for hybrid AD/cloud scenarios
# Microsoft ADFS (SAML)
Source: https://docs.strata.io/reference/orchestrator/identity-fabric/adfs
The ADFS connector integrates the Maverics Orchestrator with Microsoft Active Directory Federation Services -- enabling authentication for applications that rely on ADFS for identity federation.
**Console terminology:** In the Maverics Console, this section is called
**Identity Fabric**. The YAML configuration uses the `connectors` key to define
identity provider integrations.
## Overview
The ADFS connector integrates with ADFS using the SAML 2.0 protocol. It is designed for organizations modernizing their identity infrastructure -- allowing you to migrate away from ADFS without disrupting existing applications or requiring simultaneous cutover of all relying parties.
## Use Cases
* **ADFS-to-cloud migration** -- Gradually move relying parties from ADFS to a modern cloud IdP without downtime, reducing ADFS licensing and infrastructure costs
* **Unify SSO across ADFS and cloud IdPs** -- Bridge ADFS with cloud identity providers so users get seamless access across on-prem and cloud applications during migration
* **ADFS modernization without rip-and-replace** -- Add modern authentication capabilities like MFA and conditional access to ADFS-protected applications without modifying ADFS itself
* **ADFS failover and resilience** -- Pair ADFS with a backup IdP through the Continuity connector so authentication continues if the ADFS farm becomes unavailable
## Setup
To create a Microsoft ADFS (SAML) connector in the Maverics Console:
1. Navigate to **Identity Fabric** in the Console sidebar.
2. Click **Create** and select **Microsoft ADFS (SAML)**.
3. Enter a **Name** -- the friendly name for your ADFS provider.
4. Enter the **Metadata URL** -- the ADFS federation metadata endpoint (typically `https://{adfs-host}/FederationMetadata/2007-06/FederationMetadata.xml`).
5. Enter the **Consumer Service (ACS) URL** -- the URL where ADFS sends SAML responses after authentication.
6. Enter the **Entity ID** -- the unique identifier for the Orchestrator as the SAML Service Provider.
7. Optionally enter a **Logout Callback URL** for Single Logout (SLO) callback.
8. Optionally enter the **SP Certificate Path** and **SP Private Key Path** if your ADFS configuration requires signed SAML requests.
9. Optionally enable **IdP Initiated Login** if authentication flows will be started from the ADFS side.
10. Click **Save**.
```yaml maverics.yaml theme={null}
connectors:
- name: adfs
type: adfs
samlMetadataURL: "https://{{ env.ADFS_HOST }}/FederationMetadata/2007-06/FederationMetadata.xml"
samlConsumerServiceURL: "https://orch.example.com/saml/callback"
samlEntityID: "https://orch.example.com"
tls: adfs-tls
```
## Configuration Reference
| Key | Type | Required | Description |
| ------------------------ | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `name` | string | Yes | Unique connector identifier referenced in app policies |
| `type` | string | Yes | Must be `adfs` |
| `samlMetadataURL` | string | Yes | URL to the ADFS federation metadata XML (typically `https://{adfs-host}/FederationMetadata/2007-06/FederationMetadata.xml`) |
| `samlConsumerServiceURL` | string | Yes | Assertion Consumer Service (ACS) URL where ADFS sends SAML responses |
| `samlEntityID` | string | No | Service Provider entity ID that identifies the Orchestrator to ADFS |
| `samlLogoutCallbackURL` | string | No | Logout callback URL for SAML single logout |
| `samlSPCertPath` | string | No | Path to the SP certificate file for signing SAML requests |
| `samlSPKeyPath` | string | No | Path to the SP private key file for signing SAML requests |
| `samlIDPInitiatedLogin` | object | No | IdP-initiated login configuration |
| `cache` | string | No | Cache name reference for SAML request data storage |
| `tls` | string | No | Named TLS profile for metadata retrieval and IdP communication |
| `healthCheck` | object | No | Health check monitoring configuration (see [Identity Fabric Configuration Reference](/reference/orchestrator/identity-fabric#configuration-reference)) |
For the complete connector field reference including health check details, see [Identity Fabric Configuration Reference](/reference/orchestrator/identity-fabric#configuration-reference).
## Troubleshooting
* **Verify the ADFS federation metadata URL is accessible** -- The Orchestrator fetches the ADFS metadata XML at startup. The metadata URL is typically `https://{adfs-host}/FederationMetadata/2007-06/FederationMetadata.xml`. Test the URL with `curl` from the Orchestrator host.
* **Ensure the entity ID matches ADFS relying party configuration** -- The `samlEntityID` value must match the Relying Party Trust identifier configured in ADFS. Mismatched entity IDs cause ADFS to reject authentication requests.
* **Check the Assertion Consumer Service URL** -- The `samlConsumerServiceURL` must match the Orchestrator's actual callback endpoint. If behind a load balancer or reverse proxy, use the external-facing URL that ADFS will redirect to.
* **SP signing certificate errors** -- If ADFS requires signed authentication requests, ensure `samlSPCertPath` and `samlSPKeyPath` point to valid PEM files and the key matches the certificate.
## Related Pages
Overview of all identity providers
Generic SAML 2.0 connector
OIDC connector for Microsoft Entra ID
Failover connector for IdP high availability
# Auth0 (OIDC)
Source: https://docs.strata.io/reference/orchestrator/identity-fabric/auth0
The Auth0 connector integrates the Maverics Orchestrator with Auth0 by Okta -- enabling OIDC-based single sign-on for applications that authenticate against Auth0 tenants.
**Console terminology:** In the Maverics Console, this section is called
**Identity Fabric**. The YAML configuration uses the `connectors` key to define
identity provider integrations.
## Overview
The Auth0 connector uses OpenID Connect to federate authentication with Auth0. It supports standard OIDC flows -- designed for organizations that use Auth0 as their identity platform, whether for customer-facing (CIAM) or workforce identity scenarios. The connector can also facilitate Auth0 tenant migrations and multi-IdP orchestration.
## Use Cases
* **Unify SSO across CIAM and workforce apps** -- Extend Auth0 authentication to legacy applications that don't support OIDC natively, bridging customer-facing and internal identity scenarios
* **Rationalize Auth0 tenants** -- Consolidate multiple Auth0 tenants or migrate users from Auth0 to another IdP gradually without downtime, reducing per-tenant licensing costs
* **Authentication resilience** -- Route authentication to a backup identity provider if Auth0 becomes unavailable, maintaining continuous access for end users
* **Orchestrate Auth0 with enterprise IdPs** -- Combine Auth0 with providers like Microsoft Entra ID or Okta in a single authentication flow, enabling flexible identity routing across platforms
## Setup
To create an Auth0 (OIDC) connector in the Maverics Console:
1. Navigate to **Identity Fabric** in the Console sidebar.
2. Click **Create** and select **Auth0 (OIDC)**.
3. Enter a **Name** -- this is the friendly name that identifies your provider.
4. Enter the **OIDC Well Known URL** -- for Auth0, this follows the pattern `https://{your-tenant}.auth0.com/.well-known/openid-configuration`. If you are using a custom domain, replace the tenant URL with your custom domain.
5. Enter the **OAuth Client ID** -- the Client ID from your Auth0 application settings in the Auth0 dashboard.
6. Enter the **OAuth Client Secret** -- the Client Secret from your Auth0 application settings.
7. Under **Redirect URLs**, add the callback URL where Auth0 will redirect after authentication. This URL must match an entry in the Allowed Callback URLs configured in your Auth0 application.
8. Optionally configure **Logout Callback URLs** for single logout support.
9. Optionally set **Scopes** (space-separated). Default scopes are typically `openid profile email`.
10. The **PKCE** toggle is enabled by default. Disable it only if your Auth0 application is not configured to support Proof Key for Code Exchange.
11. Optionally enable **Offline Access** for token refresh support (Proxy apps only).
12. Click **Save**.
```yaml theme={null}
connectors:
- name: auth0
type: auth0
oidcWellKnownURL: "https://{{ env.AUTH0_DOMAIN }}/.well-known/openid-configuration"
oauthClientID: "{{ env.AUTH0_CLIENT_ID }}"
oauthClientSecret:
oauthLoginRedirect:
urls:
- https://app.example.com/oidc/callback
```
## Configuration Reference
| Key | Type | Required | Description |
| -------------------------- | ------ | -------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `name` | string | Yes | Unique connector identifier referenced in app policies |
| `type` | string | Yes | Must be `auth0` |
| `oidcWellKnownURL` | string | Yes | OIDC discovery endpoint URL (Auth0 tenant domain) |
| `oauthClientID` | string | Yes | OAuth 2.0 client ID from the Auth0 dashboard |
| `oauthClientSecret` | string | Yes | OAuth 2.0 client secret (use secret reference syntax) |
| `oauthLoginRedirect.urls` | list | Yes | Callback URL(s) registered with the Auth0 application. The Orchestrator selects the URL whose host matches the incoming request. |
| `oauthLogoutRedirect.urls` | list | No | URL(s) called by Auth0 after a successful logout. |
| `tls` | string | No | Named TLS profile for provider communication |
For the complete field reference including health checks, offline access, and PKCE settings, see [Identity Fabric](/reference/orchestrator/identity-fabric#configuration-reference).
## Troubleshooting
* **Verify the `oidcWellKnownURL` is accessible** from the Orchestrator host -- ensure the Auth0 domain is correct (e.g., `your-tenant.auth0.com` or custom domain)
* **Ensure each URL in `oauthLoginRedirect.urls` matches exactly** what is registered in the Auth0 application under Allowed Callback URLs
* **Check that the client secret reference resolves correctly** via your secret provider
## Related Pages
Overview of all identity providers
OIDC connector for Okta
Generic OpenID Connect connector
Failover connector for IdP high availability
# Microsoft Entra ID (OIDC)
Source: https://docs.strata.io/reference/orchestrator/identity-fabric/azure-ad
The Microsoft Entra ID connector integrates the Maverics Orchestrator with Microsoft Entra ID (formerly Azure Active Directory) -- enabling OIDC-based single sign-on for your applications.
**Console terminology:** In the Maverics Console, this section is called
**Identity Fabric**. The YAML configuration uses the `connectors` key to define
identity provider integrations.
## Overview
The Microsoft Entra ID connector uses OpenID Connect to federate authentication with Microsoft Entra ID and supports standard OIDC flows -- allowing you to bridge Microsoft Entra ID with applications that don't natively support modern identity protocols.
## Use Cases
* **Unify SSO across hybrid environments** -- Extend Microsoft Entra ID authentication to legacy and on-premises applications that don't support modern protocols, creating seamless SSO across your entire hybrid estate
* **Rationalize identity platforms** -- Consolidate redundant identity providers onto Microsoft Entra ID by orchestrating gradual user migration without disrupting access to existing applications
* **Identity resilience and failover** -- Configure Microsoft Entra ID as a primary or secondary IdP with automatic failover routing, ensuring authentication continuity if another provider experiences an outage
* **Bridge on-premises Active Directory** -- Connect on-premises AD (synced via Entra ID Connect) with cloud applications through OIDC federation, unifying access across directory boundaries
## Setup
To create a Microsoft Entra ID (OIDC) connector in the Maverics Console:
1. Navigate to **Identity Fabric** in the Console sidebar.
2. Click **Create** and select **Microsoft Entra ID (OIDC)**.
3. Enter a **Name** -- this is the friendly name that identifies your provider.
4. Enter the **OIDC Well Known URL** -- for Microsoft Entra ID, this follows the pattern `https://login.microsoftonline.com/{tenant-id}/v2.0/.well-known/openid-configuration`. Replace `{tenant-id}` with your Microsoft Entra ID directory (tenant) ID from the Azure portal. Use the v2.0 endpoint for standard OIDC support.
5. Enter the **OAuth Client ID** -- the Application (client) ID from your Entra ID app registration in the Azure portal.
6. Enter the **OAuth Client Secret** -- the client secret from your Entra ID app registration.
7. Under **Redirect URLs**, add the callback URL where Entra ID will redirect after authentication. This URL must match a Redirect URI configured in the app registration under Authentication.
8. Optionally configure **Logout Callback URLs** for single logout support.
9. Optionally set **Scopes** (space-separated). Default scopes are typically `openid profile email`.
10. The **PKCE** toggle is enabled by default. Disable it only if your Entra ID app registration is not configured to support Proof Key for Code Exchange.
11. Optionally enable **Offline Access** for token refresh support (Proxy apps only).
12. Optionally configure **Error Handling** rules to redirect users based on errors returned by the IdP during the OIDC callback. See [Callback Error Handling](#callback-error-handling) for details.
13. Click **Save**.
```yaml theme={null}
connectors:
- name: azure
type: azure
oidcWellKnownURL: "https://login.microsoftonline.com/{{ env.AZURE_TENANT_ID }}/v2.0/.well-known/openid-configuration"
oauthClientID: "{{ env.AZURE_CLIENT_ID }}"
oauthClientSecret:
oauthLoginRedirect:
urls:
- https://app.example.com/oidc/callback
```
The Microsoft Entra ID well-known URL includes a tenant ID in the path: `login.microsoftonline.com/{tenant-id}/v2.0/`. Use the v2.0 endpoint for standard OIDC support. Replace the tenant ID with your Microsoft Entra ID directory (tenant) ID from the Azure portal.
## Configuration Reference
| Key | Type | Required | Description |
| -------------------------- | ------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name` | string | Yes | Unique connector identifier referenced in app policies |
| `type` | string | Yes | Must be `azure` |
| `oidcWellKnownURL` | string | Yes | OIDC discovery endpoint URL (tenant-specific) |
| `oauthClientID` | string | Yes | OAuth 2.0 client (application) ID from the Azure portal |
| `oauthClientSecret` | string | Yes | OAuth 2.0 client secret (use secret reference syntax) |
| `oauthLoginRedirect.urls` | list | Yes | Callback URL(s) registered with the Microsoft Entra ID app registration. The Orchestrator selects the URL whose host matches the incoming request. |
| `oauthLogoutRedirect.urls` | list | No | URL(s) called by Entra ID after a successful logout. |
| `tls` | string | No | Named TLS profile for provider communication |
| `errorHandling` | object | No | Configures how IdP errors during the OIDC callback are handled. See [Callback Error Handling](#callback-error-handling) below. |
For the complete field reference including health checks, offline access, and PKCE settings, see [Identity Fabric](/reference/orchestrator/identity-fabric#configuration-reference).
## Callback Error Handling
When Microsoft Entra ID returns an error during the OIDC callback (e.g., the user forgot their password in an Azure AD B2C flow, or cancelled login), the Orchestrator can evaluate configurable rules to redirect the user to a specific URL based on the error.
Rules are evaluated in order -- the first matching rule wins. You can match on the `error` or `error_description` callback parameters using exact or substring matching. A default catch-all rule can be included to handle any unmatched errors.
In the connector's **Error Handling** section:
1. Click **Add Rule** to create a new error handling rule.
2. Select a **Match On** value -- either **Error** or **Error Description** -- to choose which OIDC callback parameter to match against.
3. Select a **Match Type** -- either **Contains** (substring match) or **Equals** (exact match).
4. Enter the **Match Value** -- the string to match against the selected callback parameter (e.g., `AADB2C90118` for Azure AD B2C password reset flows).
5. Enter the **Redirect URL** -- the URL to redirect the user to when this rule matches.
6. Optionally check **Default** to make a rule the catch-all for any unmatched errors. A default rule does not require Match On, Match Type, or Match Value fields. Only one default rule is allowed.
7. Drag rules to reorder them -- rules are evaluated top to bottom and the first match wins.
8. Click **Save**.
Rules are defined under `errorHandling.onCallbackError`:
```yaml theme={null}
connectors:
- name: azure
type: azure
oidcWellKnownURL: "https://login.microsoftonline.com/{{ env.AZURE_TENANT_ID }}/v2.0/.well-known/openid-configuration"
oauthClientID: "{{ env.AZURE_CLIENT_ID }}"
oauthClientSecret:
oauthLoginRedirect:
urls:
- https://app.example.com/oidc/callback
errorHandling:
onCallbackError:
- contains: "AADB2C90118"
matchOn: error_description
redirectURL: "https://app.example.com/password-reset"
- equals: server_error
matchOn: error
redirectURL: "https://app.example.com/error"
- default: true
redirectURL: "https://app.example.com/generic-error"
```
### Rule Reference
Each rule in the `onCallbackError` list supports the following fields:
| Key | Type | Required | Description |
| ------------- | ------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `contains` | string | Conditional | Matches when the target field contains this substring. Mutually exclusive with `equals`. Required unless `default` is `true`. |
| `equals` | string | Conditional | Matches when the target field exactly equals this value. Mutually exclusive with `contains`. Required unless `default` is `true`. |
| `matchOn` | string | Conditional | Which callback parameter to match against. Must be `error` or `error_description`. Required unless `default` is `true`. |
| `redirectURL` | string | Yes | The URL to redirect the user to when the rule matches. |
| `default` | boolean | No | When `true`, this rule acts as a catch-all for any error not matched by prior rules. When set, `contains`, `equals`, and `matchOn` must not be defined. Only one default rule is allowed. |
If no rule matches the error and no `default` rule is defined, the Orchestrator falls back to the standard error handling behavior.
## Troubleshooting
* **Verify the `oidcWellKnownURL` is accessible** from the Orchestrator host -- ensure the tenant ID is correct and the v2.0 endpoint is used
* **Ensure each URL in `oauthLoginRedirect.urls` matches exactly** what is registered in the Microsoft Entra ID app registration under Authentication > Redirect URIs
* **Check that the client secret reference resolves correctly** via your secret provider -- Microsoft Entra ID client secrets expire and need periodic rotation
## Related Pages
Overview of all identity providers
OIDC connector for Okta
Generic OpenID Connect connector
OIDC connector for ADFS
# Amazon Cognito (OIDC)
Source: https://docs.strata.io/reference/orchestrator/identity-fabric/cognito
The Cognito connector integrates the Maverics Orchestrator with Amazon Cognito -- enabling OIDC-based single sign-on for applications that authenticate against Cognito user pools.
**Console terminology:** In the Maverics Console, this section is called
**Identity Fabric**. The YAML configuration uses the `connectors` key to define
identity provider integrations.
## Overview
The Cognito connector uses OpenID Connect to federate authentication with Amazon Cognito and supports standard OIDC flows -- allowing you to bridge Cognito user pools with applications that don't natively support modern identity protocols.
## Use Cases
* **Unify SSO for AWS-native workloads** -- Extend Cognito user pool authentication to legacy and non-AWS applications, creating a consistent SSO experience across your AWS and hybrid environments
* **Rationalize away from Cognito** -- Gradually migrate users from Cognito to an enterprise IdP like Microsoft Entra ID or Okta without downtime, reducing the complexity of maintaining separate identity stores
* **Hybrid cloud identity orchestration** -- Route authentication across Cognito and enterprise identity providers based on application context, unifying access for organizations with multi-cloud deployments
* **AWS application resilience** -- Configure Cognito as a failover IdP for AWS-hosted applications, ensuring authentication continuity even when the primary identity provider is unavailable
## Setup
To create an Amazon Cognito (OIDC) connector in the Maverics Console:
1. Navigate to **Identity Fabric** in the Console sidebar.
2. Click **Create** and select **Amazon Cognito (OIDC)**.
3. Enter a **Name** for the connector -- this is the friendly name that identifies your Cognito integration.
4. Enter the **OIDC Well Known URL** for your Cognito user pool. This follows the pattern `https://cognito-idp.{region}.amazonaws.com/{user-pool-id}/.well-known/openid-configuration` -- replace `{region}` with your AWS region (e.g., `us-east-1`) and `{user-pool-id}` with the Cognito user pool ID from the AWS Console.
5. Enter the **OAuth Client ID** -- the app client ID from your Cognito user pool's App integration settings.
6. Enter the **OAuth Client Secret** -- the app client secret associated with the client ID. Use the show/hide toggle to verify the value.
7. Add one or more **Redirect URLs** -- the callback URL(s) where Cognito redirects users after authentication. The Maverics OIDC handler will be served on this URL.
8. Optionally add **Logout Callback URLs** -- the URL(s) that Cognito calls after a successful logout.
9. Optionally enter **Scopes** -- space-separated OIDC scopes to request (e.g., `openid profile email`). If left empty, default scopes are used.
10. **Proof Key for Code Exchange (PKCE)** is enabled by default. Disable this toggle only if your Cognito app client is not configured to support PKCE.
11. Optionally enable **Offline Access** if you need refresh tokens. When enabled, set your policy's `decision.lifetime` slightly longer than the interval for token refreshing.
12. Click **Save**.
```yaml theme={null}
connectors:
- name: cognito
type: cognito
oidcWellKnownURL: "https://cognito-idp.{{ env.AWS_REGION }}.amazonaws.com/{{ env.COGNITO_USER_POOL_ID }}/.well-known/openid-configuration"
oauthClientID: "{{ env.COGNITO_CLIENT_ID }}"
oauthClientSecret:
oauthRedirectURL: "https://app.example.com/oidc/callback"
scopes: "openid profile email"
```
The Cognito well-known URL follows the pattern: `cognito-idp.{region}.amazonaws.com/{user-pool-id}/`. Replace the region and user pool ID with your Cognito configuration values from the AWS Console.
## Configuration Reference
| Key | Type | Required | Description |
| ------------------- | ------ | -------- | -------------------------------------------------------------- |
| `name` | string | Yes | Unique connector identifier referenced in app policies |
| `type` | string | Yes | Must be `cognito` |
| `oidcWellKnownURL` | string | Yes | OIDC discovery endpoint URL (Cognito user pool-specific) |
| `oauthClientID` | string | Yes | OAuth 2.0 app client ID from the Cognito user pool |
| `oauthClientSecret` | string | Yes | OAuth 2.0 app client secret (use secret reference syntax) |
| `oauthRedirectURL` | string | Yes | Callback URL registered with the Cognito app client |
| `scopes` | string | No | Space-separated OAuth scopes (default: `openid profile email`) |
| `tls` | string | No | Named TLS profile for provider communication |
For the complete field reference including health checks, offline access, and PKCE settings, see [Identity Fabric](/reference/orchestrator/identity-fabric#configuration-reference).
## Troubleshooting
* **Verify the `oidcWellKnownURL` is accessible** from the Orchestrator host -- ensure the AWS region and user pool ID are correct
* **Ensure the `oauthRedirectURL` matches exactly** what is registered in the Cognito app client under Allowed callback URLs
* **Check that the client secret reference resolves correctly** via your secret provider -- ensure the Cognito app client is configured to generate a client secret
## Related Pages
Overview of all identity providers
Generic OpenID Connect connector
Full field-level reference for all connector types
# Continuity
Source: https://docs.strata.io/reference/orchestrator/identity-fabric/continuity
The Continuity connector enables IdP failover across multiple identity providers -- ensuring authentication continues working even when a primary identity provider is unavailable.
**Console terminology:** In the Maverics Console, this section is called
**Identity Fabric**. The YAML configuration uses the `connectors` key to define
identity provider integrations.
## Overview
The Continuity connector is unique among identity connectors because it doesn't connect to a single identity provider. Instead, it orchestrates failover across multiple existing connectors. When the primary IdP is unavailable, the Orchestrator automatically routes authentication requests to the next connector in the ordered list. The connector also supports attribute normalization, mapping different attribute names across providers to a consistent set of names.
The Continuity connector uses the `failover` strategy with an ordered list of IdP connectors defined in `failover.idps`. The first connector in the list is the primary; subsequent connectors serve as fallbacks.
### Identity Backup vs Identity Continuity
It is important to distinguish between **Identity Backup** and **Identity Continuity**:
* **Identity Backup** preserves identity data (users, groups, policies) so it can be restored after an outage. It protects the data itself.
* **Identity Continuity** ensures that authentication and access remain uninterrupted during an IdP outage. It protects the user experience by routing requests to an alternate identity provider while the primary is down.
The Continuity connector implements Identity Continuity -- it does not back up or replicate identity data between providers. Instead, it uses health-check-driven failover to route authentication to whichever provider is currently available.
## Use Cases
* **Identity resilience with automatic failover** -- Ensure authentication never goes down by automatically routing users to a healthy backup IdP when the primary experiences an outage. Health-check-driven failover eliminates manual intervention and keeps business-critical applications accessible.
* **Cloud-to-on-premises failover** -- When a cloud IdP (such as Okta or Entra ID) is unavailable, automatically fail over to an on-premises IdP like ADFS or Active Directory so users maintain uninterrupted access to applications.
* **Cloud-to-cloud redundancy** -- Maintain high availability by configuring failover between two cloud identity providers (e.g., Okta primary with Entra ID backup), protecting against vendor-specific outages.
* **Zero-downtime IdP migration** -- Gradually shift authentication from a legacy IdP to a modern one without service interruption. Set the new IdP as primary and keep the old IdP as fallback during the transition, reducing risk and enabling IdP rationalization.
## Supported Identity Services
Not all identity services support the health monitoring required for Continuity failover. The following table lists which services are supported:
| Supported | Not Supported |
| ----------------------------- | ---------------------------- |
| ADFS SAML | 1Kosmos |
| Amazon Cognito | HYPR |
| Auth0 | Windows Client Authenticator |
| CyberArk | WSO2 |
| Duo | |
| Entra ID | |
| Generic OIDC | |
| Generic SAML | |
| Keycloak | |
| Okta | |
| Oracle Identity Cloud Service | |
| Ping Federate | |
| Trusona | |
Unsupported services lack a reliable health check endpoint. If your identity provider is not listed as supported, contact [Strata support](https://strataidentity.my.site.com/support/s/) to discuss options.
## Setup
To create a Continuity Strategy in the Maverics Console:
1. Navigate to **Identity Fabric** in the Console sidebar.
2. Click **Create** and select **Continuity Strategy**.
3. Enter a **Name** for the strategy -- this is the friendly name that identifies your failover configuration.
4. In the **Fallback Strategy** section, add identity providers in priority order. The first provider is the primary; subsequent providers serve as backups that are used when providers above them are unavailable.
5. In the **Schema Abstraction Layer** section, define attribute mappings. For each attribute your applications need, map it to the corresponding claim name in each identity provider (see [Schema Abstraction Layer](#schema-abstraction-layer) below).
6. Click **Save**.
Deploying a Continuity Strategy to production requires a license. Contact [sales@strata.io](mailto:sales@strata.io) for licensing.
```yaml maverics.yaml theme={null}
connectors:
- name: failover-idp
type: continuity
strategy: failover
failover:
idps:
- primary-idp
- backup-idp
attributes:
- name: email
mapping:
primary-idp: primary_email
backup-idp: backup_email
default: "unknown@example.com"
```
## Configuration Reference
| Key | Type | Required | Description |
| ---------------------- | --------- | -------- | ------------------------------------------------------------------------------------------------------------------------ |
| `name` | string | Yes | Unique connector identifier referenced by app policies |
| `type` | string | Yes | Must be `continuity` |
| `strategy` | string | Yes | Failover strategy -- currently only `failover` is supported |
| `failover.idps` | string\[] | Yes | Ordered list of connector names to try. The first entry is the primary; subsequent entries are fallbacks tried in order. |
| `attributes` | object\[] | No | Attribute normalization rules across identity providers |
| `attributes[].name` | string | Yes | Normalized attribute name used by the Orchestrator |
| `attributes[].mapping` | map | Yes | Map of connector name to that connector's attribute name (e.g., `primary-idp: "primary_email"`) |
| `attributes[].default` | string | No | Default value if the attribute is unavailable from any IdP |
For the complete connector field reference, see [Identity Fabric](/reference/orchestrator/identity-fabric#configuration-reference).
The connectors listed in `failover.idps` must be separately defined in the `connectors` section. The Continuity connector does not create them -- it orchestrates failover between existing connectors. Each referenced connector (e.g., an OIDC or SAML connector) must have its own complete configuration.
## How Failover Works
1. The Orchestrator performs configurable health checks on each connector listed in `failover.idps`. Health checks run at the interval specified on each individual connector's `healthCheck` configuration.
2. When an authentication request arrives, the Orchestrator routes it to the first **healthy** connector in the ordered list.
3. If the primary connector's health check is failing, the Orchestrator skips it and routes to the next healthy connector in the list. This is proactive, health-check-driven routing -- not trial-and-error login attempts.
4. The `attributes` section normalizes attribute names across providers, so downstream applications see consistent attribute names regardless of which IdP handled the authentication.
## Health Monitoring
Identity Service Health Monitoring must be enabled on **each individual IdP connector** used in the Continuity strategy -- not on the Continuity connector itself. The Continuity connector reads the health status of its referenced connectors to make routing decisions.
### Health Check Configuration
Add a `healthCheck` block to each connector referenced in `failover.idps`:
```yaml maverics.yaml theme={null}
connectors:
- name: primary-idp
type: oidc
oidcWellKnownURL: "https://primary.example.com/.well-known/openid-configuration"
oauthClientID: "{{ env.PRIMARY_CLIENT_ID }}"
oauthClientSecret:
oauthRedirectURL: "https://app.example.com/oidc/callback"
scopes: "openid profile email"
healthCheck:
enabled: true
interval: "10s"
timeout: "5s"
unhealthyThreshold: 3
healthyThreshold: 2
```
### Health Check Fields
| Key | Type | Default | Description |
| -------------------------------- | ------- | ------- | ------------------------------------------------------------------------------------------------------------------------ |
| `healthCheck.enabled` | boolean | `false` | Enable or disable health monitoring for this connector |
| `healthCheck.interval` | string | `"30s"` | Polling frequency (e.g., `"10s"`, `"1m"`, `"30s"`) |
| `healthCheck.timeout` | string | `"10s"` | Maximum wait time for a health check response before considering it failed |
| `healthCheck.unhealthyThreshold` | integer | `3` | Number of consecutive health check failures before marking the connector as unhealthy and triggering failover |
| `healthCheck.healthyThreshold` | integer | `2` | Number of consecutive health check successes before marking a previously-unhealthy connector as healthy again (fallback) |
### Custom Health Check Fields
For providers that require non-standard health check endpoints or validation, use the `customEndpoint` object:
| Key | Type | Description |
| ------------------------------------------------------------- | ---------- | ----------------------------------------------------------------------------- |
| `healthCheck.customEndpoint.type` | string | The type of the custom endpoint. Must be `http`. |
| `healthCheck.customEndpoint.endpoint` | string | Custom URL to check instead of the default well-known endpoint |
| `healthCheck.customEndpoint.headers` | map | Additional HTTP headers to include in the health check request |
| `healthCheck.customEndpoint.tls` | string | Name of the TLS config used to establish a secure connection |
| `healthCheck.customEndpoint.responseMatcher.expectedStatuses` | integer\[] | HTTP status codes considered healthy (e.g., `[200, 204]`) |
| `healthCheck.customEndpoint.responseMatcher.body.equals` | string | The response body must exactly equal this string to be considered healthy |
| `healthCheck.customEndpoint.responseMatcher.body.contains` | string | The response body must contain this string to be considered healthy |
| `healthCheck.customEndpoint.responseMatcher.body.regexp` | string | The response body must match this regular expression to be considered healthy |
Only one of `body.equals`, `body.contains`, or `body.regexp` can be defined at a time.
### How Health Checks Work by Protocol
* **OIDC-based services** (Okta, Entra ID, Auth0, Keycloak, Generic OIDC): Health checks call the well-known discovery endpoint (e.g., `/.well-known/openid-configuration`). If the endpoint is unreachable or returns an error, the connector is marked unhealthy.
* **SAML-based services** (ADFS SAML, Generic SAML, Ping Federate): Health checks call the IdP's metadata endpoint.
* **LDAP/AD services** (Active Directory, LDAP): Health checks attempt a connection to the server URL and perform a bind operation.
When troubleshooting health check failures, enable debug-level logging. Look for messages like:
```
level=debug msg="idp health check failed: well-known metadata unavailable"
```
This indicates the Orchestrator cannot reach the IdP's discovery endpoint.
## Schema Abstraction Layer
The Schema Abstraction Layer creates a mapping between the attributes your applications require and the claims available from each identity service. Different identity providers often use different attribute names for the same data -- for example, Okta might use `email` while Entra ID uses `preferred_username`, and an LDAP directory might use `mail`.
The Schema Abstraction Layer solves this by defining a normalized attribute name (the Maverics attribute) and mapping it to the corresponding claim in each provider. During failover, when the Orchestrator establishes a new session with the backup IdP, it uses this mapping to retrieve the equivalent claims -- ensuring downstream applications receive the same attribute names regardless of which IdP authenticated the user.
In YAML configuration, the Schema Abstraction Layer is expressed through the `attributes` section of the Continuity connector:
```yaml maverics.yaml theme={null}
connectors:
- name: failover-idp
type: continuity
strategy: failover
failover:
idps:
- okta-idp
- entra-idp
- ldap-idp
attributes:
- name: email
mapping:
okta-idp: email
entra-idp: preferred_username
ldap-idp: mail
- name: role
mapping:
okta-idp: role
entra-idp: group
default: "user"
- name: display_name
mapping:
okta-idp: name
entra-idp: displayName
ldap-idp: cn
```
Each entry in `attributes` defines:
* **`name`** -- The normalized attribute name that your applications will receive.
* **`mapping`** -- A map from connector name to the claim name used by that provider.
* **`default`** -- An optional fallback value if the attribute is unavailable from the authenticating IdP.
## Troubleshooting
Every connector name in `failover.idps` must have a corresponding entry in the `connectors` section. Missing connectors will cause configuration validation errors at startup.
**Fix:** Check that each name listed in `failover.idps` exactly matches a connector `name` defined elsewhere in the configuration.
If different IdPs use different attribute names for the same data (e.g., `email` vs `mail`), applications may receive inconsistent attribute names depending on which IdP authenticated the user.
**Fix:** Use the `attributes` section to map provider-specific claim names to a single normalized name. Ensure every connector in `failover.idps` has an entry in each attribute's `mapping`.
If health checks are not enabled on the individual connectors referenced by the Continuity connector, the Orchestrator cannot proactively detect unavailable IdPs. It will instead rely on authentication failure, which degrades the user experience.
**Fix:** Add `healthCheck.enabled: true` on each connector listed in `failover.idps`. Set appropriate `interval`, `timeout`, and `unhealthyThreshold` values.
This debug log message indicates the Orchestrator cannot reach the IdP's discovery endpoint.
**Possible causes:**
* Network connectivity issues between the Orchestrator and the IdP
* DNS resolution failures
* Firewall rules blocking the health check request
* The IdP's well-known endpoint has changed or is temporarily unavailable
* TLS certificate issues (use `healthCheck.customEndpoint.tls` to reference a TLS config for self-signed certificates)
**Fix:** Verify the IdP's well-known endpoint is reachable from the Orchestrator host. Check DNS, firewall, and TLS settings. Enable debug logging to see the full error.
The connector listed first in `failover.idps` is always tried first when healthy. If your preferred IdP is not receiving traffic, check the ordering.
**Fix:** Place the most reliable or preferred IdP first in the `failover.idps` list. Subsequent connectors are only used when all preceding connectors are unhealthy.
## Related Pages
Step-by-step guide to configuring Continuity with Console UI and YAML
Overview of all identity providers and supported types
Complete field reference for all connector types
Generic OIDC connector -- commonly used as a failover target
Generic SAML connector -- commonly used as a failover target
# Generic OIDC
Source: https://docs.strata.io/reference/orchestrator/identity-fabric/custom-oidc
The Generic OIDC connector provides a generic OpenID Connect integration for any OIDC-compliant identity provider -- giving you flexibility to connect providers that don't have a dedicated connector in the Orchestrator.
**Console terminology:** In the Maverics Console, this section is called
**Identity Fabric**. The YAML configuration uses the `connectors` key to define
identity provider integrations.
## Overview
The Generic OIDC connector supports standard OpenID Connect discovery, authorization code flow, and token validation. It works with any identity provider that publishes an OIDC discovery document -- making it suitable for non-standard providers, development/testing identity servers, and custom-built identity systems.
## Use Cases
* **Unify SSO with any OIDC provider** -- Connect identity providers that don't have a dedicated connector, extending SSO to legacy applications through any standards-compliant IdP
* **Rationalize custom identity systems** -- Integrate in-house or niche identity services into a unified orchestration layer, enabling gradual migration to a strategic IdP without rewriting applications
* **Identity resilience with secondary providers** -- Add any OIDC-compliant provider as a failover target, ensuring authentication continuity regardless of which providers are in your Identity Fabric
* **Development and testing** -- Integrate with local identity servers like Dex or mock OIDC providers to validate orchestration policies before deploying to production
## Setup
To create a Generic OIDC Configuration connector in the Maverics Console:
1. Navigate to **Identity Fabric** in the Console sidebar.
2. Click **Create** and select **Generic OIDC Configuration**.
3. Enter a **Name** for the connector -- this is the friendly name that identifies your OIDC integration.
4. Enter the **OIDC Well Known URL** -- the URL that returns OpenID Connect metadata about the authorization server (typically ending in `/.well-known/openid-configuration`). This works with any OIDC-compliant provider.
5. Enter the **OAuth Client ID** -- the client ID of the application registered with your identity provider.
6. Enter the **OAuth Client Secret** -- the client secret associated with the client ID. Use the show/hide toggle to verify the value.
7. Add one or more **Redirect URLs** -- the callback URL(s) where the provider redirects users after authentication. The Maverics OIDC handler will be served on this URL.
8. Optionally add **Logout Callback URLs** -- the URL(s) that the OIDC provider calls after a successful logout.
9. Optionally enter **Scopes** -- space-separated OIDC scopes to request (e.g., `openid profile email`). If left empty, default scopes are used.
10. **Proof Key for Code Exchange (PKCE)** is enabled by default. Disable this toggle only if your provider is not configured to support PKCE.
11. Optionally enable **Offline Access** if you need refresh tokens. When enabled, set your policy's `decision.lifetime` slightly longer than the interval for token refreshing.
12. Optionally configure **Error Handling** rules to redirect users based on errors returned by the IdP during the OIDC callback. See [Callback Error Handling](#callback-error-handling) for details.
13. Click **Save**.
The Generic OIDC Configuration works with any identity provider that publishes a standard OIDC discovery document -- including Keycloak, Dex, IdentityServer, and other custom OIDC implementations. If your provider has a dedicated connector type in the Console (e.g., Okta, Entra ID), prefer using that instead for provider-specific optimizations.
```yaml theme={null}
connectors:
- name: my-idp
type: oidc
oidcWellKnownURL: "https://idp.example.com/.well-known/openid-configuration"
oauthClientID: "{{ env.OIDC_CLIENT_ID }}"
oauthClientSecret:
oauthLoginRedirect:
urls:
- https://app.example.com/oidc/callback
scopes: "openid profile email"
```
## Configuration Reference
| Key | Type | Required | Description |
| --------------------------------- | ------ | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `name` | string | Yes | Unique connector identifier referenced in app policies |
| `type` | string | Yes | Must be `oidc` |
| `oidcWellKnownURL` | string | Yes | OIDC discovery endpoint URL |
| `oauthClientID` | string | Yes | OAuth 2.0 client ID from the identity provider |
| `oauthClientSecret` | string | Conditional | OAuth 2.0 client secret (use secret reference syntax). Required if `oauthClientAssertion` is not configured. |
| `oauthClientAssertion` | object | Conditional | Client assertion config for RFC 7523 private key JWT authentication. Required if `oauthClientSecret` is not configured. See [Client Assertion Authentication](#client-assertion-authentication). |
| `oauthClientAssertion.privateKey` | string | Yes | PEM-encoded RSA private key used to sign the assertion JWT. Use secret reference syntax. |
| `oauthClientAssertion.audience` | string | No | The `aud` claim in the assertion JWT. Defaults to the IdP's token endpoint URL. |
| `oauthLoginRedirect.urls` | list | Yes | Callback URL(s) registered with the identity provider. The Orchestrator selects the URL whose host matches the incoming request. |
| `oauthLogoutRedirect.urls` | list | No | URL(s) called by the identity provider after a successful logout. |
| `scopes` | string | No | Space-separated OAuth scopes (default: `openid profile email`) |
| `tls` | string | No | Named TLS profile for provider communication |
| `errorHandling` | object | No | Configures how IdP errors during the OIDC callback are handled. See [Callback Error Handling](#callback-error-handling) below. |
For the complete field reference including health checks, offline access, and PKCE settings, see [Identity Fabric](/reference/orchestrator/identity-fabric#configuration-reference).
## Client Assertion Authentication
By default, the Generic OIDC connector authenticates to the identity provider using a client secret (`oauthClientSecret`). For providers that require stronger client authentication, you can use **RFC 7523 private key JWT** -- the connector signs a short-lived assertion JWT with an RSA private key instead of sending a shared secret.
Replace `oauthClientSecret` with an `oauthClientAssertion` block:
```yaml theme={null}
connectors:
- name: my-idp
type: oidc
oidcWellKnownURL: https://idp.example.com/.well-known/openid-configuration
oauthClientID: exampleClientID
oauthClientAssertion:
privateKey:
audience: https://idp.example.com
oauthLoginRedirect:
urls:
- https://app.example.com/oidc/callback
oauthLogoutRedirect:
urls:
- https://app.example.com/logout
```
The `privateKey` value should be sourced from a secret provider. See [Secrets Management](/guides/security/secrets-management) for supported reference syntax.
## Callback Error Handling
When an identity provider returns an error during the OIDC callback (e.g., the user forgot their password, cancelled login, or the provider encountered a server error), the Orchestrator can evaluate configurable rules to redirect the user to a specific URL based on the error.
Rules are evaluated in order -- the first matching rule wins. You can match on the `error` or `error_description` callback parameters using exact or substring matching. A default catch-all rule can be included to handle any unmatched errors.
In the connector's **Error Handling** section:
1. Click **Add Rule** to create a new error handling rule.
2. Select a **Match On** value -- either **Error** or **Error Description** -- to choose which OIDC callback parameter to match against.
3. Select a **Match Type** -- either **Contains** (substring match) or **Equals** (exact match).
4. Enter the **Match Value** -- the string to match against the selected callback parameter.
5. Enter the **Redirect URL** -- the URL to redirect the user to when this rule matches.
6. Optionally check **Default** to make a rule the catch-all for any unmatched errors. A default rule does not require Match On, Match Type, or Match Value fields. Only one default rule is allowed.
7. Drag rules to reorder them -- rules are evaluated top to bottom and the first match wins.
8. Click **Save**.
Rules are defined under `errorHandling.onCallbackError`:
```yaml theme={null}
connectors:
- name: my-idp
type: oidc
oidcWellKnownURL: "https://idp.example.com/.well-known/openid-configuration"
oauthClientID: "{{ env.OIDC_CLIENT_ID }}"
oauthClientSecret:
oauthLoginRedirect:
urls:
- https://app.example.com/oidc/callback
errorHandling:
onCallbackError:
- contains: "AADB2C90118"
matchOn: error_description
redirectURL: "https://app.example.com/password-reset"
- equals: server_error
matchOn: error
redirectURL: "https://app.example.com/error"
- default: true
redirectURL: "https://app.example.com/generic-error"
```
### Rule Reference
Each rule in the `onCallbackError` list supports the following fields:
| Key | Type | Required | Description |
| ------------- | ------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `contains` | string | Conditional | Matches when the target field contains this substring. Mutually exclusive with `equals`. Required unless `default` is `true`. |
| `equals` | string | Conditional | Matches when the target field exactly equals this value. Mutually exclusive with `contains`. Required unless `default` is `true`. |
| `matchOn` | string | Conditional | Which callback parameter to match against. Must be `error` or `error_description`. Required unless `default` is `true`. |
| `redirectURL` | string | Yes | The URL to redirect the user to when the rule matches. |
| `default` | boolean | No | When `true`, this rule acts as a catch-all for any error not matched by prior rules. When set, `contains`, `equals`, and `matchOn` must not be defined. Only one default rule is allowed. |
If no rule matches the error and no `default` rule is defined, the Orchestrator falls back to the standard error handling behavior.
## Troubleshooting
* **Verify the `oidcWellKnownURL` is accessible** from the Orchestrator host -- confirm the provider's discovery document returns valid JSON
* **Ensure each URL in `oauthLoginRedirect.urls` matches exactly** what is registered in the identity provider
* **Check that the client secret reference resolves correctly** via your secret provider
## Related Pages
Overview of all identity providers
Generic SAML 2.0 connector
OIDC connector for Microsoft Entra ID
OIDC connector for Okta
# Generic SAML
Source: https://docs.strata.io/reference/orchestrator/identity-fabric/custom-saml
The Generic SAML connector provides a generic SAML 2.0 integration for any SAML-compliant identity provider -- giving you flexibility to connect providers that use the SAML protocol for federation.
**Console terminology:** In the Maverics Console, this section is called
**Identity Fabric**. The YAML configuration uses the `connectors` key to define
identity provider integrations.
## Overview
The Generic SAML connector supports SAML 2.0 SSO profiles including SP-initiated and IdP-initiated flows. It handles SAML assertion parsing, signature validation, and attribute extraction -- making it suitable for government and education SAML federations, legacy SAML systems, and any provider that speaks SAML 2.0.
## Use Cases
* **Unify SSO across non-standard IdPs** -- Connect SAML identity providers that aren't covered by dedicated connectors, bringing them into a single orchestrated sign-on experience across your hybrid environment
* **Government and education federations** -- Integrate with InCommon, eduGAIN, and other SAML-based federation services that require generic SAML 2.0 support
* **Legacy SAML modernization** -- Extend SSO to older identity systems that only support SAML 2.0, without rewriting applications or migrating users
* **IdP resilience for SAML providers** -- Pair with the Continuity connector to enable failover between SAML identity providers, ensuring authentication availability if a primary IdP becomes unreachable
## Setup
To create a Generic SAML connector in the Maverics Console:
1. Navigate to **Identity Fabric** in the Console sidebar.
2. Click **Create** and select **Generic SAML**.
3. Enter a **Name** -- the friendly name for your SAML provider.
4. Enter the **Metadata URL** -- the URL of the IdP's SAML metadata document.
5. Enter the **Consumer Service (ACS) URL** -- the Assertion Consumer Service URL where the IdP sends SAML responses.
6. Enter the **Entity ID** -- the unique identifier for the Orchestrator as the SAML Service Provider.
7. Optionally enter a **Logout Callback URL** for Single Logout (SLO) callback.
8. Optionally enter the **SP Certificate Path** and **SP Private Key Path** for signing SAML requests.
9. Optionally select a **NameID Format** to specify the NameID format used in SAML assertions.
10. Optionally enable **IdP Initiated Login** to allow authentication flows started by the identity provider.
11. Click **Save**.
```yaml maverics.yaml theme={null}
connectors:
- name: saml-idp
type: saml
samlMetadataURL: "https://idp.example.com/metadata"
samlConsumerServiceURL: "https://orch.example.com/saml/callback"
samlEntityID: "https://orch.example.com"
samlNameIDFormat: "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
tls: idp-tls
```
## Configuration Reference
| Key | Type | Required | Description |
| ------------------------ | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `name` | string | Yes | Unique connector identifier referenced by app policies and attribute providers |
| `type` | string | Yes | Must be `saml` |
| `samlMetadataURL` | string | Yes | URL to the IdP's SAML metadata XML -- the Orchestrator fetches this to discover SSO endpoints and signing certificates |
| `samlConsumerServiceURL` | string | Yes | Assertion Consumer Service (ACS) URL where the IdP sends SAML responses |
| `samlEntityID` | string | No | Service Provider entity ID that identifies the Orchestrator to the IdP |
| `samlLogoutCallbackURL` | string | No | Logout callback URL for SAML single logout |
| `samlSPCertPath` | string | No | Path to the SP certificate file for signing SAML requests |
| `samlSPKeyPath` | string | No | Path to the SP private key file for signing SAML requests |
| `samlNameIDFormat` | string | No | Requested NameID format (e.g., `urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress`) |
| `samlIDPInitiatedLogin` | object | No | IdP-initiated login configuration |
| `cache` | string | No | Cache name reference for SAML request data storage |
| `tls` | string | No | Named TLS profile for metadata retrieval and IdP communication |
| `healthCheck` | object | No | Health check monitoring configuration (see [Identity Fabric Configuration Reference](/reference/orchestrator/identity-fabric#configuration-reference)) |
For the complete connector field reference including health check details, see [Identity Fabric Configuration Reference](/reference/orchestrator/identity-fabric#configuration-reference).
## Troubleshooting
* **Verify SAML metadata URL is accessible** -- The Orchestrator fetches the IdP's metadata XML at startup. If the URL is unreachable or returns an error, the connector will fail to initialize. Test the URL with `curl` from the Orchestrator host.
* **Ensure entityID matches the IdP configuration** -- The `samlEntityID` value must match what is configured as the trusted Service Provider on the IdP side. Mismatched entity IDs cause the IdP to reject authentication requests.
* **Check the Assertion Consumer Service URL** -- The `samlConsumerServiceURL` must match the Orchestrator's actual callback endpoint. If behind a load balancer or reverse proxy, use the external-facing URL that the IdP will redirect to.
* **SP signing certificate errors** -- If the IdP requires signed authentication requests, ensure `samlSPCertPath` and `samlSPKeyPath` point to valid PEM files and the key matches the certificate.
## Related Pages
Overview of all identity providers
Complete field reference for all connector types
Generic OpenID Connect connector
IdP failover connector
# CyberArk (OIDC)
Source: https://docs.strata.io/reference/orchestrator/identity-fabric/cyberark
The CyberArk Identity OIDC connector integrates the Maverics Orchestrator with CyberArk Identity using OpenID Connect -- enabling enterprise single sign-on and privileged access management.
**Console terminology:** In the Maverics Console, this section is called
**Identity Fabric**. The YAML configuration uses the `connectors` key to define
identity provider integrations.
## Overview
The CyberArk OIDC connector uses the generic OIDC connector in the Orchestrator configuration. CyberArk Identity exposes a standard OIDC discovery endpoint, so no CyberArk-specific connector type is needed. For SAML-based federation with CyberArk, see [CyberArk (SAML)](/reference/orchestrator/identity-fabric/cyberark-saml).
## Use Cases
* **Privileged access management** -- Extend CyberArk-managed privileged identities to legacy applications that lack native CyberArk support, bridging PAM-controlled sessions with header-based or cookie-based authentication
* **Unify SSO with CyberArk Identity** -- Federate CyberArk Identity authentication across cloud and on-premises applications, creating a seamless SSO experience for organizations that centralize workforce identity in CyberArk
* **Rationalize identity platforms** -- Consolidate authentication onto CyberArk Identity by orchestrating migration from other IdPs, reducing licensing costs while extending privileged access controls
* **Authentication resilience** -- Configure CyberArk as a primary or failover identity provider alongside other IdPs, ensuring continuous access to critical applications and privileged workflows
## Setup
To create a CyberArk OIDC connector in the Maverics Console:
1. Navigate to **Identity Fabric** in the Console sidebar.
2. Click **Create** and select **CyberArk (OIDC)**.
3. Enter a **Name** -- this is the friendly name that identifies your provider.
4. Enter the **OIDC Well Known URL** -- for CyberArk, this follows the pattern `https://{tenant}.id.cyberark.cloud/.well-known/openid-configuration`.
5. Enter the **OAuth Client ID** -- the client ID from your CyberArk Identity application.
6. Enter the **OAuth Client Secret** -- the client secret from your CyberArk Identity application.
7. Under **Redirect URLs**, add the callback URL where CyberArk will redirect after authentication.
8. Optionally configure **Logout Callback URLs** for single logout support.
9. Optionally set **Scopes** (space-separated). Default scopes are typically `openid profile email`.
10. The **PKCE** toggle is enabled by default. Disable it only if your CyberArk application is not configured to support Proof Key for Code Exchange.
11. Optionally enable **Offline Access** for token refresh support (Proxy apps only).
12. Click **Save**.
```yaml maverics.yaml theme={null}
connectors:
- name: cyberark
type: oidc
oidcWellKnownURL: "https://{{ env.CYBERARK_TENANT }}.id.cyberark.cloud/.well-known/openid-configuration"
oauthClientID: "{{ env.CYBERARK_CLIENT_ID }}"
oauthClientSecret:
oauthRedirectURL: "https://app.example.com/oidc/callback"
```
## Configuration Reference
| Key | Type | Required | Description |
| ------------------- | ------ | -------- | ------------------------------------------------------ |
| `name` | string | Yes | Unique connector identifier referenced in app policies |
| `type` | string | Yes | Must be `oidc` |
| `oidcWellKnownURL` | string | Yes | CyberArk OIDC discovery endpoint URL |
| `oauthClientID` | string | Yes | OAuth 2.0 client ID from CyberArk Identity |
| `oauthClientSecret` | string | Yes | OAuth 2.0 client secret (use secret reference syntax) |
| `oauthRedirectURL` | string | Yes | Callback URL registered with the CyberArk application |
| `tls` | string | No | Named TLS profile for provider communication |
For the complete field reference including health checks, offline access, and PKCE settings, see [Identity Fabric](/reference/orchestrator/identity-fabric#configuration-reference).
## Troubleshooting
* **Verify the discovery URL is accessible** from the Orchestrator host -- ensure the CyberArk tenant name is correct
* **Ensure the redirect URL matches exactly** what is registered in CyberArk Identity
* **Check that the client secret reference resolves correctly** via your secret provider
## Related Pages
SAML connector for CyberArk Identity
Overview of all identity providers
Generic OpenID Connect connector
Generic SAML 2.0 connector
# CyberArk (SAML)
Source: https://docs.strata.io/reference/orchestrator/identity-fabric/cyberark-saml
The CyberArk Identity SAML connector integrates the Maverics Orchestrator with CyberArk Identity using SAML 2.0 -- enabling enterprise single sign-on and privileged access management.
**Console terminology:** In the Maverics Console, this section is called
**Identity Fabric**. The YAML configuration uses the `connectors` key to define
identity provider integrations.
## Overview
The CyberArk SAML connector uses the generic SAML connector in the Orchestrator configuration. CyberArk Identity exposes a standard SAML metadata endpoint, so no CyberArk-specific connector type is needed. For OIDC-based federation with CyberArk, see [CyberArk (OIDC)](/reference/orchestrator/identity-fabric/cyberark).
## Use Cases
* **Privileged access management** -- Extend CyberArk-managed identities to applications that lack native CyberArk support, unifying privileged and standard access under a single orchestration layer
* **Unify SSO across CyberArk and other IdPs** -- Federate SAML-based authentication with CyberArk Identity alongside other identity providers, delivering seamless access across cloud and on-premises applications
* **Legacy application modernization** -- Use SAML federation to connect CyberArk Identity with legacy applications that only support SAML or header-based authentication, without rewriting them
* **CyberArk failover with Continuity** -- Pair CyberArk Identity with a backup IdP to maintain authentication availability during CyberArk service disruptions
## Setup
To create a CyberArk SAML connector in the Maverics Console:
1. Navigate to **Identity Fabric** in the Console sidebar.
2. Click **Create** and select **CyberArk (SAML)**.
3. Enter a **Name** -- the friendly name for your CyberArk SAML provider.
4. Enter the **Metadata URL** -- the URL of the CyberArk IdP's SAML metadata document.
5. Enter the **Consumer Service (ACS) URL** -- the Assertion Consumer Service URL where CyberArk sends SAML responses.
6. Enter the **Entity ID** -- the unique identifier for the Orchestrator as the SAML Service Provider.
7. Optionally enter a **Logout Callback URL** for Single Logout (SLO) callback.
8. Optionally enter the **SP Certificate Path** and **SP Private Key Path** for signing SAML requests.
9. Optionally enable **IdP Initiated Login** to allow authentication flows started by CyberArk.
10. Click **Save**.
```yaml maverics.yaml theme={null}
connectors:
- name: cyberark-saml
type: saml
samlMetadataURL: "https://{{ env.CYBERARK_TENANT }}.id.cyberark.cloud/saml2/metadata"
samlConsumerServiceURL: "https://orch.example.com/saml/callback"
samlEntityID: "https://orch.example.com"
```
## Configuration Reference
| Key | Type | Required | Description |
| ------------------------ | ------ | -------- | --------------------------------------------------------- |
| `name` | string | Yes | Unique connector identifier referenced by app policies |
| `type` | string | Yes | Must be `saml` |
| `samlMetadataURL` | string | Yes | URL to the CyberArk SAML metadata XML |
| `samlConsumerServiceURL` | string | Yes | Assertion Consumer Service (ACS) URL for SAML responses |
| `samlEntityID` | string | No | Service Provider entity ID |
| `samlLogoutCallbackURL` | string | No | Logout callback URL for SAML single logout |
| `samlSPCertPath` | string | No | Path to the SP certificate file for signing SAML requests |
| `samlSPKeyPath` | string | No | Path to the SP private key file for signing SAML requests |
| `tls` | string | No | Named TLS profile for metadata retrieval |
For the complete field reference including health checks and IdP-initiated login, see [Identity Fabric](/reference/orchestrator/identity-fabric#configuration-reference).
## Troubleshooting
* **Verify the metadata URL is accessible** from the Orchestrator host -- ensure the CyberArk tenant name is correct
* **Ensure the ACS URL matches exactly** what is registered in CyberArk Identity
* **Check the entity ID** -- the `samlEntityID` must match the Service Provider identifier configured in CyberArk Identity
## Related Pages
OIDC connector for CyberArk Identity
Overview of all identity providers
Generic SAML 2.0 connector
Generic OpenID Connect connector
# Duo (SAML)
Source: https://docs.strata.io/reference/orchestrator/identity-fabric/duo
The Duo Security connector integrates the Maverics Orchestrator with Duo -- enabling SAML-based single sign-on with built-in multi-factor authentication.
**Console terminology:** In the Maverics Console, this section is called
**Identity Fabric**. The YAML configuration uses the `connectors` key to define
identity provider integrations.
## Overview
The Duo Security connector uses SAML 2.0 federation. Duo combines identity verification with multi-factor authentication in a single sign-on flow -- making it well-suited for environments where strong authentication is required at every login.
## Use Cases
* **MFA-integrated SSO** -- Leverage Duo's built-in multi-factor authentication alongside SAML-based single sign-on, adding strong authentication to applications managed by the Orchestrator
* **Unify SSO with Duo MFA for legacy apps** -- Extend Duo's MFA capabilities to legacy and on-prem applications that lack native Duo support, delivering consistent strong authentication across your hybrid environment
* **Strengthen resilience with MFA failover** -- Pair Duo with a secondary IdP through the Continuity connector so authentication continues even if one provider is unavailable, with MFA enforced throughout
* **Consolidate MFA under Duo** -- Route authentication from multiple IdPs through Duo to standardize multi-factor policies, reducing the cost and complexity of managing MFA across separate platforms
## Setup
To create a Duo (SAML) connector in the Maverics Console:
1. Navigate to **Identity Fabric** in the Console sidebar.
2. Click **Create** and select **Duo (SAML)**.
3. Enter a **Name** -- the friendly name for your Duo provider.
4. Enter the **Metadata URL** -- the URL of Duo's SAML metadata document, typically `https://{api-host}/saml2/idp/metadata`.
5. Enter the **Consumer Service (ACS) URL** -- the Assertion Consumer Service URL where Duo sends SAML responses.
6. Enter the **Entity ID** -- the unique identifier for the Orchestrator as the SAML Service Provider.
7. Optionally enter a **Logout Callback URL** for Single Logout (SLO) callback.
8. Optionally enter the **SP Certificate Path** and **SP Private Key Path** for signing SAML requests.
9. Optionally enable **IdP Initiated Login** to allow authentication flows started by Duo.
10. Click **Save**.
```yaml maverics.yaml theme={null}
connectors:
- name: duo
type: saml
samlMetadataURL: "https://{{ env.DUO_HOST }}/saml2/idp/metadata"
samlConsumerServiceURL: "https://orch.example.com/saml/callback"
samlEntityID: "https://orch.example.com"
```
Duo's SAML metadata URL uses the API hostname assigned to your Duo account. You can find this in the Duo Admin Panel under the SAML application configuration.
## Configuration Reference
| Key | Type | Required | Description |
| ------------------------ | ------ | -------- | ------------------------------------------------------------------ |
| `name` | string | Yes | Unique connector identifier referenced by app policies |
| `type` | string | Yes | Must be `saml` |
| `samlMetadataURL` | string | Yes | URL to Duo's SAML metadata XML |
| `samlConsumerServiceURL` | string | Yes | Assertion Consumer Service (ACS) URL for SAML responses |
| `samlEntityID` | string | No | Service Provider entity ID that identifies the Orchestrator to Duo |
| `samlLogoutCallbackURL` | string | No | Logout callback URL for SAML single logout |
| `samlSPCertPath` | string | No | Path to the SP certificate file for signing SAML requests |
| `samlSPKeyPath` | string | No | Path to the SP private key file for signing SAML requests |
| `cache` | string | No | Cache name reference for SAML request data storage |
| `tls` | string | No | Named TLS profile for metadata retrieval and IdP communication |
For the complete field reference including health check details, see [Identity Fabric](/reference/orchestrator/identity-fabric#configuration-reference).
## Troubleshooting
* **Verify the SAML metadata URL is accessible** from the Orchestrator host -- ensure the Duo API hostname is correct
* **Ensure the Entity ID matches the Duo configuration** -- the `samlEntityID` must match what is configured as the trusted Service Provider in the Duo Admin Panel
* **Check the ACS URL** -- the `samlConsumerServiceURL` must match the Orchestrator's callback endpoint. If behind a load balancer, use the external-facing URL.
* **Confirm Duo SAML application is active** -- disabled or draft applications in Duo will not respond to authentication requests
## Related Pages
Overview of all identity providers
Generic SAML 2.0 connector
ADFS connector
IdP failover connector
# Microsoft Entra ID Attribute Provider
Source: https://docs.strata.io/reference/orchestrator/identity-fabric/entra-id-attr
The Microsoft Entra ID Attribute Provider connector retrieves user attributes from Microsoft Entra ID (formerly Microsoft Entra ID) using the Microsoft Graph API -- enriching session claims with directory data beyond what authentication alone provides.
**Console terminology:** In the Maverics Console, this section is called
**Identity Fabric**. The YAML configuration uses the `connectors` key to define
attribute provider integrations.
## Overview
The Entra ID Attribute Provider uses the Microsoft Graph API to look up user profile data, group memberships, and other directory attributes. It shares the same connector type as the [Microsoft Entra ID IdP connector](/reference/orchestrator/identity-fabric/azure-ad), but configured without OIDC authentication fields. This connector is not an identity provider. It does not handle authentication. Instead, it is paired with an IdP connector (such as Okta, ADFS, or Microsoft Entra ID OIDC) to supplement the session with additional attributes from Microsoft Entra ID.
## Use Cases
* **Unified SSO with Entra ID attribute enrichment** -- Enrich sessions with Entra ID profile data (department, job title, manager) so applications receive consistent identity attributes regardless of which IdP handles authentication
* **Cross-IdP authorization with Entra ID groups** -- Query Entra ID group memberships to drive authorization decisions in Orchestrator policies, even when users authenticate through a non-Microsoft IdP like Okta or ADFS
* **Bridge identity data during IdP consolidation** -- During migration away from or toward Entra ID, maintain access to Microsoft directory attributes so applications continue to receive the claims they depend on
* **Multi-directory identity enrichment** -- Combine Entra ID attribute lookups with authentication from any supported IdP, bridging identity data across organizational boundaries such as post-acquisition environments
## Setup
To create a Microsoft Entra ID Attribute Provider connector in the Maverics Console:
1. Navigate to **Identity Fabric** in the Console sidebar.
2. Click **Create** and select **Microsoft Entra ID Attribute Provider**.
3. Enter a **Name** -- this is the friendly name that identifies your provider.
4. Enter the **Microsoft Graph URL** -- this defines the endpoint used to make calls to the Microsoft Graph API. Use `https://graph.microsoft.com/v1.0` for the stable API version.
5. Optionally enter the **OIDC Well Known URL** -- the URL that returns OpenID Connect metadata about the Entra ID authorization server. This follows the pattern `https://login.microsoftonline.com/{tenant-id}/v2.0/.well-known/openid-configuration`.
6. Enter the **OAuth Client ID** -- the client ID of the Maverics application registered in the Entra ID organization.
7. Enter the **OAuth Client Secret** -- the client secret of the Maverics application registered in the Entra ID organization.
8. Click **Save**.
```yaml maverics.yaml theme={null}
connectors:
- name: azure-attr
type: azure
graphURL: "https://graph.microsoft.com/v1.0"
oidcWellKnownURL: "https://login.microsoftonline.com/{{ env.AZURE_TENANT_ID }}/v2.0/.well-known/openid-configuration"
oauthClientID: "{{ env.AZURE_CLIENT_ID }}"
oauthClientSecret:
```
The Entra ID Attribute Provider requires an app registration in the Azure portal with **Microsoft Graph API** permissions. Grant the application `User.Read.All` (or equivalent) permissions so the Orchestrator can query user attributes.
## Configuration Reference
| Key | Type | Required | Description |
| ------------------- | ------ | -------- | ----------------------------------------------------------------------- |
| `name` | string | Yes | Unique connector identifier referenced in app policies |
| `type` | string | Yes | Must be `azure` |
| `graphURL` | string | Yes | Microsoft Graph API endpoint (e.g., `https://graph.microsoft.com/v1.0`) |
| `oidcWellKnownURL` | string | No | OIDC discovery endpoint URL for Entra ID authorization |
| `oauthClientID` | string | Yes | OAuth 2.0 client (application) ID from the Azure portal |
| `oauthClientSecret` | string | Yes | OAuth 2.0 client secret (use secret reference syntax) |
For the complete field reference, see [Identity Fabric](/reference/orchestrator/identity-fabric#configuration-reference).
## Troubleshooting
* **Verify the `graphURL` is reachable** from the Orchestrator host -- the standard endpoint is `https://graph.microsoft.com/v1.0`
* **Ensure the app registration has the correct Graph API permissions** -- without `User.Read.All` or similar scopes, attribute lookups will fail with 403 errors
* **Check that the `oauthClientSecret` reference resolves correctly** via your secret provider -- Entra ID client secrets expire and need periodic rotation
* **Confirm the tenant ID in the `oidcWellKnownURL`** matches the directory where the app registration and target users reside
## Related Pages
OIDC identity provider connector for Microsoft Entra ID
Overview of all identity providers and attribute providers
OIDC connector for Okta -- commonly paired with this attribute provider
OIDC connector for ADFS -- another common pairing for Entra ID attributes
# Microsoft Entra ID (SAML)
Source: https://docs.strata.io/reference/orchestrator/identity-fabric/entra-id-saml
The Microsoft Entra ID (SAML) connector integrates the Maverics Orchestrator with Microsoft Entra ID using the SAML 2.0 protocol -- providing an alternative to the OIDC-based Entra ID connector for environments that require SAML federation.
**Console terminology:** In the Maverics Console, this section is called
**Identity Fabric**. The YAML configuration uses the `connectors` key to define
identity provider integrations.
## Overview
The Microsoft Entra ID (SAML) connector supports SAML 2.0 SSO profiles including SP-initiated and IdP-initiated flows. For most deployments, the [Microsoft Entra ID (OIDC) connector](/reference/orchestrator/identity-fabric/azure-ad) is recommended as the more common integration path. Use the SAML variant when your environment requires SAML-based federation or when integrating with applications that only support SAML assertions.
## Use Cases
* **Unify SSO for SAML-dependent applications** -- Connect to Entra ID via SAML when legacy applications or compliance policies require SAML 2.0 federation instead of OIDC
* **Consolidate IdPs around Entra ID** -- Route authentication from multiple legacy IdPs to Entra ID using SAML, reducing the number of identity platforms and associated licensing costs
* **Multi-protocol orchestration** -- Combine Entra ID SAML with other SAML or OIDC connectors to deliver unified access across hybrid environments without rewriting applications
* **Entra ID failover with Continuity** -- Pair Entra ID SAML with a secondary IdP to maintain authentication availability during Entra ID service disruptions
## Setup
To create a Microsoft Entra ID (SAML) connector in the Maverics Console:
1. Navigate to **Identity Fabric** in the Console sidebar.
2. Click **Create** and select **Microsoft Entra ID (SAML)**.
The Console also offers **Microsoft Entra ID (OIDC)** for OpenID Connect-based integration, which is the more common option. See the [Entra ID (OIDC) page](/reference/orchestrator/identity-fabric/azure-ad) for details.
3. Enter a **Name** -- the friendly name for your Entra ID SAML provider.
4. Enter the **Metadata URL** -- the URL of the Entra ID SAML metadata document (e.g., `https://login.microsoftonline.com/{tenant-id}/federationmetadata/2007-06/federationmetadata.xml`).
5. Enter the **Consumer Service (ACS) URL** -- the Assertion Consumer Service URL where Entra ID sends SAML responses.
6. Enter the **Entity ID** -- the unique identifier for the Orchestrator as the SAML Service Provider.
7. Optionally enter a **Logout Callback URL** for Single Logout (SLO) callback.
8. Optionally enter the **SP Certificate Path** and **SP Private Key Path** for signing SAML requests.
9. Optionally enable **IdP Initiated Login** to allow authentication flows started by Entra ID.
10. Click **Save**.
```yaml maverics.yaml theme={null}
connectors:
- name: entra-id-saml
type: saml
samlMetadataURL: "https://login.microsoftonline.com/{{ env.AZURE_TENANT_ID }}/federationmetadata/2007-06/federationmetadata.xml"
samlConsumerServiceURL: "https://orch.example.com/saml/callback"
samlEntityID: "https://orch.example.com"
tls: entra-tls
```
## Configuration Reference
| Key | Type | Required | Description |
| ------------------------ | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `name` | string | Yes | Unique connector identifier referenced by app policies and attribute providers |
| `type` | string | Yes | Must be `saml` |
| `samlMetadataURL` | string | Yes | URL to the Entra ID SAML federation metadata XML |
| `samlConsumerServiceURL` | string | Yes | Assertion Consumer Service (ACS) URL where Entra ID sends SAML responses |
| `samlEntityID` | string | No | Service Provider entity ID that identifies the Orchestrator to Entra ID |
| `samlLogoutCallbackURL` | string | No | Logout callback URL for SAML single logout |
| `samlSPCertPath` | string | No | Path to the SP certificate file for signing SAML requests |
| `samlSPKeyPath` | string | No | Path to the SP private key file for signing SAML requests |
| `samlIDPInitiatedLogin` | object | No | IdP-initiated login configuration |
| `cache` | string | No | Cache name reference for SAML request data storage |
| `tls` | string | No | Named TLS profile for metadata retrieval and IdP communication |
| `healthCheck` | object | No | Health check monitoring configuration (see [Identity Fabric Configuration Reference](/reference/orchestrator/identity-fabric#configuration-reference)) |
For the complete connector field reference including health check details, see [Identity Fabric Configuration Reference](/reference/orchestrator/identity-fabric#configuration-reference).
## Troubleshooting
* **Verify the Entra ID metadata URL is accessible** -- The Orchestrator fetches the federation metadata XML at startup. Replace `{tenant-id}` with your Microsoft Entra ID directory (tenant) ID from the Azure portal.
* **Ensure the entity ID matches the Entra ID enterprise application** -- The `samlEntityID` value must match the Identifier (Entity ID) configured in the Entra ID enterprise application's SAML configuration.
* **Check the Assertion Consumer Service URL** -- The `samlConsumerServiceURL` must match the Reply URL (Assertion Consumer Service URL) configured in the Entra ID enterprise application. If behind a load balancer, use the external-facing URL.
* **SP signing certificate errors** -- If the Entra ID application requires signed authentication requests, ensure `samlSPCertPath` and `samlSPKeyPath` point to valid PEM files and the key matches the certificate.
## Related Pages
OIDC-based Entra ID connector (recommended for most deployments)
Generic SAML 2.0 connector
Overview of all identity providers
IdP failover connector
# Google Workspace (OIDC)
Source: https://docs.strata.io/reference/orchestrator/identity-fabric/google-workspace
Google Workspace does not have a dedicated connector type. Use the generic `oidc` connector type with Google's OIDC discovery endpoint.
The Maverics Orchestrator integrates with Google Workspace identity using the generic OIDC connector -- enabling single sign-on for applications that need to authenticate Google Workspace users.
**Console terminology:** In the Maverics Console, this section is called
**Identity Fabric**. The YAML configuration uses the `connectors` key to define
identity provider integrations.
## Overview
Google Workspace supports standard OpenID Connect, so you can connect it to the Orchestrator using the generic OIDC connector with Google's well-known discovery URL. This approach works for organizations that use Google Workspace as their primary identity provider or for hybrid environments that combine Google and other identity platforms.
## Use Cases
* **Unify SSO for Google-first organizations** -- Extend Google Workspace authentication to legacy and enterprise applications that don't support Google login natively, creating a single sign-on experience across your entire app portfolio
* **Rationalize duplicate IdPs** -- Consolidate identity platforms by routing Google Workspace users to applications previously managed by a separate IdP, reducing licensing and operational overhead
* **Hybrid Google/Microsoft environments** -- Orchestrate authentication across Google Workspace and Microsoft Entra ID from a single point, unifying access for organizations running both platforms after mergers or acquisitions
## Setup
The Console does not have a dedicated Google Workspace option. Use **Generic OIDC
Configuration** since Google Workspace supports standard OpenID Connect.
To configure Google Workspace as an identity provider in the Maverics Console:
1. Navigate to **Identity Fabric** in the Console sidebar.
2. Click **Create** and select **Generic OIDC Configuration**.
3. Enter a **Name** for the connector (e.g., `Google Workspace`).
4. Enter the **OIDC Well Known URL**: `https://accounts.google.com/.well-known/openid-configuration`
5. Enter the **OAuth Client ID** from the Google Cloud Console (APIs & Services > Credentials).
6. Enter the **OAuth Client Secret** from the Google Cloud Console.
7. Add one or more **Redirect URLs** -- the callback URL where Google redirects after authentication. This must match an Authorized redirect URI in the Google Cloud Console.
8. Optionally add **Logout Callback URLs** for single logout.
9. Optionally enter **Scopes** (e.g., `openid profile email`). Separate multiple scopes with a space.
10. **Proof Key for Code Exchange (PKCE)** is enabled by default. Google supports PKCE, so leave this on.
11. Optionally enable **Offline Access** if you need refresh tokens for ongoing attribute retrieval.
12. Click **Save**.
```yaml theme={null}
connectors:
- name: google
type: oidc
oidcWellKnownURL: "https://accounts.google.com/.well-known/openid-configuration"
oauthClientID: "{{ env.GOOGLE_CLIENT_ID }}"
oauthClientSecret:
oauthLoginRedirect:
urls:
- https://app.example.com/oidc/callback
scopes: "openid profile email"
```
OAuth credentials for Google Workspace must be created in the Google Cloud Console under APIs & Services > Credentials. Create an "OAuth 2.0 Client ID" of type "Web application" and add each URL from `oauthLoginRedirect.urls` to the Authorized redirect URIs.
## Configuration Reference
| Key | Type | Required | Description |
| -------------------------- | ------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `name` | string | Yes | Unique connector identifier referenced in app policies |
| `type` | string | Yes | Must be `oidc` (Google uses the generic OIDC connector) |
| `oidcWellKnownURL` | string | Yes | Google's OIDC discovery endpoint: `https://accounts.google.com/.well-known/openid-configuration` |
| `oauthClientID` | string | Yes | OAuth 2.0 client ID from the Google Cloud Console |
| `oauthClientSecret` | string | Yes | OAuth 2.0 client secret (use secret reference syntax) |
| `oauthLoginRedirect.urls` | list | Yes | Callback URL(s) registered in the Google Cloud Console credentials. The Orchestrator selects the URL whose host matches the incoming request. |
| `oauthLogoutRedirect.urls` | list | No | URL(s) called by Google after a successful logout. |
| `scopes` | string | No | Space-separated OAuth scopes (default: `openid profile email`) |
| `tls` | string | No | Named TLS profile for provider communication |
For the complete field reference including health checks, offline access, and PKCE settings, see [Identity Fabric](/reference/orchestrator/identity-fabric#configuration-reference).
## Troubleshooting
* **Verify the OAuth consent screen** is configured in the Google Cloud Console -- the consent screen must be published or in test mode with authorized test users
* **Ensure each URL in `oauthLoginRedirect.urls` matches exactly** what is registered in the Google Cloud Console under Authorized redirect URIs
* **Check that the client secret reference resolves correctly** via your secret provider
## Related Pages
Overview of all identity providers
Generic OpenID Connect connector
OIDC connector for Microsoft Entra ID
OIDC connector for Okta
# HYPR
Source: https://docs.strata.io/reference/orchestrator/identity-fabric/hypr
The HYPR connector integrates the Maverics Orchestrator with HYPR passwordless authentication -- enabling phishing-resistant, device-based authentication for your applications.
**Console terminology:** In the Maverics Console, this section is called
**Identity Fabric**. The YAML configuration uses the `connectors` key to define
identity provider integrations.
## Overview
The HYPR connector enables passwordless authentication using the HYPR platform. It supports device-based authentication and QR code flows -- allowing users to authenticate without passwords using their registered mobile device. The Orchestrator uses OIDC internally, but the Console exposes HYPR-specific configuration fields for the HYPR domain, application, and access token.
## Use Cases
* **Passwordless SSO across legacy and modern apps** -- Replace passwords with HYPR device-based authentication and extend it to applications that lack native HYPR support, unifying passwordless SSO through the Orchestrator
* **Phishing-resistant MFA for IdP consolidation** -- Add strong, phishing-resistant multi-factor authentication as part of an IdP rationalization strategy, strengthening security posture while reducing reliance on legacy MFA solutions
* **QR code authentication for shared workstations** -- Enable users to scan a QR code with the HYPR mobile app for fast, secure authentication on shared or kiosk devices where passwords are impractical
* **Zero-trust authentication upgrade** -- Layer HYPR passwordless authentication into existing identity infrastructure through the Orchestrator, upgrading security without replacing or reconfiguring individual applications
## Setup
To create a HYPR connector in the Maverics Console:
1. Navigate to **Identity Fabric** in the Console sidebar.
2. Click **Create** and select **HYPR**.
3. Enter a **Name** -- this is the friendly name that identifies your provider.
4. Enter the **HYPR Domain** -- the base domain of your HYPR account (e.g., `your-org.hypr.com`).
5. Enter the **HYPR App ID** -- the name of the application as defined in the HYPR Control Center.
6. Enter the **Access Token** -- an access token configured in the HYPR Control Center. Use the show/hide toggle to verify the value.
7. Optionally enable **QR Authentication** to display a QR code that users can scan with the HYPR mobile app. This toggle is off by default.
8. Optionally set a **Status Check URL** to monitor the HYPR service status.
9. Optionally set a **Login URL** to define a custom endpoint for posting user credentials.
10. Optionally upload a **Custom Login HTML** file to customize the login page displayed to users.
11. Optionally upload a **Custom Interstitial HTML** file to customize the interstitial page displayed during authentication.
12. Optionally upload a **Custom Error HTML** file to customize the error page displayed when authentication fails.
13. Click **Save**.
```yaml maverics.yaml theme={null}
connectors:
- name: hypr
type: hypr
hyprDomain: "https://{{ env.HYPR_DOMAIN }}"
hyprAppID: "{{ env.HYPR_APP_ID }}"
accessToken:
qrAuthentication:
enabled: true
statusCheckURL: /.hypr-status-check
loginURL: /.hypr-login
customLoginHTML: /etc/maverics/html/login.html
customInterstitialHTML: /etc/maverics/html/interstitial.html
customErrorHTML: /etc/maverics/html/error.html
```
Custom HTML files can be loaded from the local filesystem or from the
deployment configuration bundle. When using the Maverics Console, upload
custom HTML files directly through the connector settings.
## Configuration Reference
| Key | Type | Required | Description |
| -------------------------- | ------- | -------- | ----------------------------------------------------------------------- |
| `name` | string | Yes | Unique connector identifier referenced in app policies |
| `type` | string | Yes | Must be `hypr` |
| `hyprDomain` | string | Yes | The base domain of the HYPR account (e.g., `https://your-org.hypr.com`) |
| `hyprAppID` | string | Yes | The application name as defined in the HYPR Control Center |
| `accessToken` | string | Yes | Access token from the HYPR Control Center (use secret reference syntax) |
| `statusCheckURL` | string | No | URL for polling authentication status (default: `/.hypr-status-check`) |
| `loginURL` | string | No | Custom endpoint for the HYPR login form (default: `/.hypr-login`) |
| `mfaOnly` | boolean | No | Use HYPR for MFA only (no standalone login handler) |
| `qrAuthentication.enabled` | boolean | No | Enable QR code authentication flow |
| `customLoginHTML` | string | No | Path to a custom login page HTML template |
| `customInterstitialHTML` | string | No | Path to a custom interstitial page HTML template |
| `customErrorHTML` | string | No | Path to a custom error page HTML template |
| `tls` | string | No | Named TLS profile for communication with the HYPR domain |
For the complete field reference, see [Identity Fabric](/reference/orchestrator/identity-fabric#configuration-reference).
## Custom HTML Pages
The HYPR connector serves three pages during the authentication flow: a **login page** where users enter their username, an **interstitial page** displayed while the user responds to the HYPR prompt on their device, and an **error page** displayed when authentication fails. You can customize each page by providing your own HTML templates.
Custom HTML templates are Go [`html/template`](https://pkg.go.dev/html/template) files. The Orchestrator injects template values at render time that you can reference using `{{ "{{" }} .FieldName {{ "}}" }}` syntax.
### Template Values
The following template values are available in custom HTML pages:
| Value | Available In | Description |
| --------------------------------------- | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `{{ "{{" }} .LoginURL {{ "}}" }}` | Login, Error | The URL for the login form action and retry links |
| `{{ "{{" }} .RedirectURL {{ "}}" }}` | Login, Interstitial | The originally requested URL -- include as a hidden form field so the user is redirected after login |
| `{{ "{{" }} .StatusCheckURL {{ "}}" }}` | Interstitial | The URL the page should poll to check if the user has completed authentication on their device. Returns plain text: `COMPLETED` when successful, `CANCELED` when the user declines |
| `{{ "{{" }} .QRCodeImg {{ "}}" }}` | Interstitial | Base64-encoded QR code image for scanning with the HYPR mobile app (only populated when `qrAuthentication.enabled` is `true`) |
| `{{ "{{" }} .QRDynamicLink {{ "}}" }}` | Interstitial | A dynamic link that opens the HYPR mobile app directly -- serves as a fallback when scanning the QR code fails (only populated when `qrAuthentication.enabled` is `true`) |
| `{{ "{{" }} .QRFallbackCode {{ "}}" }}` | Interstitial | A fallback code for HYPR authentication when QR scanning is not available (only populated when `qrAuthentication.enabled` is `true`) |
| `{{ "{{" }} .Error {{ "}}" }}` | Error | The error message describing why authentication failed |
### Examples
This template provides a branded login page where users enter their username to initiate HYPR
passwordless authentication. The form posts to `{{ .LoginURL }}` and passes `{{ .RedirectURL }}`
as a hidden field so the user returns to their original destination after login.
```html login.html theme={null}
Login
Sign In
```
This template displays a waiting screen while the user authenticates on their HYPR mobile device.
It uses JavaScript to poll the status check URL and automatically redirects the user once
authentication completes. A dynamic link fallback is provided for users who cannot scan the QR code.
```html interstitial.html theme={null}
Authenticating
Waiting for Authentication
Please approve the login request on your HYPR mobile app.
```
This template displays a user-friendly error message when HYPR authentication fails. It renders
the error message provided by the Orchestrator and gives the user an option to retry.
```html error.html theme={null}
Authentication Error
```
## Troubleshooting
* **Verify the HYPR domain is accessible** from the Orchestrator host -- ensure the domain is correct and reachable
* **Ensure the App ID matches exactly** what is configured in the HYPR Control Center -- mismatched app IDs cause authentication failures
* **Check that the access token is valid** -- expired or revoked tokens will prevent the connector from communicating with HYPR
* **QR code not displaying** -- confirm that the QR Authentication toggle is enabled in the Console or that the equivalent setting is configured in YAML
## Related Pages
Overview of all identity providers
Generic OpenID Connect connector
OIDC connector for Okta
OIDC connector for Microsoft Entra ID
# Keycloak (OIDC)
Source: https://docs.strata.io/reference/orchestrator/identity-fabric/keycloak
The Keycloak connector integrates the Maverics Orchestrator with Keycloak -- enabling OIDC-based single sign-on using the open-source identity platform.
**Console terminology:** In the Maverics Console, this section is called
**Identity Fabric**. The YAML configuration uses the `connectors` key to define
identity provider integrations.
## Overview
The Keycloak connector uses OpenID Connect. Keycloak publishes a standard OIDC discovery endpoint per realm, making it straightforward to integrate with the Orchestrator -- whether Keycloak is self-hosted or running in a managed environment.
## Use Cases
* **Unify SSO with open-source identity** -- Extend Keycloak authentication to legacy and enterprise applications, delivering seamless SSO for organizations that prefer open-source identity infrastructure
* **Rationalize commercial IdP costs** -- Use Keycloak as a cost-effective replacement for commercial identity platforms, orchestrating gradual migration without disrupting application access
* **Self-hosted identity resilience** -- Deploy Keycloak as a self-hosted failover IdP alongside a primary SaaS provider, ensuring authentication continuity even during cloud provider outages
* **On-premises and private-cloud identity** -- Connect to Keycloak deployments running in private environments where a SaaS IdP is not an option, bridging air-gapped or regulated infrastructure with modern applications
## Setup
To create a Keycloak (OIDC) connector in the Maverics Console:
1. Navigate to **Identity Fabric** in the Console sidebar.
2. Click **Create** and select **Keycloak (OIDC)**.
3. Enter a **Name** -- this is the friendly name that identifies your provider.
4. Enter the **OIDC Well Known URL** -- for Keycloak, this follows the pattern `https://{host}/realms/{realm}/.well-known/openid-configuration`.
5. Enter the **OAuth Client ID** -- the client ID of the Maverics application registered in your Keycloak realm.
6. Enter the **OAuth Client Secret** -- the client secret from the Keycloak client configuration.
7. Under **Redirect URLs**, add the callback URL where Keycloak will redirect after authentication. This URL must match the Valid Redirect URIs configured in your Keycloak client.
8. Optionally configure **Logout Callback URLs** for single logout support.
9. Optionally set **Scopes** (space-separated). Default scopes are typically `openid profile email`.
10. The **PKCE** toggle is enabled by default. Disable it only if your Keycloak client is not configured to support Proof Key for Code Exchange.
11. Optionally enable **Offline Access** for token refresh support (Proxy apps only).
12. Click **Save**.
```yaml maverics.yaml theme={null}
connectors:
- name: keycloak
type: oidc
oidcWellKnownURL: "https://{{ env.KEYCLOAK_HOST }}/realms/{{ env.KEYCLOAK_REALM }}/.well-known/openid-configuration"
oauthClientID: "{{ env.KEYCLOAK_CLIENT_ID }}"
oauthClientSecret:
oauthLoginRedirect:
urls:
- https://app.example.com/oidc/callback
scopes: "openid profile email"
```
Keycloak's well-known URL is realm-specific. Make sure to include the correct realm name in the path: `/realms/{realm}/.well-known/openid-configuration`.
## Configuration Reference
| Key | Type | Required | Description |
| -------------------------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `name` | string | Yes | Unique connector identifier referenced in app policies |
| `type` | string | Yes | Must be `oidc` |
| `oidcWellKnownURL` | string | Yes | Keycloak OIDC discovery endpoint URL (realm-specific) |
| `oauthClientID` | string | Yes | OAuth 2.0 client ID from the Keycloak admin console |
| `oauthClientSecret` | string | Yes | OAuth 2.0 client secret (use secret reference syntax) |
| `oauthLoginRedirect.urls` | list | Yes | Callback URL(s) registered with the Keycloak client. The Orchestrator selects the URL whose host matches the incoming request. |
| `oauthLogoutRedirect.urls` | list | No | URL(s) called by Keycloak after a successful logout. |
| `scopes` | string | No | Space-separated OAuth scopes (default: `openid profile email`) |
| `tls` | string | No | Named TLS profile for provider communication |
For the complete field reference including health checks, offline access, and PKCE settings, see [Identity Fabric](/reference/orchestrator/identity-fabric#configuration-reference).
## Troubleshooting
* **Verify the well-known URL is accessible** from the Orchestrator host -- ensure the Keycloak host and realm name are correct
* **Ensure each URL in `oauthLoginRedirect.urls` matches exactly** what is registered in the Keycloak client under Valid Redirect URIs
* **Check that the client secret reference resolves correctly** via your secret provider
* **Confirm the Keycloak realm is active** -- disabled or misconfigured realms will cause OIDC discovery to fail
## Related Pages
Overview of all identity providers
Generic OpenID Connect connector
OIDC connector for Okta
OIDC connector for Microsoft Entra ID
# LDAP Authentication
Source: https://docs.strata.io/reference/orchestrator/identity-fabric/ldap
The LDAP Authentication connector integrates the Maverics Orchestrator with LDAP-based directory services -- enabling user authentication via LDAP bind operations. For attribute-only lookups without authentication, see [LDAP Attribute Provider](/reference/orchestrator/identity-fabric/ldap-attr). For Microsoft Active Directory environments, see the dedicated [Active Directory connector](/reference/orchestrator/identity-fabric/activedirectory).
**Console terminology:** In the Maverics Console, this section is called
**Identity Fabric**. The YAML configuration uses the `connectors` key to define
identity provider integrations.
## Overview
The LDAP Authentication connector supports both LDAP and LDAPS (LDAP over TLS) protocols for secure directory integration. It authenticates end users via LDAP bind operations against the directory. For attribute-only lookups without authentication, see the [LDAP Attribute Provider](/reference/orchestrator/identity-fabric/ldap-attr).
## Use Cases
* **Legacy app SSO with on-premises directories** -- Extend single sign-on to applications that authenticate against LDAP directories, without rewriting the application or migrating users out of the directory
* **IdP consolidation for LDAP-dependent apps** -- Route authentication through the Orchestrator so LDAP-bound applications can participate in a unified authentication layer, reducing the need for standalone LDAP integrations per app
* **Hybrid identity bridge** -- Combine LDAP bind authentication with cloud IdP sessions so users in on-premises directories can access both legacy and modern applications through a single login experience
* **Combined authentication and attribute retrieval** -- Authenticate users and retrieve directory attributes (group memberships, email, department) in a single connector for header injection or policy evaluation
## Setup
To create an LDAP Authentication connector in the Maverics Console:
**Settings**
1. Navigate to **Identity Fabric** in the Console sidebar.
2. Click **Create** and select **LDAP Authentication**.
3. Enter a **Name** for the connector.
4. Enter the **URL** of the LDAP server (e.g., `ldaps://ldap.example.com:636`).
5. Enter the **Service Account Username** (bind DN used to connect to the server).
6. Enter the **Service Account Password**.
7. Enter the **Base DN** for LDAP searches (e.g., `dc=example,dc=com`).
8. Enter the **Username Search Key** -- the attribute used to filter on during query and bind operations (e.g., `uid` for OpenLDAP, `sAMAccountName` for AD).
9. Optionally select an **Authentication Search Scope** from the dropdown to control the search depth (e.g., `wholeSubtree`).
10. Click **Save**.
**Template and Assets**
To configure a custom login page with localization:
1. In the connector settings, scroll to the **Template and Assets** section.
2. Upload a **Template File** -- an HTML file using Go Template syntax that renders the login form (e.g., `ldap-login.html`).
3. Under **Methods**, configure the language parsing method:
* **Parsing Method Type** -- How the Orchestrator determines the user's language. Options include `http.request.header` (from the `Accept-Language` header) or `http.request.query` (from a URL query parameter).
* **Parsing Method Name** -- The specific header or query parameter name to read the language from (e.g., `Accept-Language` for headers, or `ui_local` for a query parameter).
4. Under **Localization**, add one or more language entries:
* **Language** -- A BCP 47 language tag (e.g., `en`, `fr`, `es`).
* Upload the corresponding JSON localization file for each language.
5. Click **Save**.
```yaml maverics.yaml theme={null}
connectors:
- name: ldap
type: ldap
url:
- "ldaps://ldap.example.com:636"
serviceAccountUsername: "cn=admin,dc=example,dc=com"
serviceAccountPassword:
baseDN: "dc=example,dc=com"
usernameSearchKey: uid
enableAuthentication: true
authenticationSearchScope: wholeSubtree
loginURL: /.ldap-login
customLogin:
templateFile: /etc/maverics/ldap-login.html
parseLanguageFrom:
type: http.request.header
name: Accept-Language
localization:
en: /etc/maverics/en.json
fr: /etc/maverics/fr.json
userAttributes:
- cn
- email
- memberOf
attributeMapping:
email: mail
name: cn
tls: ldap-tls
```
## Configuration Reference
| Key | Type | Required | Description |
| ------------------------------------ | --------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `name` | string | Yes | Unique connector identifier referenced by app policies and attribute providers |
| `type` | string | Yes | Must be `ldap` |
| `url` | string\[] | Yes | LDAP server URLs -- supports `ldap://` (port 389) and `ldaps://` (port 636); multiple URLs enable failover |
| `serviceAccountUsername` | string | Yes | Bind DN for the service account (e.g., `cn=admin,dc=example,dc=com`) |
| `serviceAccountPassword` | string | Yes | Service account password -- use secret reference syntax `` |
| `baseDN` | string | Yes | Base DN for LDAP searches (e.g., `dc=example,dc=com`) |
| `usernameSearchKey` | string | No | LDAP attribute used for username lookup (e.g., `uid` for OpenLDAP, `sAMAccountName` for AD) |
| `userRDNKey` | string | No | Relative Distinguished Name key for user entries |
| `enableAuthentication` | boolean | No | Enable LDAP bind authentication for end users |
| `loginURL` | string | No | Custom endpoint for posting user credentials (default: `/.ldap-login`) |
| `authenticationSearchScope` | string | No | LDAP search scope for authentication queries (e.g., `wholeSubtree`, `singleLevel`, `baseObject`) |
| `customLogin.templateFile` | string | No | Path to a custom HTML login form template using Go Template syntax |
| `customLogin.parseLanguageFrom.type` | string | No | How to determine the user's language -- `http.request.header` (from a request header) or `http.request.query` (from a URL query parameter) |
| `customLogin.parseLanguageFrom.name` | string | No | The header or query parameter name to read the language from (e.g., `Accept-Language` or `ui_local`) |
| `customLogin.localization` | map | No | Map of BCP 47 language tags to localization file paths (e.g., `en: /etc/maverics/en.json`) |
| `userAttributes` | string\[] | No | LDAP attributes to retrieve during searches (e.g., `["cn", "mail", "memberOf"]`) |
| `objectClasses` | string\[] | No | Object classes for the LDAP search filter (e.g., `["inetOrgPerson"]`) |
| `attributeMapping` | map | No | Map Orchestrator attribute names to LDAP attribute names (e.g., `email: "mail"`) |
| `attributeDelimiter` | string | No | Delimiter for multi-valued LDAP attributes (default: `","`) |
| `tls` | string | No | Named TLS profile for LDAP connection |
| `healthCheck` | object | No | Health check monitoring configuration (see [Identity Fabric Configuration Reference](/reference/orchestrator/identity-fabric#configuration-reference)) |
For the complete connector field reference including health check details, see [Identity Fabric Configuration Reference](/reference/orchestrator/identity-fabric#configuration-reference).
The LDAP connector supports `attributeMapping` to translate between LDAP attribute names and Orchestrator attribute names. For example, mapping `email: "mail"` allows you to reference the attribute as `ldap.email` in header templates and policy rules, even though the LDAP directory stores it as `mail`. OIDC-based connectors do not have this field -- they use claims directly from the OIDC token.
## Custom Login Page
When `customLogin.templateFile` is configured, the Orchestrator serves a custom HTML page for LDAP authentication instead of the default login form. The template file uses [Go Template](https://pkg.go.dev/html/template) syntax with the following variables:
| Variable | Type | Description |
| --------------- | ------ | ---------------------------------------------------------------------------------------------------- |
| `.LoginURL` | string | The URL the form must POST credentials to |
| `.RedirectURL` | string | The originally requested URL -- include as a hidden form field so the user is redirected after login |
| `.Error` | string | An error message if the previous login attempt failed (empty on first load) |
| `.Language` | string | The resolved BCP 47 language tag for the current request |
| `.Localization` | object | The parsed localization data from the JSON file matching the current language |
The login form must submit a `POST` request to `{{ .LoginURL }}` with the following form fields:
* `username` -- the user's login name
* `password` -- the user's password
* `redirectURL` -- the value of `{{ .RedirectURL }}`
**Example template:**
```html ldap-login.html theme={null}
{{ .Localization.title }}
{{ .Localization.title }}
{{ if .Error }}
{{ .Localization.error }}
{{ end }}
```
## Localization
The custom login page supports standards-based language localization using [BCP 47](https://www.rfc-editor.org/info/bcp47) language tags. The Orchestrator determines the user's preferred language and loads the corresponding localization file, making its contents available as `.Localization` in the Go Template.
### Language Detection
The `customLogin.parseLanguageFrom` block controls how the Orchestrator determines the user's preferred language:
* **`http.request.header`** -- Parses the language from an HTTP request header. Set `name` to `Accept-Language` to use the browser's default language preference.
* **`http.request.query`** -- Parses the language from a URL query parameter. Set `name` to the query parameter name (e.g., `ui_local` for URLs like `?ui_local=fr`).
If the detected language does not match any configured localization, the Orchestrator falls back to the first localization entry.
### Localization File Format
Each localization file is a JSON object with key-value pairs. The keys are referenced in the Go Template as fields on `.Localization`:
```json en.json theme={null}
{
"title": "Login",
"username": "Username",
"password": "Password",
"submit": "Sign In",
"error": "Invalid username or password. Please try again."
}
```
```json fr.json theme={null}
{
"title": "Connexion",
"username": "Nom d'utilisateur",
"password": "Mot de passe",
"submit": "Se connecter",
"error": "Nom d'utilisateur ou mot de passe invalide. Veuillez réessayer."
}
```
Reference localization values in the template using `{{ .Localization. }}` (e.g., `{{ .Localization.title }}`).
## Troubleshooting
* **Test LDAP connectivity from the Orchestrator host** -- Use `ldapsearch` or a similar tool to verify the Orchestrator can reach the LDAP server on the configured port. Network firewalls or DNS issues are common causes of connection failures.
* **Verify the service account has read permissions on the baseDN** -- The bind DN specified in `serviceAccountUsername` must have sufficient permissions to search the `baseDN` subtree and read the attributes listed in `userAttributes`.
* **For LDAPS, ensure the TLS profile includes the correct CA certificate** -- If the LDAP server uses a private CA, the TLS profile referenced by the `tls` field must include the CA certificate via `caFile`. Self-signed certificates require `insecureSkipVerify: true` (not recommended for production).
* **Check attribute names in mapping** -- LDAP attribute names are case-insensitive in the protocol but must match the directory schema. Common sources of confusion: `mail` vs `email`, `cn` vs `commonName`, `sAMAccountName` vs `uid`.
* **Custom login page not rendering** -- Verify that the `customLogin.templateFile` path is correct and the file is readable by the Orchestrator process. Check Orchestrator logs for template parsing errors.
* **Localization not switching languages** -- Confirm that the `parseLanguageFrom.type` and `parseLanguageFrom.name` values match how your application sends language preferences. Verify the BCP 47 tags in the `localization` map match the tags sent by the client.
## Related Pages
LDAP attribute lookups without authentication
LDAP-based connector optimized for Active Directory environments
Overview of all identity providers
IdP failover connector
# LDAP Attribute Provider
Source: https://docs.strata.io/reference/orchestrator/identity-fabric/ldap-attr
The LDAP Attribute Provider connector integrates the Maverics Orchestrator with LDAP-based directory services for attribute lookups -- retrieving user attributes for header injection, claim enrichment, or authorization decisions without performing LDAP bind authentication.
**Console terminology:** In the Maverics Console, this section is called
**Identity Fabric**. The YAML configuration uses the `connectors` key to define
identity provider integrations.
## Overview
The LDAP Attribute Provider functions as a read-only attribute source. Unlike the [LDAP Authentication](/reference/orchestrator/identity-fabric/ldap) connector, the attribute provider does not authenticate users -- it retrieves user attributes from the directory using a service account. This is useful when authentication is handled by a separate identity provider (e.g., OIDC or SAML) and you need to enrich the user's session with directory attributes.
## Use Cases
* **Unified SSO with LDAP-sourced attributes** -- Enrich cloud IdP sessions with on-premises directory data (department, title, group memberships) so applications receive consistent headers and claims regardless of where authentication happens
* **Authorization from directory group memberships** -- Retrieve LDAP group memberships to drive fine-grained authorization decisions in Orchestrator policies, bridging access control between legacy directories and modern apps
* **Cross-directory identity enrichment** -- Combine OIDC or SAML authentication from one provider with attribute lookups from an LDAP directory, enabling applications to access identity data that spans multiple systems
* **Simplify IdP migration with attribute continuity** -- During IdP consolidation, maintain access to on-premises directory attributes even after shifting authentication to a cloud provider
## Setup
To create an LDAP Attribute Provider connector in the Maverics Console:
1. Navigate to **Identity Fabric** in the Console sidebar.
2. Click **Create** and select **LDAP Attribute Provider**.
3. Enter a **Name** for the connector.
4. Enter the **URL** of the LDAP server (e.g., `ldaps://ldap.example.com:636`).
5. Enter the **Base DN** for LDAP searches (e.g., `dc=example,dc=com`).
6. Enter the **Service Account Username** (bind DN used to connect to the server).
7. Enter the **Service Account Password**.
8. Optionally set an **Attribute Delimiter** for multi-valued attributes (default: `,`).
9. Enter the **OUD Search Key** -- the attribute used for looking up user and group data.
10. Click **Save**.
```yaml maverics.yaml theme={null}
connectors:
- name: ldap-attrs
type: ldap
url:
- "ldaps://ldap.example.com:636"
serviceAccountUsername: "cn=admin,dc=example,dc=com"
serviceAccountPassword:
baseDN: "dc=example,dc=com"
usernameSearchKey: uid
tls: ldap-tls
```
## Configuration Reference
| Key | Type | Required | Description |
| ------------------------ | --------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `name` | string | Yes | Unique connector identifier referenced by app policies and attribute providers |
| `type` | string | Yes | Must be `ldap` |
| `url` | string\[] | Yes | LDAP server URLs -- supports `ldap://` (port 389) and `ldaps://` (port 636); multiple URLs enable failover |
| `serviceAccountUsername` | string | Yes | Bind DN for the service account (e.g., `cn=admin,dc=example,dc=com`) |
| `serviceAccountPassword` | string | Yes | Service account password -- use secret reference syntax `` |
| `baseDN` | string | Yes | Base DN for LDAP searches (e.g., `dc=example,dc=com`) |
| `usernameSearchKey` | string | No | LDAP attribute used for username lookup (e.g., `uid`, `cn`) |
| `attributeDelimiter` | string | No | Delimiter for multi-valued LDAP attributes (default: `","`) |
| `tls` | string | No | Named TLS profile for LDAP connection |
| `healthCheck` | object | No | Health check monitoring configuration (see [Identity Fabric Configuration Reference](/reference/orchestrator/identity-fabric#configuration-reference)) |
For the complete connector field reference including health check details, see [Identity Fabric Configuration Reference](/reference/orchestrator/identity-fabric#configuration-reference).
## Troubleshooting
* **Test LDAP connectivity from the Orchestrator host** -- Use `ldapsearch` or a similar tool to verify the Orchestrator can reach the LDAP server on the configured port
* **Verify the service account has read permissions on the baseDN** -- The bind DN must have sufficient permissions to search the subtree and read the configured attributes
* **Check attribute names in application claims and headers** -- LDAP attribute names referenced in application claims, headers, or policy attributes must match the directory schema exactly. Common sources of confusion: `mail` vs `email`, `cn` vs `commonName`
* **For LDAPS, ensure the TLS profile includes the correct CA certificate** -- If the LDAP server uses a private CA, the TLS profile must include the CA certificate via `caFile`
## Related Pages
LDAP connector for user authentication via bind operations
LDAP-based connector for Microsoft Active Directory
Overview of all identity providers
Oracle OUD directory integration
# Generic OAuth
Source: https://docs.strata.io/reference/orchestrator/identity-fabric/oauth
The Generic OAuth connector provides a pure OAuth 2.0 integration for upstream authorization servers. It speaks OAuth only -- it does not consume an `id_token` or call a userinfo endpoint. The OAuth connector provides flexibility to connect services like GitHub, Atlassian, and other platforms that support OAuth but not OpenID Connect..
**Console terminology:** In the Maverics Console, this section is called
**Identity Fabric**. The YAML configuration uses the `connectors` key to define
identity provider integrations.
## Overview
The Generic OAuth connector targets authorization servers that expose OAuth 2.0 endpoints. It supports two configuration styles -- discovery via a `wellKnownURL`, or manually specified `authorizeURL` and `tokenURL` endpoints -- and a non-standard "no client authentication" mode for federation flows where the upstream authenticates the request via a subject token instead of client credentials.
The connector can also obtain or assert its own client identity instead of using a pre-provisioned one, through [Dynamic Client Registration](#dynamic-client-registration) or a [Client ID Metadata Document](#client-id-metadata-document). See [Client Authentication Modes](#client-authentication-modes) for how the options compare.
The `wellKnownURL` field accepts either an [OAuth Authorization Server Metadata](https://datatracker.ietf.org/doc/html/rfc8414) document or an [OIDC discovery](https://openid.net/specs/openid-connect-discovery-1_0.html) document (which is a superset of the OAuth metadata format). Either way, the connector reads only the OAuth endpoints from the discovery document -- it does not perform OIDC end-user authentication.
For interactive end-user login against a full OpenID Connect IdP, use the [Generic OIDC](/reference/orchestrator/identity-fabric/custom-oidc) connector instead.
## Use Cases
* **[Token brokering](/reference/orchestrator/experimental/token-brokering) against OAuth-only authorization servers** -- Exchange Orchestrator-issued tokens for upstream tokens (RFC 8693 token exchange) against services like Databricks account-wide federation or GCP Workload Identity Federation, where the upstream exposes OAuth but no `id_token` and no userinfo endpoint.
* **Machine-to-machine outbound calls** -- Authorize outbound calls from the Orchestrator where the upstream authenticates the request via a subject token rather than client credentials.
* **OAuth-only authorization servers** -- Integrate with services like GitHub or Atlassian that provide OAuth 2.0 authorization but not full OIDC, when you need access tokens for API access rather than user identity.
* **Federation without a pre-provisioned credential** -- Connect to an authorization server you cannot register a client with ahead of time. The Orchestrator either registers itself on startup ([Dynamic Client Registration](#dynamic-client-registration)) or identifies itself by a URL it publishes ([Client ID Metadata Document](#client-id-metadata-document)), so no client ID or secret has to be issued and rotated by hand.
## Setup
To create a Generic OAuth connector in the Maverics Console:
1. Navigate to **Identity Fabric** in the Console sidebar.
2. Click **Create** and select **Generic OAuth**.
3. Enter a **Name** for the connector -- this is the friendly name that identifies your OAuth integration.
4. Provide endpoints either by:
* Entering the **Well Known URL** -- either an OAuth Authorization Server Metadata URL (RFC 8414) or an OIDC discovery URL; **or**
* Entering the **Authorization URL** and **Token URL** manually.
These two approaches are mutually exclusive -- provide one or the other, not both.
5. Enter the **Client ID** issued by the upstream authorization server. Leave this empty if you plan to use CIMD or DCR in step 9.
6. Enter the **Client Secret** associated with the client ID. Use the show/hide toggle to verify the value. Leave this empty if you plan to use CIMD or DCR in step 9.
7. Add one or more **Redirect URLs** -- the URL(s) where the Orchestrator's OAuth handler is served. At least one entry is required.
8. Optionally enable **Disable Client Authentication** if the upstream authorization server authenticates the request via the subject token alone (for example, Databricks account-wide federation). See [Disable Client Authentication](#disable-client-authentication) below.
9. Optionally configure a credential-less mode in the **CIMD / DCR** section at the bottom of the drawer. Leave **Client ID** and **Client Secret** empty to use either one:
* For [Client ID Metadata Document](#client-id-metadata-document) mode, enter the **Client ID Metadata Document (CIMD) Metadata URL**. This is the HTTPS URL the Orchestrator serves the document at, and the value it presents as its client ID.
* For [Dynamic Client Registration](#dynamic-client-registration), fill in the **Dynamic Client Registration (DCR)** sub-section: **Client Name** is the display name the authorization server records, and **Token Endpoint Authentication Method** is the authentication method to request.
CIMD and DCR are mutually exclusive -- configure one or the other, not both.
10. Click **Save**.
If your upstream is a full OpenID Connect provider and you need identity claims and end-user session handling out of the box (i.e., `id_token` and userinfo), use the [Generic OIDC](/reference/orchestrator/identity-fabric/custom-oidc) connector instead.
The OAuth connector supports two configuration approaches. Use `wellKnownURL` when
the authorization server publishes a discovery document (either OAuth Authorization
Server Metadata or OIDC discovery), or manually specify the `authorizeURL` and
`tokenURL` endpoints. These two options are mutually exclusive.
**Option 1: Using a well-known discovery URL**
```yaml maverics.yaml theme={null}
connectors:
- name: databricks
type: oauth
clientID: "{{ env.DATABRICKS_CLIENT_ID }}"
clientSecret:
wellKnownURL: https://accounts.cloud.databricks.com/.well-known/oauth-authorization-server
loginRedirect:
urls:
- https://app.example.com/databricks/oauth
```
**Option 2: Manually specifying authorize and token URLs**
```yaml maverics.yaml theme={null}
connectors:
- name: github
type: oauth
clientID: "{{ env.GITHUB_CLIENT_ID }}"
clientSecret:
authorizeURL: https://github.com/login/oauth/authorize
tokenURL: https://github.com/login/oauth/access_token
loginRedirect:
urls:
- https://app.example.com/github/oauth
scopes: repo
```
**Option 3: Registering the client dynamically**
```yaml maverics.yaml theme={null}
connectors:
- name: partner-oauth
type: oauth
wellKnownURL: https://auth.example.com/.well-known/oauth-authorization-server
loginRedirect:
urls:
- https://app.example.com/partner/oauth
# No clientID or clientSecret -- the Orchestrator registers itself on startup.
dcr:
clientName: Maverics Orchestrator
```
**Option 4: Identifying the client by a metadata document URL**
```yaml maverics.yaml theme={null}
connectors:
- name: partner-oauth
type: oauth
wellKnownURL: https://auth.example.com/.well-known/oauth-authorization-server
loginRedirect:
urls:
- https://app.example.com/partner/oauth
cimd:
# Served by the Orchestrator at this address, and presented as the client ID.
url: https://app.example.com/.well-known/oauth-client
```
See [Dynamic Client Registration](#dynamic-client-registration) and [Client ID Metadata Document](#client-id-metadata-document) for how each mode behaves.
## Configuration Reference
| Key | Type | Required | Description |
| ----------------------------- | ------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `name` | string | Yes | Friendly name of the connector, referenced in app policies. |
| `type` | string | Yes | Must be `oauth`. |
| `wellKnownURL` | string | Conditional | Discovery document URL -- either OAuth Authorization Server Metadata (RFC 8414) or OIDC discovery. The connector reads only the OAuth endpoints. Provide this **or** `authorizeURL` + `tokenURL`, not both. |
| `authorizeURL` | string | Conditional | OAuth 2.0 authorization endpoint. Required only when `wellKnownURL` is omitted. Mutually exclusive with `wellKnownURL`. |
| `tokenURL` | string | Conditional | OAuth 2.0 token endpoint. Required only when `wellKnownURL` is omitted. Mutually exclusive with `wellKnownURL`. |
| `clientID` | string | Conditional | OAuth 2.0 client ID. Required unless `disableClientAuthentication` is `true`, in which case it is optional (some grants may still require it at runtime). Must be empty when `dcr` or `cimd` is configured. |
| `clientSecret` | string | Conditional | OAuth 2.0 client secret (use secret reference syntax). Required unless `disableClientAuthentication` is `true`, in which case it must be empty. Must be empty when `dcr` or `cimd` is configured. |
| `loginRedirect.urls` | list | Yes | Redirect URL(s) where the Orchestrator's OAuth handler is served. At least one entry is required. |
| `disableClientAuthentication` | boolean | No | When `true`, the Orchestrator does not send `client_secret` in OAuth form bodies. See [Disable Client Authentication](#disable-client-authentication). Defaults to `false`. |
| `scopes` | string | No | Space-separated OAuth scopes to request. |
| `dcr` | object | No | Enables [Dynamic Client Registration](#dynamic-client-registration) (RFC 7591). Requires `wellKnownURL`. Mutually exclusive with `clientID`, `clientSecret`, `disableClientAuthentication`, and `cimd`. |
| `dcr.clientName` | string | No | Display name sent as `client_name` in the registration request. |
| `dcr.tokenEndpointAuthMethod` | string | No | The `token_endpoint_auth_method` to request. When omitted, the authorization server chooses. |
| `cimd` | object | No | Enables [Client ID Metadata Document](#client-id-metadata-document) mode. Mutually exclusive with `clientID`, `clientSecret`, `disableClientAuthentication`, and `dcr`. |
| `cimd.url` | string | Conditional | HTTPS URL the metadata document is served at, and the connector's client ID. Required when `cimd` is set. Must be lowercase, include a path, and omit any query string, fragment, userinfo, or dot-segments. |
For the complete field reference including health checks, see [Identity Fabric](/reference/orchestrator/identity-fabric#configuration-reference).
## Client Authentication Modes
The connector authenticates to the upstream authorization server in one of four ways. Choose one -- they are mutually exclusive.
| Mode | Configuration | Client authentication |
| ----------------------------------------------------------- | ----------------------------------- | --------------------------------------------------------------------------- |
| Static credentials (default) | `clientID` + `clientSecret` | Sends `client_secret` in the OAuth form body. |
| [Dynamic Client Registration](#dynamic-client-registration) | `dcr` | Uses the credential the authorization server issues at startup. |
| [Client ID Metadata Document](#client-id-metadata-document) | `cimd` | None. The connector is a public client and PKCE protects the code exchange. |
| [No client authentication](#disable-client-authentication) | `disableClientAuthentication: true` | None. The subject token authenticates the request. |
Configuring `dcr` or `cimd` alongside `clientID`, `clientSecret`, `disableClientAuthentication`, or each other is rejected when the configuration loads. Both modes install their own client ID, so a connector configured for two of them would have one silently overwrite the other.
Dynamic Client Registration and Client ID Metadata Document mode require Orchestrator **v2026.08.2** or later. Earlier versions ignore the `dcr` and `cimd` keys.
## Dynamic Client Registration
Dynamic Client Registration ([RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591)) lets the Orchestrator create its own OAuth client at the upstream authorization server instead of using credentials you provision by hand. Add a `dcr` block and omit `clientID` and `clientSecret`.
```yaml maverics.yaml theme={null}
connectors:
- name: partner-oauth
type: oauth
wellKnownURL: https://auth.example.com/.well-known/oauth-authorization-server
loginRedirect:
urls:
- https://app.example.com/partner/oauth
dcr:
# Display name the authorization server records for the registered client.
clientName: Maverics Orchestrator
```
### How registration works
DCR requires `wellKnownURL`. The Orchestrator reads the `registration_endpoint` from the discovery document, so it cannot be used with manually specified `authorizeURL` and `tokenURL` endpoints.
Registration runs once when the connector starts, as part of discovery. The Orchestrator sends a `POST` to the registration endpoint containing:
* `client_name` -- from `dcr.clientName`.
* `token_endpoint_auth_method` -- from `dcr.tokenEndpointAuthMethod`, when set.
* `grant_types` -- `authorization_code`.
* `response_types` -- `code`.
* `redirect_uris` -- the connector's `loginRedirect.urls`.
The Orchestrator accepts an HTTP 200 or 201 response and reads `client_id`, `client_secret`, and `token_endpoint_auth_method` from it. A `client_id` is required -- registration fails without one. If the response sets `token_endpoint_auth_method` to `none` or omits `client_secret`, the connector operates as a public client and sends no client credential on subsequent requests.
Registered credentials are held in memory only. They are not persisted, so **the connector registers a new client every time the Orchestrator restarts**. On an authorization server that retains registrations, this accumulates clients over time. Confirm your server's registration limits and cleanup policy before enabling DCR in production.
When `dcr` is configured, a failure to load the discovery document is fatal -- the connector does not start. Without `dcr`, the same failure is logged and startup continues.
## Client ID Metadata Document
Client ID Metadata Documents are an experimental feature -- see [Experimental Features](/reference/orchestrator/experimental/overview) for important caveats.
Client ID Metadata Document (CIMD) mode, defined in [draft-ietf-oauth-client-id-metadata-document](https://datatracker.ietf.org/doc/draft-ietf-oauth-client-id-metadata-document/), lets the connector identify itself by an HTTPS URL rather than a registered client ID. The Orchestrator serves a JSON metadata document at that URL and presents the same URL as its client ID in every authorization and token request. Nothing is registered with the authorization server in advance.
A CIMD connector is a public client: PKCE protects the authorization code exchange in place of a client credential.
This section covers the Orchestrator acting as a **CIMD client** toward an upstream authorization server. For the Orchestrator acting as an **authorization server** that accepts CIMD clients, see [Client ID Metadata Documents](/reference/orchestrator/experimental/client-id-metadata-documents).
```yaml maverics.yaml theme={null}
connectors:
- name: partner-oauth
type: oauth
wellKnownURL: https://auth.example.com/.well-known/oauth-authorization-server
loginRedirect:
urls:
- https://app.example.com/partner/oauth
cimd:
# Served by the Orchestrator at this address, and presented verbatim as the
# client ID. Must be lowercase and reachable by the authorization server.
url: https://app.example.com/.well-known/oauth-client
# Listing offline_access adds refresh_token to the published grant types.
scopes: offline_access
```
### The published document
The Orchestrator builds the metadata document from the connector's own configuration -- there are no separate fields to set. The example above publishes:
```json theme={null}
{
"client_id": "https://app.example.com/.well-known/oauth-client",
"client_name": "partner-oauth",
"client_uri": "https://app.example.com",
"redirect_uris": ["https://app.example.com/partner/oauth"],
"grant_types": ["authorization_code", "refresh_token"],
"response_types": ["code"],
"scope": "offline_access",
"token_endpoint_auth_method": "none"
}
```
| Field | Derived from |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `client_id` | `cimd.url`, verbatim. |
| `client_name` | The connector's `name`. |
| `client_uri` | The scheme and host of `cimd.url`, including a non-default port. Not configurable, so it cannot drift from `client_id` under an authorization server that enforces a same-domain rule between the two. |
| `redirect_uris` | The connector's `loginRedirect.urls`. |
| `grant_types` | `authorization_code`, plus `refresh_token` when `offline_access` is among the requested `scopes`. |
| `response_types` | Always `code`. |
| `scope` | The connector's `scopes`. Omitted when `scopes` is unset. |
| `token_endpoint_auth_method` | Always `none`. |
The document is served with a `Content-Type` of `application/json` and `Cache-Control: max-age=3600`.
The Generic OAuth connector has no `offlineAccess` setting. To publish the `refresh_token` grant, list `offline_access` in `scopes` directly, as in the example above.
### URL requirements
The Orchestrator registers a route from the host and path of `cimd.url`, dropping the scheme, port, and any trailing slash. The Orchestrator must be reachable at that host and path from the authorization server, or the server cannot fetch the document.
`cimd.url` is validated when the configuration loads and must:
* Use the `https` scheme.
* Include a host and a path other than `/`.
* Omit any query string, fragment, or userinfo component.
* Omit dot-segments (`.` and `..`).
* Be **entirely lowercase**, in both host and path. The route is registered lowercased while the published client ID keeps the casing you configure, so a mixed-case URL would return 404 at the very address the document advertises.
### Discovery
If the authorization server's discovery document omits `client_id_metadata_document_supported`, the Orchestrator logs a message and proceeds anyway, since some servers accept CIMD clients without advertising support.
## Disable Client Authentication
Setting `disableClientAuthentication: true` is intended for federation flows where the upstream authorization server authenticates the request via the subject token alone -- for example, Databricks account-wide federation. When enabled:
* `clientSecret` must be empty.
* `clientID` becomes optional, though some grants may still require it at runtime.
* The Orchestrator enforces grant-type-level rules. For instance, the client-credentials and Resource Owner Password Credentials (ROPC) grants are rejected at runtime when client authentication is disabled, because those grants depend on client credentials to authenticate the request.
```yaml maverics.yaml theme={null}
connectors:
- name: databricks-federation
type: oauth
clientID: "{{ env.DATABRICKS_CLIENT_ID }}"
wellKnownURL: https://accounts.cloud.databricks.com/.well-known/oauth-authorization-server
loginRedirect:
urls:
- https://app.example.com/databricks/oauth
disableClientAuthentication: true
```
## Troubleshooting
* **Verify the `authorizeURL` and `tokenURL` are accessible** from the Orchestrator host -- confirm both endpoints respond correctly.
* **If using `wellKnownURL`**, ensure the discovery document URL is correct and returns valid JSON with `authorization_endpoint` and `token_endpoint` fields.
* **Ensure the `loginRedirect` URLs match exactly** what is registered with the upstream authorization server.
* **Check that the client secret reference resolves correctly** via your secret provider -- unless `disableClientAuthentication` is `true`, in which case `clientSecret` must be empty.
* **If `disableClientAuthentication` is `true`**, confirm the grant type in use is supported -- client-credentials and ROPC grants are rejected when client authentication is disabled.
* **Verify the requested `scopes` are valid** for the authorization server -- invalid scopes may cause authorization failures.
* **If registration fails with a missing `registration_endpoint`**, the discovery document does not advertise one. That authorization server does not support Dynamic Client Registration; use static credentials or CIMD instead.
* **If the authorization server rejects a CIMD client as unknown**, fetch `cimd.url` from outside your network and confirm it returns the metadata document rather than a 404. The usual cause is the Orchestrator not being routable at that host and path.
* **If the configuration fails to load with `'url' must be lowercase`**, lowercase the entire `cimd.url`, host and path alike.
* **If either credential-less mode is ignored entirely**, check the Orchestrator version -- `dcr` and `cimd` require v2026.08.2 or later.
## Related Pages
Overview of all identity providers
RFC 8693 token exchange for downstream APIs
Generic OpenID Connect connector
Generic SAML 2.0 connector
Accept CIMD clients as an OIDC Provider
Caveats that apply to experimental features
# Okta (OIDC)
Source: https://docs.strata.io/reference/orchestrator/identity-fabric/okta
The Okta connector integrates the Maverics Orchestrator with the Okta identity platform -- enabling OIDC-based single sign-on for your applications.
**Console terminology:** In the Maverics Console, this section is called
**Identity Fabric**. The YAML configuration uses the `connectors` key to define
identity provider integrations.
## Overview
The Okta connector uses OpenID Connect to federate authentication with Okta and supports standard OIDC flows -- allowing you to consolidate SSO across applications and bridge Okta-managed identities with legacy applications that lack native Okta support.
## Use Cases
* **Unify SSO for legacy applications** -- Extend Okta SSO to legacy and on-premises applications that lack native OIDC support by translating tokens into header-based or cookie-based authentication
* **Rationalize IdP sprawl** -- Migrate users from competing identity platforms to Okta at your own pace, reducing licensing costs while maintaining uninterrupted access to all applications
* **Authentication resilience** -- Pair Okta with a secondary identity provider for automatic failover, ensuring users can still authenticate if Okta experiences downtime
* **Multi-IdP orchestration** -- Route authentication requests to Okta alongside other identity providers based on user attributes, application requirements, or organizational policy
## Setup
To create an Okta (OIDC) connector in the Maverics Console:
1. Navigate to **Identity Fabric** in the Console sidebar.
2. Click **Create** and select **Okta (OIDC)**.
3. Enter a **Name** -- this is the friendly name that identifies your provider.
4. Enter the **OIDC Well Known URL** -- for Okta, this follows the pattern `https://{your-org}.okta.com/.well-known/openid-configuration`. If you are using a custom authorization server, use `https://{your-org}.okta.com/oauth2/{server-id}/.well-known/openid-configuration`.
5. Enter the **OAuth Client ID** -- the client ID from your Okta application integration.
6. Enter the **OAuth Client Secret** -- the client secret from your Okta application integration.
7. Under **Redirect URLs**, add the callback URL where Okta will redirect after authentication. This URL must match the Sign-in redirect URI configured in your Okta application.
8. Optionally configure **Logout Callback URLs** for single logout support.
9. Optionally set **Scopes** (space-separated). Default scopes are typically `openid profile email`.
10. The **PKCE** toggle is enabled by default. Disable it only if your Okta application is not configured to support Proof Key for Code Exchange.
11. Optionally enable **Offline Access** for token refresh support (Proxy apps only).
12. Click **Save**.
```yaml theme={null}
connectors:
- name: okta
type: okta
oidcWellKnownURL: "https://{{ env.OKTA_ORG }}.okta.com/.well-known/openid-configuration"
oauthClientID: "{{ env.OKTA_CLIENT_ID }}"
oauthClientSecret:
oauthLoginRedirect:
urls:
- https://app.example.com/oidc/callback
scopes: "openid profile email"
```
The Okta well-known URL follows the org-based pattern: `{org}.okta.com`. If you are using a custom authorization server, use the path `{org}.okta.com/oauth2/{server-id}/.well-known/openid-configuration`.
## Configuration Reference
| Key | Type | Required | Description |
| -------------------------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `name` | string | Yes | Unique connector identifier referenced in app policies |
| `type` | string | Yes | Must be `okta` |
| `oidcWellKnownURL` | string | Yes | OIDC discovery endpoint URL (org-specific) |
| `oauthClientID` | string | Yes | OAuth 2.0 client ID from the Okta admin console |
| `oauthClientSecret` | string | Yes | OAuth 2.0 client secret (use secret reference syntax) |
| `oauthLoginRedirect.urls` | list | Yes | Callback URL(s) registered with the Okta application. The Orchestrator selects the URL whose host matches the incoming request. |
| `oauthLogoutRedirect.urls` | list | No | URL(s) called by Okta after a successful logout. |
| `scopes` | string | No | Space-separated OAuth scopes (default: `openid profile email`) |
| `tls` | string | No | Named TLS profile for provider communication |
For the complete field reference including health checks, offline access, and PKCE settings, see [Identity Fabric](/reference/orchestrator/identity-fabric#configuration-reference).
## Troubleshooting
* **Verify the `oidcWellKnownURL` is accessible** from the Orchestrator host -- ensure the Okta org name is correct
* **Ensure each URL in `oauthLoginRedirect.urls` matches exactly** what is registered in the Okta application under Sign-in redirect URIs
* **Check that the client secret reference resolves correctly** via your secret provider
## Related Pages
Overview of all identity providers
OIDC connector for Microsoft Entra ID
OIDC connector for Auth0 by Okta
Generic OpenID Connect connector
# Okta Attribute Provider
Source: https://docs.strata.io/reference/orchestrator/identity-fabric/okta-attr
The Okta Attribute Provider connector retrieves user attributes from Okta using API requests -- enriching session claims with directory data beyond what authentication alone provides.
**Console terminology:** In the Maverics Console, this section is called
**Identity Fabric**. The YAML configuration uses the `connectors` key to define
attribute provider integrations.
## Overview
The Okta Attribute Provider uses the Okta API to look up user profile data, group memberships, and other directory attributes. It shares the same connector type as the [Okta IdP connector](/reference/orchestrator/identity-fabric/okta), but configured with an API token instead of OIDC authentication fields. This connector is not an identity provider. It does not handle authentication. Instead, it is paired with another IdP connector (such as Microsoft Entra ID, ADFS, or a SAML provider) to supplement the session with additional attributes from Okta.
## Use Cases
* **Unified SSO with Okta attribute enrichment** -- Enrich sessions with Okta profile data (department, job title, custom attributes) so applications receive consistent identity attributes regardless of which IdP handles authentication
* **Cross-IdP authorization with Okta groups** -- Query Okta group memberships to drive authorization decisions in Orchestrator policies, even when users authenticate through a non-Okta IdP like Entra ID or ADFS
* **Preserve Okta attributes during IdP rationalization** -- During migration away from Okta, maintain access to Okta directory attributes so applications continue to receive the claims they depend on without disruption
* **Multi-directory identity enrichment** -- Combine Okta attribute lookups with authentication from any supported IdP, bridging identity data across systems in hybrid or multi-vendor identity environments
## Setup
To create an Okta Attribute Provider connector in the Maverics Console:
1. Navigate to **Identity Fabric** in the Console sidebar.
2. Click **Create** and select **Okta Attribute Provider**.
3. Enter a **Name** -- this is the friendly name that identifies your provider.
4. Enter the **API Token** -- the token used to authenticate the Maverics client with the Okta API. Generate this from the Okta admin console under **Security** > **API** > **Tokens**.
5. Enter the **Domain** -- the Okta domain to use for attributes (e.g., `your-org.okta.com`).
6. Click **Save**.
```yaml maverics.yaml theme={null}
connectors:
- name: okta-attr
type: okta
apiToken:
domain: "{{ env.OKTA_DOMAIN }}"
```
The Okta API token must be created by an admin user in the Okta admin console. Tokens inherit the permissions of the admin who creates them. Use a service account with the minimum required permissions for attribute lookups.
## Configuration Reference
| Key | Type | Required | Description |
| ---------- | ------ | -------- | ------------------------------------------------------------------------ |
| `name` | string | Yes | Unique connector identifier referenced in app policies |
| `type` | string | Yes | Must be `okta` |
| `apiToken` | string | Yes | Okta API token for authenticating requests (use secret reference syntax) |
| `domain` | string | Yes | Okta organization domain (e.g., `https://your-org.okta.com`) |
For the complete field reference, see [Identity Fabric](/reference/orchestrator/identity-fabric#configuration-reference).
## Troubleshooting
* **Verify the `domain` is correct** -- ensure it matches your Okta organization URL (e.g., `https://your-org.okta.com`)
* **Ensure the API token is valid and not expired** -- Okta API tokens expire if not used for 30 days; check the token status in the Okta admin console under **Security** > **API** > **Tokens**
* **Check that the `apiToken` secret reference resolves correctly** via your secret provider
* **Confirm the token has sufficient permissions** -- the admin who created the token must have read access to user profiles and groups
## Related Pages
OIDC identity provider connector for Okta
Overview of all identity providers and attribute providers
OIDC connector for Microsoft Entra ID -- commonly paired with this attribute provider
Generic OpenID Connect connector
# Okta (SAML)
Source: https://docs.strata.io/reference/orchestrator/identity-fabric/okta-saml
The Okta (SAML) connector integrates the Maverics Orchestrator with Okta using the SAML 2.0 protocol -- providing an alternative to the OIDC-based Okta connector for environments that require SAML federation.
**Console terminology:** In the Maverics Console, this section is called
**Identity Fabric**. The YAML configuration uses the `connectors` key to define
identity provider integrations.
## Overview
The Okta (SAML) connector supports SAML 2.0 SSO profiles including SP-initiated and IdP-initiated flows. For most deployments, the [Okta (OIDC) connector](/reference/orchestrator/identity-fabric/okta) is recommended as the more common integration path. Use the SAML variant when your environment requires SAML-based federation or when integrating with applications that only support SAML assertions.
## Use Cases
* **Unify SSO for SAML-dependent applications** -- Connect to Okta via SAML when legacy applications or compliance policies require SAML 2.0 federation instead of OIDC
* **Legacy application modernization** -- Bridge Okta SAML assertions to header-based or cookie-based authentication for legacy applications, extending SSO without rewriting them
* **Rationalize identity platforms through Okta** -- Consolidate authentication from multiple IdPs into Okta, reducing licensing overlap and simplifying identity operations
* **Okta failover with Continuity** -- Pair Okta SAML with a secondary IdP to maintain authentication availability during Okta service disruptions
## Setup
To create an Okta (SAML) connector in the Maverics Console:
1. Navigate to **Identity Fabric** in the Console sidebar.
2. Click **Create** and select **Okta (SAML)**.
The Console also offers **Okta (OIDC)** for OpenID Connect-based integration, which is the more common option. See the [Okta (OIDC) page](/reference/orchestrator/identity-fabric/okta) for details.
3. Enter a **Name** -- the friendly name for your Okta SAML provider.
4. Enter the **Metadata URL** -- the URL of the Okta SAML metadata document (e.g., `https://{your-org}.okta.com/app/{app-id}/sso/saml/metadata`).
5. Enter the **Consumer Service (ACS) URL** -- the Assertion Consumer Service URL where Okta sends SAML responses.
6. Enter the **Entity ID** -- the unique identifier for the Orchestrator as the SAML Service Provider.
7. Optionally enter a **Logout Callback URL** for Single Logout (SLO) callback.
8. Optionally enter the **SP Certificate Path** and **SP Private Key Path** for signing SAML requests.
9. Optionally enable **IdP Initiated Login** to allow authentication flows started by Okta.
10. Click **Save**.
```yaml maverics.yaml theme={null}
connectors:
- name: okta-saml
type: saml
samlMetadataURL: "https://{{ env.OKTA_ORG }}.okta.com/app/{{ env.OKTA_APP_ID }}/sso/saml/metadata"
samlConsumerServiceURL: "https://orch.example.com/saml/callback"
samlEntityID: "https://orch.example.com"
tls: okta-tls
```
## Configuration Reference
| Key | Type | Required | Description |
| ------------------------ | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `name` | string | Yes | Unique connector identifier referenced by app policies and attribute providers |
| `type` | string | Yes | Must be `saml` |
| `samlMetadataURL` | string | Yes | URL to the Okta SAML metadata XML -- the Orchestrator fetches this to discover SSO endpoints and signing certificates |
| `samlConsumerServiceURL` | string | Yes | Assertion Consumer Service (ACS) URL where Okta sends SAML responses |
| `samlEntityID` | string | No | Service Provider entity ID that identifies the Orchestrator to Okta |
| `samlLogoutCallbackURL` | string | No | Logout callback URL for SAML single logout |
| `samlSPCertPath` | string | No | Path to the SP certificate file for signing SAML requests |
| `samlSPKeyPath` | string | No | Path to the SP private key file for signing SAML requests |
| `samlIDPInitiatedLogin` | object | No | IdP-initiated login configuration |
| `cache` | string | No | Cache name reference for SAML request data storage |
| `tls` | string | No | Named TLS profile for metadata retrieval and IdP communication |
| `healthCheck` | object | No | Health check monitoring configuration (see [Identity Fabric Configuration Reference](/reference/orchestrator/identity-fabric#configuration-reference)) |
For the complete connector field reference including health check details, see [Identity Fabric Configuration Reference](/reference/orchestrator/identity-fabric#configuration-reference).
## Troubleshooting
* **Verify the Okta SAML metadata URL is accessible** -- The Orchestrator fetches the metadata XML at startup. The metadata URL is typically found in the Okta application's Sign On settings under "Identity Provider metadata."
* **Ensure the entity ID matches the Okta application** -- The `samlEntityID` value must match the Audience URI (SP Entity ID) configured in the Okta SAML application settings.
* **Check the Assertion Consumer Service URL** -- The `samlConsumerServiceURL` must match the Single sign on URL configured in the Okta SAML application. If behind a load balancer, use the external-facing URL.
* **SP signing certificate errors** -- If the Okta application requires signed authentication requests, ensure `samlSPCertPath` and `samlSPKeyPath` point to valid PEM files and the key matches the certificate.
## Related Pages
OIDC-based Okta connector (recommended for most deployments)
Generic SAML 2.0 connector
Overview of all identity providers
IdP failover connector
# 1Kosmos (SAML)
Source: https://docs.strata.io/reference/orchestrator/identity-fabric/onekosmos
The 1Kosmos connector integrates the Maverics Orchestrator with the 1Kosmos BlockID platform -- enabling passwordless and identity-verified authentication for your applications.
**Console terminology:** In the Maverics Console, this section is called
**Identity Fabric**. The YAML configuration uses the `connectors` key to define
identity provider integrations.
## Overview
The 1Kosmos connector uses SAML 2.0 to federate authentication with the 1Kosmos BlockID platform -- enabling identity-verified, passwordless authentication through the Maverics Orchestrator.
## Use Cases
* **Passwordless authentication** -- Replace passwords with 1Kosmos BlockID identity-verified authentication, modernizing the sign-on experience across legacy and cloud applications
* **Identity proofing for high-assurance access** -- Leverage 1Kosmos document verification and biometric capabilities for high-assurance authentication where compliance or security policies demand strong identity verification
* **Unify SSO with passwordless across hybrid environments** -- Route authentication to 1Kosmos alongside other IdPs, extending passwordless access to legacy apps that were never designed for it
* **Phased IdP rationalization** -- Gradually migrate users from legacy IdPs to 1Kosmos BlockID, reducing the number of identity platforms and the associated licensing and maintenance costs
## Setup
To create a 1Kosmos connector in the Maverics Console:
1. Navigate to **Identity Fabric** in the Console sidebar.
2. Click **Create** and select **1Kosmos (SAML)**.
3. Enter a **Name** -- the friendly name that identifies your provider.
4. Enter the **Metadata URL** -- the URL of the 1Kosmos SAML metadata document.
5. Enter the **Consumer Service (ACS) URL** -- the Assertion Consumer Service URL where 1Kosmos sends SAML responses.
6. Enter the **Entity ID** -- the unique identifier for the Service Provider.
7. Click **Save**.
```yaml maverics.yaml theme={null}
connectors:
- name: onekosmos
type: onekosmos
domain: "{{ env.ONEKOSMOS_DOMAIN }}"
samlMetadataURL: "https://{{ env.ONEKOSMOS_DOMAIN }}/saml2/idp/metadata"
samlConsumerServiceURL: "https://orch.example.com/saml/callback"
samlEntityID: "https://orch.example.com"
tls: onekosmos-tls
```
## Configuration Reference
| Key | Type | Required | Description |
| ------------------------ | ------ | -------- | ----------------------------------------------------------------------- |
| `name` | string | Yes | Unique connector identifier referenced in app policies |
| `type` | string | Yes | Must be `onekosmos` |
| `domain` | string | Yes | The 1Kosmos BlockID domain for your organization |
| `samlMetadataURL` | string | Yes | URL to the 1Kosmos SAML metadata XML |
| `samlConsumerServiceURL` | string | Yes | Assertion Consumer Service (ACS) URL where 1Kosmos sends SAML responses |
| `samlEntityID` | string | No | Service Provider entity ID that identifies the Orchestrator to 1Kosmos |
| `errorPage` | string | No | URL to redirect users to when an error occurs during authentication |
| `cache` | string | No | Cache name reference for SAML request data storage |
| `tls` | string | No | Named TLS profile for metadata retrieval and IdP communication |
For the complete connector field reference, see [Identity Fabric Configuration Reference](/reference/orchestrator/identity-fabric#configuration-reference).
## Troubleshooting
* **Verify the SAML metadata URL is accessible** from the Orchestrator host -- confirm the 1Kosmos domain is correct and reachable
* **Ensure the entity ID matches the 1Kosmos configuration** -- The `samlEntityID` value must match the trusted Service Provider identifier configured in the 1Kosmos BlockID administration portal
* **Check the Assertion Consumer Service URL** -- The `samlConsumerServiceURL` must match the Orchestrator's actual callback endpoint. If behind a load balancer, use the external-facing URL.
* **Verify the domain value** -- The `domain` field must match the 1Kosmos BlockID domain assigned to your organization
## Related Pages
Overview of all identity providers
Generic OpenID Connect connector
Generic SAML 2.0 connector
HYPR passwordless authentication connector
# Oracle Identity Cloud Service (OIDC)
Source: https://docs.strata.io/reference/orchestrator/identity-fabric/oracle-ics
The Oracle Identity Cloud Service connector integrates the Maverics Orchestrator with Oracle IDCS using the OpenID Connect protocol -- enabling OIDC-based single sign-on for your applications.
**Console terminology:** In the Maverics Console, this section is called
**Identity Fabric**. The YAML configuration uses the `connectors` key to define
identity provider integrations.
## Overview
The Oracle Identity Cloud Service connector supports standard OIDC flows via Oracle IDCS's OpenID Connect endpoints. The Orchestrator communicates with Oracle IDCS through standard OIDC discovery -- no provider-specific configuration is required beyond the well-known URL.
## Use Cases
* **Unify SSO across Oracle and non-Oracle apps** -- Extend Oracle IDCS authentication to legacy and on-premises applications that don't support modern identity protocols, creating a unified SSO experience across your Oracle Cloud and hybrid environments
* **Rationalize identity platforms** -- Orchestrate migration from Oracle IDCS to a strategic IdP or consolidate Oracle IDCS with other providers, reducing licensing costs while maintaining application access
* **Oracle Cloud resilience** -- Configure Oracle IDCS as a primary or failover IdP alongside other providers, ensuring authentication continuity for Oracle-dependent workloads during outages
* **Hybrid Oracle environments** -- Bridge Oracle IDCS-managed identities with applications running outside the Oracle Cloud ecosystem through identity orchestration
## Setup
To create an Oracle Identity Cloud Service (OIDC) connector in the Maverics Console:
1. Navigate to **Identity Fabric** in the Console sidebar.
2. Click **Create** and select **Oracle Identity Cloud Service (OIDC)**.
3. Enter a **Name** -- this is the friendly name that identifies your Oracle IDCS provider.
4. Enter the **OIDC Well Known URL** -- for Oracle IDCS, this follows the pattern `https://{idcs-instance}.identity.oraclecloud.com/.well-known/openid-configuration`.
5. Enter the **OAuth Client ID** -- the client ID from your Oracle IDCS application registration.
6. Enter the **OAuth Client Secret** -- the client secret from your Oracle IDCS application registration.
7. Under **Redirect URLs**, add the callback URL where Oracle IDCS will redirect after authentication. This URL must match the Redirect URL configured in your IDCS application.
8. Optionally configure **Logout Callback URLs** for single logout support.
9. Optionally set **Scopes** (space-separated). Default scopes are typically `openid profile email`.
10. The **PKCE** toggle is enabled by default. Disable it only if your Oracle IDCS application is not configured to support Proof Key for Code Exchange.
11. Optionally enable **Offline Access** for token refresh support (Proxy apps only).
12. Click **Save**.
```yaml maverics.yaml theme={null}
connectors:
- name: oracle-idcs
type: oidc
oidcWellKnownURL: "https://{{ env.IDCS_INSTANCE }}.identity.oraclecloud.com/.well-known/openid-configuration"
oauthClientID: "{{ env.IDCS_CLIENT_ID }}"
oauthClientSecret:
oauthRedirectURL: "https://app.example.com/oidc/callback"
scopes: "openid profile email"
```
## Configuration Reference
| Key | Type | Required | Description |
| ------------------- | ------ | -------- | -------------------------------------------------------------- |
| `name` | string | Yes | Unique connector identifier referenced in app policies |
| `type` | string | Yes | Must be `oidc` |
| `oidcWellKnownURL` | string | Yes | OIDC discovery endpoint URL for your Oracle IDCS instance |
| `oauthClientID` | string | Yes | OAuth 2.0 client ID from the Oracle IDCS application |
| `oauthClientSecret` | string | Yes | OAuth 2.0 client secret (use secret reference syntax) |
| `oauthRedirectURL` | string | Yes | Callback URL registered with the Oracle IDCS application |
| `scopes` | string | No | Space-separated OAuth scopes (default: `openid profile email`) |
| `tls` | string | No | Named TLS profile for provider communication |
For the complete field reference including health checks, offline access, and PKCE settings, see [Identity Fabric](/reference/orchestrator/identity-fabric#configuration-reference).
## Troubleshooting
* **Verify the `oidcWellKnownURL` is accessible** from the Orchestrator host -- ensure the IDCS instance name is correct and the URL resolves to the Oracle IDCS discovery document
* **Ensure the `oauthRedirectURL` matches exactly** what is registered in the Oracle IDCS application under Redirect URLs
* **Check that the client secret reference resolves correctly** via your secret provider
* **Verify IDCS application is activated** -- Oracle IDCS applications must be in an active state before they can process authentication requests
## Related Pages
Overview of all identity providers
Generic OpenID Connect connector
LDAP-based connector for Oracle Universal Directory
IdP failover connector
# Oracle Universal Directory (LDAP)
Source: https://docs.strata.io/reference/orchestrator/identity-fabric/oracle-oud
The Oracle Universal Directory connector integrates the Maverics Orchestrator with Oracle Unified Directory (OUD) using the LDAP protocol -- enabling attribute lookups and directory queries against an Oracle directory service.
**Console terminology:** In the Maverics Console, this section is called
**Identity Fabric**. The YAML configuration uses the `connectors` key to define
identity provider integrations.
## Overview
The Oracle Universal Directory connector functions as an LDAP attribute provider. It retrieves user attributes from Oracle Unified Directory for header injection, claim enrichment, or authorization decisions. For general-purpose LDAP directories, see the [LDAP connector](/reference/orchestrator/identity-fabric/ldap). For Microsoft Active Directory environments, see the [Active Directory connector](/reference/orchestrator/identity-fabric/activedirectory).
## Use Cases
* **Unify SSO across Oracle and non-Oracle stacks** -- Enrich sessions with OUD attributes so applications across Oracle and non-Oracle environments receive consistent identity data through a single orchestration layer
* **Simplify Oracle directory consolidation** -- Route OUD attribute lookups through the Orchestrator to reduce direct directory integrations per application, supporting consolidation of Oracle identity infrastructure
* **Cross-platform identity enrichment** -- Combine OIDC or SAML authentication from a cloud IdP with OUD attribute lookups, bridging identity data between Oracle directories and modern identity providers
* **Legacy Oracle app header injection** -- Look up user attributes in OUD and inject them as HTTP headers for legacy Oracle applications that depend on header-based identity
## Setup
To create an Oracle Universal Directory (LDAP) connector in the Maverics Console:
1. Navigate to **Identity Fabric** in the Console sidebar.
2. Click **Create** and select **Oracle Universal Directory (LDAP)**.
3. Enter a **Name** -- the friendly name for your OUD connector.
4. Enter the **URL** of the OUD LDAP server (e.g., `ldaps://oud.example.com:636`).
5. Enter the **Base DN** -- the search base for LDAP queries (e.g., `dc=example,dc=com`).
6. Enter the **Service Account Username** -- the bind DN used to connect to OUD.
7. Enter the **Service Account Password** -- use the show/hide toggle to verify the value.
8. Optionally set an **Attribute Delimiter** for multi-valued attributes (default: `,`).
9. Enter the **OUD Search Key** -- the attribute used for looking up user and group data (e.g., `uid` or `cn`).
10. Click **Save**.
```yaml maverics.yaml theme={null}
connectors:
- name: oracle-oud
type: ldap
url:
- "ldaps://{{ env.OUD_HOST }}:636"
serviceAccountUsername: "cn=admin,dc=example,dc=com"
serviceAccountPassword:
baseDN: "dc=example,dc=com"
usernameSearchKey: uid
userAttributes:
- cn
- mail
- memberOf
attributeMapping:
email: mail
name: cn
tls: oud-tls
```
## Configuration Reference
| Key | Type | Required | Description |
| ------------------------ | --------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `name` | string | Yes | Unique connector identifier referenced by app policies and attribute providers |
| `type` | string | Yes | Must be `ldap` |
| `url` | string\[] | Yes | OUD server URLs -- supports `ldap://` (port 389) and `ldaps://` (port 636); multiple URLs enable failover |
| `serviceAccountUsername` | string | Yes | Bind DN for the service account (e.g., `cn=admin,dc=example,dc=com`) |
| `serviceAccountPassword` | string | Yes | Service account password -- use secret reference syntax `` |
| `baseDN` | string | Yes | Base DN for LDAP searches (e.g., `dc=example,dc=com`) |
| `usernameSearchKey` | string | No | LDAP attribute used for username lookup (e.g., `uid` or `cn`) |
| `userAttributes` | string\[] | No | LDAP attributes to retrieve during searches (e.g., `["cn", "mail", "memberOf"]`) |
| `attributeMapping` | map | No | Map Orchestrator attribute names to LDAP attribute names (e.g., `email: "mail"`) |
| `attributeDelimiter` | string | No | Delimiter for multi-valued LDAP attributes (default: `","`) |
| `tls` | string | No | Named TLS profile for LDAP connection |
| `healthCheck` | object | No | Health check monitoring configuration (see [Identity Fabric Configuration Reference](/reference/orchestrator/identity-fabric#configuration-reference)) |
For the complete connector field reference including health check details, see [Identity Fabric Configuration Reference](/reference/orchestrator/identity-fabric#configuration-reference).
## Troubleshooting
* **Test LDAP connectivity from the Orchestrator host** -- Use `ldapsearch` or a similar tool to verify the Orchestrator can reach the OUD server on the configured port. Network firewalls or DNS issues are common causes of connection failures.
* **Verify the service account has read permissions on the baseDN** -- The bind DN specified in `serviceAccountUsername` must have sufficient permissions to search the `baseDN` subtree and read the configured attributes.
* **For LDAPS, ensure the TLS profile includes the correct CA certificate** -- If the OUD server uses a private CA, the TLS profile referenced by the `tls` field must include the CA certificate via `caFile`.
* **Check attribute names in mapping** -- LDAP attribute names must match the Oracle Unified Directory schema. Common OUD attributes include `uid`, `cn`, `mail`, and `memberOf`.
## Related Pages
OIDC connector for Oracle IDCS
General-purpose LDAP connector
LDAP-based connector for Microsoft Active Directory
Overview of all identity providers
# PingFederate (SAML)
Source: https://docs.strata.io/reference/orchestrator/identity-fabric/pingfederate-saml
The PingFederate (SAML) connector integrates the Maverics Orchestrator with Ping Identity's PingFederate server using the SAML 2.0 protocol -- providing an alternative to the OIDC-based PingFederate connector for environments that require SAML federation.
**Console terminology:** In the Maverics Console, this section is called
**Identity Fabric**. The YAML configuration uses the `connectors` key to define
identity provider integrations.
## Overview
The PingFederate (SAML) connector supports SAML 2.0 SSO profiles including SP-initiated and IdP-initiated flows. For OpenID Connect-based integration, see the [PingFederate (OIDC) connector](/reference/orchestrator/identity-fabric/pingone). Use the SAML variant when your environment requires SAML-based federation or when integrating with applications that only support SAML assertions.
## Use Cases
* **Unify SSO across PingFederate and other IdPs** -- Orchestrate PingFederate SAML alongside other identity providers to deliver seamless access across hybrid cloud and on-prem environments
* **Legacy application modernization** -- Bridge PingFederate SAML assertions to header-based or cookie-based authentication for legacy applications, extending SSO without rewriting them
* **Rationalize Ping licensing costs** -- Consolidate authentication workloads by routing apps away from PingFederate to a target IdP, reducing the number of Ping connections and associated licensing fees
* **PingFederate failover with Continuity** -- Pair PingFederate SAML with a backup IdP to maintain authentication availability if the PingFederate server becomes unreachable
## Setup
To create a Ping Federate (SAML) connector in the Maverics Console:
1. Navigate to **Identity Fabric** in the Console sidebar.
2. Click **Create** and select **Ping Federate (SAML)**.
The Console also offers **Ping Federate (OIDC)** for OpenID Connect-based integration. See the [PingFederate (OIDC) page](/reference/orchestrator/identity-fabric/pingone) for details.
3. Enter a **Name** -- the friendly name for your PingFederate SAML provider.
4. Enter the **Metadata URL** -- the URL of the PingFederate SAML metadata document (e.g., `https://{your-pingfederate-host}/pf/federation_metadata.ping?PartnerSpId={sp-entity-id}`).
5. Enter the **Consumer Service (ACS) URL** -- the Assertion Consumer Service URL where PingFederate sends SAML responses.
6. Enter the **Entity ID** -- the unique identifier for the Orchestrator as the SAML Service Provider.
7. Optionally enter a **Logout Callback URL** for Single Logout (SLO) callback.
8. Optionally enter the **SP Certificate Path** and **SP Private Key Path** for signing SAML requests.
9. Optionally enable **IdP Initiated Login** to allow authentication flows started by PingFederate.
10. Click **Save**.
```yaml maverics.yaml theme={null}
connectors:
- name: pingfederate-saml
type: saml
samlMetadataURL: "https://{{ env.PING_HOST }}/pf/federation_metadata.ping?PartnerSpId={{ env.SP_ENTITY_ID }}"
samlConsumerServiceURL: "https://orch.example.com/saml/callback"
samlEntityID: "https://orch.example.com"
tls: ping-tls
```
## Configuration Reference
| Key | Type | Required | Description |
| ------------------------ | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `name` | string | Yes | Unique connector identifier referenced by app policies and attribute providers |
| `type` | string | Yes | Must be `saml` |
| `samlMetadataURL` | string | Yes | URL to the PingFederate SAML metadata XML |
| `samlConsumerServiceURL` | string | Yes | Assertion Consumer Service (ACS) URL where PingFederate sends SAML responses |
| `samlEntityID` | string | No | Service Provider entity ID that identifies the Orchestrator to PingFederate |
| `samlLogoutCallbackURL` | string | No | Logout callback URL for SAML single logout |
| `samlSPCertPath` | string | No | Path to the SP certificate file for signing SAML requests |
| `samlSPKeyPath` | string | No | Path to the SP private key file for signing SAML requests |
| `samlIDPInitiatedLogin` | object | No | IdP-initiated login configuration |
| `cache` | string | No | Cache name reference for SAML request data storage |
| `tls` | string | No | Named TLS profile for metadata retrieval and IdP communication |
| `healthCheck` | object | No | Health check monitoring configuration (see [Identity Fabric Configuration Reference](/reference/orchestrator/identity-fabric#configuration-reference)) |
For the complete connector field reference including health check details, see [Identity Fabric Configuration Reference](/reference/orchestrator/identity-fabric#configuration-reference).
## Troubleshooting
* **Verify the PingFederate metadata URL is accessible** -- The Orchestrator fetches the metadata XML at startup. Ensure the PingFederate hostname and port are correct and the metadata endpoint is enabled.
* **Ensure the entity ID matches PingFederate's SP connection** -- The `samlEntityID` value must match the Partner Entity ID configured in the PingFederate SP Connection settings.
* **Check the Assertion Consumer Service URL** -- The `samlConsumerServiceURL` must match the ACS URL configured in the PingFederate SP Connection. If behind a load balancer, use the external-facing URL.
* **SP signing certificate errors** -- If PingFederate requires signed authentication requests, ensure `samlSPCertPath` and `samlSPKeyPath` point to valid PEM files and the key matches the certificate.
## Related Pages
OIDC-based PingFederate connector
Generic SAML 2.0 connector
Overview of all identity providers
IdP failover connector
# PingFederate (OIDC)
Source: https://docs.strata.io/reference/orchestrator/identity-fabric/pingone
The PingFederate connector integrates the Maverics Orchestrator with Ping Identity's PingFederate server -- enabling OIDC-based single sign-on for your applications.
**Console terminology:** In the Maverics Console, this section is called
**Identity Fabric**. The YAML configuration uses the `connectors` key to define
identity provider integrations.
## Overview
The PingFederate connector uses OpenID Connect to federate authentication with PingFederate and supports standard OIDC flows -- allowing you to extend PingFederate authentication to applications that don't natively support modern identity protocols.
This connector integrates with PingFederate, Ping Identity's on-premises federation server. The connector type in YAML is `pingfederate`.
## Use Cases
* **Unify SSO across PingFederate-managed apps** -- Extend PingFederate authentication to legacy applications via header or cookie injection, delivering seamless SSO without modifying existing applications
* **Rationalize identity platforms** -- Orchestrate a phased migration away from PingFederate to a target IdP, reducing Ping licensing costs while maintaining uninterrupted access during the transition
* **Authentication resilience** -- Pair PingFederate with a secondary identity provider for automatic failover, ensuring users retain access if PingFederate becomes unavailable
* **Multi-IdP orchestration** -- Route authentication to PingFederate alongside other identity providers based on user context, enabling coexistence during mergers or multi-vendor environments
## Setup
To create a Ping Federate (OIDC) connector in the Maverics Console:
1. Navigate to **Identity Fabric** in the Console sidebar.
2. Click **Create** and select **Ping Federate (OIDC)**.
The Console also offers **Ping Federate (SAML)** for SAML-based integration. This page covers the OIDC variant. Select **Ping Federate (OIDC)** for OpenID Connect federation.
3. Enter a **Name** for the connector -- this is the friendly name that identifies your PingFederate integration.
4. Enter the **OIDC Well Known URL** -- the OpenID Connect discovery endpoint for your PingFederate server (e.g., `https://your-pingfederate-host/.well-known/openid-configuration`).
5. Enter the **OAuth Client ID** -- the client ID of the application registered in PingFederate.
6. Enter the **OAuth Client Secret** -- the client secret associated with the client ID. Use the show/hide toggle to verify the value.
7. Add one or more **Redirect URLs** -- the callback URL(s) where PingFederate redirects users after authentication. The Maverics OIDC handler will be served on this URL.
8. Optionally add **Logout Callback URLs** -- the URL(s) that PingFederate calls after a successful logout.
9. Optionally enter **Scopes** -- space-separated OIDC scopes to request (e.g., `openid profile email`). If left empty, default scopes are used.
10. **Proof Key for Code Exchange (PKCE)** is enabled by default. Disable this toggle only if your PingFederate server is not configured to support PKCE.
11. Optionally enable **Offline Access** if you need refresh tokens. When enabled, set your policy's `decision.lifetime` slightly longer than the interval for token refreshing.
12. Click **Save**.
```yaml theme={null}
connectors:
- name: pingfederate
type: pingfederate
oidcWellKnownURL: "https://{{ env.PING_HOST }}/.well-known/openid-configuration"
oauthClientID: "{{ env.PING_CLIENT_ID }}"
oauthClientSecret:
oauthLoginRedirect:
urls:
- https://app.example.com/oidc/callback
```
## Configuration Reference
| Key | Type | Required | Description |
| ------------------------- | ------ | -------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `name` | string | Yes | Unique connector identifier referenced in app policies |
| `type` | string | Yes | Must be `pingfederate` |
| `oidcWellKnownURL` | string | Yes | OIDC discovery endpoint URL for your PingFederate server |
| `oauthClientID` | string | Yes | OAuth 2.0 client ID from PingFederate |
| `oauthClientSecret` | string | Yes | OAuth 2.0 client secret (use secret reference syntax) |
| `oauthLoginRedirect.urls` | list | Yes | Callback URL(s) registered with the PingFederate client. The Orchestrator selects the URL whose host matches the incoming request. |
| `tls` | string | No | Named TLS profile for provider communication |
For the complete field reference including health checks, offline access, and PKCE settings, see [Identity Fabric](/reference/orchestrator/identity-fabric#configuration-reference).
## Troubleshooting
* **Verify the `oidcWellKnownURL` is accessible** from the Orchestrator host -- ensure the PingFederate hostname and port are correct
* **Ensure each URL in `oauthLoginRedirect.urls` matches exactly** what is registered in the PingFederate client configuration
* **Check that the client secret reference resolves correctly** via your secret provider
## Related Pages
Overview of all identity providers
Generic OpenID Connect connector
OIDC connector for Okta
Failover connector for IdP high availability
# Trusona (OIDC)
Source: https://docs.strata.io/reference/orchestrator/identity-fabric/trusona
The Trusona connector integrates the Maverics Orchestrator with Trusona -- enabling OIDC-based passwordless authentication and identity verification.
**Console terminology:** In the Maverics Console, this section is called
**Identity Fabric**. The YAML configuration uses the `connectors` key to define
identity provider integrations.
## Overview
The Trusona connector uses OpenID Connect. Trusona specializes in passwordless authentication and identity proofing -- making it a strong choice for environments that need to eliminate passwords or verify user identity with high assurance.
## Use Cases
* **Passwordless authentication** -- Replace password-based login with Trusona's passwordless verification, delivering a more secure and frictionless user experience across legacy and modern applications
* **Identity proofing for high-assurance access** -- Leverage Trusona's identity verification capabilities to confirm user identity before granting access to sensitive or regulated applications
* **Unify SSO with step-up verification** -- Orchestrate Trusona alongside a primary IdP to add identity proofing as a step-up authentication layer, extending strong verification to applications that don't natively support it
* **Authentication resilience** -- Include Trusona as part of a multi-IdP failover strategy, ensuring passwordless authentication remains available even if another identity provider experiences an outage
## Setup
To create a Trusona (OIDC) connector in the Maverics Console:
1. Navigate to **Identity Fabric** in the Console sidebar.
2. Click **Create** and select **Trusona (OIDC)**.
3. Enter a **Name** -- this is the friendly name that identifies your provider.
4. Enter the **OIDC Well Known URL** -- the Trusona OIDC discovery endpoint provided by your Trusona account.
5. Enter the **OAuth Client ID** -- the client ID from your Trusona application configuration.
6. Enter the **OAuth Client Secret** -- the client secret from your Trusona application configuration.
7. Under **Redirect URLs**, add the callback URL where Trusona will redirect after authentication. This URL must match the redirect URI configured in your Trusona application.
8. Optionally configure **Logout Callback URLs** for single logout support.
9. Optionally set **Scopes** (space-separated). Default scopes are typically `openid profile email`.
10. The **PKCE** toggle is enabled by default. Disable it only if your Trusona application is not configured to support Proof Key for Code Exchange.
11. Optionally enable **Offline Access** for token refresh support (Proxy apps only).
12. Click **Save**.
```yaml maverics.yaml theme={null}
connectors:
- name: trusona
type: oidc
oidcWellKnownURL: "https://{{ env.TRUSONA_HOST }}/.well-known/openid-configuration"
oauthClientID: "{{ env.TRUSONA_CLIENT_ID }}"
oauthClientSecret:
oauthRedirectURL: "https://app.example.com/oidc/callback"
scopes: "openid profile email"
```
## Configuration Reference
| Key | Type | Required | Description |
| ------------------- | ------ | -------- | -------------------------------------------------------------- |
| `name` | string | Yes | Unique connector identifier referenced in app policies |
| `type` | string | Yes | Must be `oidc` |
| `oidcWellKnownURL` | string | Yes | Trusona OIDC discovery endpoint URL |
| `oauthClientID` | string | Yes | OAuth 2.0 client ID from Trusona |
| `oauthClientSecret` | string | Yes | OAuth 2.0 client secret (use secret reference syntax) |
| `oauthRedirectURL` | string | Yes | Callback URL registered with the Trusona application |
| `scopes` | string | No | Space-separated OAuth scopes (default: `openid profile email`) |
| `tls` | string | No | Named TLS profile for provider communication |
For the complete field reference including health checks, offline access, and PKCE settings, see [Identity Fabric](/reference/orchestrator/identity-fabric#configuration-reference).
## Troubleshooting
* **Verify the well-known URL is accessible** from the Orchestrator host -- ensure the Trusona endpoint is correct
* **Ensure the redirect URL matches exactly** what is registered in your Trusona application
* **Check that the client secret reference resolves correctly** via your secret provider
* **Confirm the Trusona application is active** -- disabled applications will not respond to authentication requests
## Related Pages
Overview of all identity providers
Generic OpenID Connect connector
OIDC connector for Okta
OIDC connector for Keycloak
# Microsoft Windows Client Authenticator
Source: https://docs.strata.io/reference/orchestrator/identity-fabric/wca
The Windows Client Authenticator (WCA) allows Windows and IIS users to validate their identity to the Maverics Orchestrator using Windows desktop credentials. WCA runs as an IIS application that authenticates users via NTLM and communicates the result to the Orchestrator over HTTPS. WCA must be used with the Orchestrator -- it has no standalone value. The WCA installer is downloaded from your Maverics deployment.
**Console terminology:** In the Maverics Console, this section is called
**Identity Fabric**. The YAML configuration uses the `connectors` key to define
identity provider integrations.
## Overview
The Windows Client Authenticator connector authenticates users via their Windows desktop credentials using NTLM. Unlike OIDC or SAML connectors, WCA does not use a standard federation protocol -- it runs as a dedicated IIS application on a Windows server and communicates directly with the Orchestrator over HTTPS.
WCA only supports **login functionality**. It does not retrieve user attributes beyond the authenticated username. For additional attributes such as email, display name, or group memberships, pair the WCA connector with an [Attribute Provider](/reference/orchestrator/identity-fabric/activedirectory) such as Active Directory.
## Use Cases
* **Unified SSO for Windows desktop environments** -- Extend single sign-on to web applications using existing Windows domain credentials via NTLM, so users on domain-joined machines authenticate seamlessly without additional passwords
* **Legacy Windows app modernization** -- Bridge NTLM-authenticated Windows environments with modern cloud IdPs through the Orchestrator, enabling a unified authentication experience across on-premises and cloud applications
* **Seamless Kerberos/NTLM-to-web SSO** -- Authenticate users with their Windows desktop session and pass identity to the Orchestrator, eliminating separate login prompts for web applications in enterprise Windows environments
* **Attribute-enriched Windows authentication** -- Pair WCA with an [Active Directory attribute provider](/reference/orchestrator/identity-fabric/activedirectory) to retrieve group memberships, email, and other directory attributes alongside NTLM authentication
## Requirements
| Requirement | Details |
| ---------------- | ------------------------------------------------------------------------------------------------------------------ |
| Operating system | Windows Server 2008 R2 or later |
| IIS | Internet Information Services with web server features enabled |
| .NET runtime | .NET 7.0.13 Windows Server Hosting bundle (the installer will install the bundle for you if not already installed) |
| Permissions | Administrator privileges on the Windows server |
## Installation
Follow these steps to install and configure the WCA on your IIS server:
Run the WCA installer downloaded from your Maverics deployment. The installer creates an IIS application for the WCA.
Open IIS Manager and navigate to the WCA application.
Under the WCA application's **Authentication** settings, enable both **Anonymous Authentication** and **Windows Authentication**.
WCA v2.x and later requires Anonymous Authentication to be enabled for the `/status` health endpoint.
Under **Windows Authentication** > **Providers**, ensure **NTLM** is the only enabled provider.
Configure the IIS site bindings with HTTPS and the appropriate hostname for your environment. This hostname is the URL you will use in the Orchestrator connector configuration.
## Upgrading from Previous Versions
When upgrading to WCA v2.x or later, **Anonymous Authentication must be enabled** in IIS. Previous versions of WCA had Anonymous Authentication disabled. This change is required for the `/status` health endpoint to function correctly.
## Status Endpoint
The WCA exposes a health endpoint at `/status` that returns `OK` with HTTP 200 when the WCA application is running correctly. Use this endpoint for monitoring and health checks.
## Setup
To create a Microsoft Windows Client Authenticator connector in the Maverics Console:
1. Navigate to **Identity Fabric** in the Console sidebar.
2. Click **Create** and select **Microsoft Windows Client Authenticator**.
3. Enter a **Name** for the connector.
4. Enter the **URL** of the WCA server -- this must match the IIS site binding hostname (e.g., `https://wca.corp.example.com`).
5. Optionally enter a **CA Path** if the IIS server uses a self-signed or internal CA certificate.
6. Click **Save**.
```yaml maverics.yaml theme={null}
connectors:
- name: wca
type: windowsclientauthenticator
url: https://wca-iis2019.testad.local
tls: wca-tls
```
## Configuration with Maverics
After installing the WCA on your IIS server:
1. **Set a friendly name** -- The `name` field is the unique identifier for this connector, referenced by app policies and attribute providers.
2. **Set the URL** -- The `url` field must match the hostname binding you configured in IIS (e.g., `https://wca.corp.example.com`).
3. **Optionally set TLS** -- If the IIS server uses a self-signed or internal CA certificate, reference a named TLS profile with the `tls` field. The TLS profile should include the CA certificate via `caFile`.
## Configuration Reference
| Key | Type | Required | Description |
| ------ | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------ |
| `name` | string | Yes | Unique connector identifier referenced by app policies and attribute providers |
| `type` | string | Yes | Must be `windowsclientauthenticator` |
| `url` | string | Yes | URL of the WCA hostname binding on the IIS server (e.g., `https://wca.corp.example.com`) |
| `tls` | string | No | Named TLS profile for communication with the WCA -- use when the IIS server has a self-signed or internal CA certificate |
For the complete connector field reference, see [Identity Fabric Configuration Reference](/reference/orchestrator/identity-fabric#configuration-reference).
## Testing
To verify the WCA is working correctly:
1. Open a browser and navigate to the WCA URL (e.g., `https://wca.corp.example.com`).
2. Enter your Windows credentials when prompted.
3. The landing page displays the authenticated username, confirming that NTLM authentication is functioning.
## NTLM Seamless Authentication
By default, browsers prompt users for credentials when accessing the WCA. You can configure browsers to pass Windows credentials automatically for a seamless single sign-on experience.
### Edge and Chrome
Go to **Internet Settings** > **Local Intranet** > **Advanced**. Under "Add this website to the zone:", add both the WCA site URL and the application URL.
### Firefox
1. Navigate to `about:config` in the Firefox address bar.
2. Add both the WCA site URL and the application URL (comma-separated) to:
* `network.automatic-ntlm-auth.trusted-uris`
* `network.negotiate-auth.delegation-uris`
* `network.negotiate-auth.trusted-uris`
3. Set `signon.autologin.proxy` to `true`.
## High Availability
WCA requires a **Layer 4 (network) load balancer** for high availability. Do **not** use a Layer 7 (application) load balancer -- Layer 7 load balancers terminate and re-establish TCP connections, which breaks the multi-step NTLM authentication handshake.
Use **source IP / destination IP / port tuple affinity** (sticky sessions based on client IP) to ensure all packets in an NTLM handshake reach the same backend IIS server.
### Architecture
The high availability architecture follows this flow:
**Client Machines** → **App Load Balancer** → **Orchestrator(s)** → **Network Load Balancer (Layer 4)** → **IIS Server(s) with WCA**
Using a Layer 7 load balancer in front of WCA servers will cause NTLM authentication failures. NTLM requires an unbroken TCP connection between the client (Orchestrator) and the server (WCA on IIS) across multiple request-response rounds. Layer 7 load balancers proxy at the HTTP level, breaking this connection continuity.
## Troubleshooting
NTLM authentication requires an unbroken TCP connection across multiple request-response rounds. Layer 7 (application) load balancers terminate and re-establish connections, breaking the handshake.
**Fix:** Replace the Layer 7 load balancer with a Layer 4 (network) load balancer. Configure source IP affinity to ensure all packets in a handshake reach the same backend server.
The `/status` endpoint requires Anonymous Authentication to be enabled in IIS. This is a common issue when upgrading from WCA versions prior to v2.x.
**Fix:** In IIS Manager, navigate to the WCA application's Authentication settings and enable **Anonymous Authentication**.
By default, browsers do not automatically send Windows credentials to intranet sites. Users will see a credential prompt on each access.
**Fix:** Configure NTLM seamless authentication in the browser or via Group Policy. See the [NTLM Seamless Authentication](#ntlm-seamless-authentication) section above.
The WCA installer requires the .NET 7.0.13 Windows Server Hosting bundle. If the bundle is not present, the installer will install the bundle for you, but this may fail if there are network or permission issues.
**Fix:** Manually download and install the [.NET 7 Windows Server Hosting bundle](https://dotnet.microsoft.com/en-us/download/dotnet/7.0) before running the WCA installer.
## Related Pages
Overview of all identity providers and supported types
IdP failover connector (WCA is not supported by Continuity)
Active Directory connector -- commonly paired with WCA for attribute retrieval
# WSO2 Identity Server (OIDC)
Source: https://docs.strata.io/reference/orchestrator/identity-fabric/wso2
The WSO2 connector integrates the Maverics Orchestrator with WSO2 Identity Server -- enabling OIDC-based single sign-on for applications that rely on WSO2 for identity management.
**Console terminology:** In the Maverics Console, this section is called
**Identity Fabric**. The YAML configuration uses the `connectors` key to define
identity provider integrations.
## Overview
The WSO2 connector uses OpenID Connect to federate authentication with WSO2 Identity Server. It supports standard OIDC authorization code flows -- allowing you to extend WSO2-managed identities to legacy and modern applications through the Maverics Orchestrator.
## Use Cases
* **Unify SSO with WSO2-managed identities** -- Extend WSO2 Identity Server authentication to legacy applications by translating OIDC tokens into header-based or cookie-based authentication
* **Rationalize identity infrastructure** -- Orchestrate a phased migration from WSO2 to a target IdP, reducing the cost and complexity of maintaining open-source identity server deployments
* **Authentication resilience** -- Pair WSO2 with a secondary identity provider for automatic failover, ensuring users retain access to critical applications if WSO2 becomes unavailable
* **Multi-IdP orchestration** -- Route authentication to WSO2 alongside commercial identity providers, enabling coexistence in complex enterprise environments
## Setup
WSO2 is not available as a dedicated option in the Maverics Console. To configure WSO2, use the **Generic OIDC Configuration** option:
1. Navigate to **Identity Fabric** in the Console sidebar.
2. Click **Create** and select **Generic OIDC Configuration**.
3. Enter a **Name** for the connector (e.g., `wso2`).
4. Enter the **OIDC Well Known URL** -- for WSO2, this follows the pattern `https://{wso2-host}/oauth2/oidcdiscovery/.well-known/openid-configuration`.
5. Enter the **OAuth Client ID** -- the client ID from your WSO2 service provider registration.
6. Enter the **OAuth Client Secret** -- the client secret from your WSO2 service provider registration.
7. Under **Redirect URLs**, add the callback URL where WSO2 will redirect after authentication.
8. Optionally configure **Logout Callback URLs** for single logout support.
9. Optionally set **Scopes** (space-separated). Default scopes are typically `openid profile email`.
10. The **PKCE** toggle is enabled by default. Disable it only if your WSO2 service provider is not configured to support Proof Key for Code Exchange.
11. Optionally enable **Offline Access** for token refresh support.
12. Click **Save**.
When using the Generic OIDC Configuration in the Console, the deployment configuration will use `type: oidc`. For the WSO2-specific `type: wso2`, use the YAML Configuration tab approach instead.
```yaml maverics.yaml theme={null}
connectors:
- name: wso2
type: wso2
oidcWellKnownURL: "https://{{ env.WSO2_HOST }}/oauth2/oidcdiscovery/.well-known/openid-configuration"
oauthClientID: "{{ env.WSO2_CLIENT_ID }}"
oauthClientSecret:
oauthLoginRedirect:
urls:
- https://app.example.com/oidc/callback
```
## Configuration Reference
| Key | Type | Required | Description |
| -------------------------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `name` | string | Yes | Unique connector identifier referenced in app policies |
| `type` | string | Yes | Must be `wso2` |
| `oidcWellKnownURL` | string | Yes | OIDC discovery endpoint URL for WSO2 Identity Server |
| `oauthClientID` | string | Yes | OAuth 2.0 client ID from the WSO2 service provider configuration |
| `oauthClientSecret` | string | Yes | OAuth 2.0 client secret (use secret reference syntax) |
| `oauthLoginRedirect.urls` | list | Yes | Callback URL(s) registered with the WSO2 service provider. The Orchestrator selects the URL whose host matches the incoming request. |
| `oauthLogoutRedirect.urls` | list | No | URL(s) called by WSO2 after a successful logout. |
| `tls` | string | No | Named TLS profile for provider communication |
For the complete field reference including health checks, offline access, and PKCE settings, see [Identity Fabric](/reference/orchestrator/identity-fabric#configuration-reference).
## Troubleshooting
* **Verify the well-known URL is accessible** from the Orchestrator host -- WSO2's OIDC discovery URL may vary by deployment; confirm the correct path
* **Ensure each URL in `oauthLoginRedirect.urls` matches exactly** what is registered in the WSO2 service provider configuration
* **Check that the client secret reference resolves correctly** via your secret provider
* **PKCE errors** -- If WSO2 returns errors during the authorization flow, verify that PKCE is enabled on both the Orchestrator and the WSO2 service provider
## Related Pages
Overview of all identity providers
Generic OpenID Connect connector
OIDC connector for Okta
OIDC connector for Auth0
# Installation
Source: https://docs.strata.io/reference/orchestrator/installation
**Console terminology:** In the Maverics Console, Orchestrator instances and
configuration delivery are managed through **Deployments**. When working directly
with YAML, configuration is managed as files delivered via the `-config` flag or
`MAVERICS_CONFIG` environment variable.
## System Requirements
Before installing the Orchestrator, ensure your environment meets the minimum requirements for your chosen deployment method.
### Hardware
* **CPU** -- 2+ cores recommended for production workloads
* **Memory** -- 1 GB minimum
* **Disk** -- 100 MB for the binary, additional space for cache. 1 GB recommended as a starting point
### Supported Operating Systems
| OS | Version | Architecture |
| ------------------------ | ----------------------- | ------------ |
| RHEL | 8+, 9+ | amd64 |
| Ubuntu | 22+ | amd64 |
| Debian | 12+ | amd64 |
| Windows | Server 2019, 2022, 2025 | amd64 |
| macOS (development only) | 26+ | arm64 |
### Network and Access
* **Port** -- 443 (HTTPS)
* **Network** -- Outbound HTTPS access from the Orchestrator host to your chosen cloud identity system
* **TLS** -- Valid TLS certificates for production deployments
* **Access** -- Root or administrator access required for installation and configuration
## Download the Orchestrator
All Orchestrator downloads are available through the **Maverics Console** at [maverics.strata.io](https://maverics.strata.io). Downloads are accessed from within a **Deployment** -- open any Deployment and use the **Download Orchestrator Software** modal.
The download experience is currently located inside Deployments rather than in the main Console navigation. To access the download modal, create or open a Deployment, then look for the download option in the Deployment detail view.
### Platform Installers
Platform installers are production-ready packages for deploying the Orchestrator to your infrastructure. The latest version is **v2026.02.1** (released February 5, 2026).
The Orchestrator is a stateless service that can be deployed on Linux, Windows, Docker, and optionally run on Kubernetes.
| Platform | File | Notes |
| --------------- | --------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| Windows | `maverics-orchestrator.msi` | Registers as a Windows service with guided setup for configuration source, TLS certificates, and environment variables |
| macOS | `maverics-orchestrator.zip` | Standalone binary archive — development and testing only, not for production |
| Red Hat | `maverics-rhlinux.rpm` | RPM package for RHEL-based distributions |
| Ubuntu / Debian | `maverics-package.deb` | DEB package for Debian-based distributions |
| Docker | `maverics-orchestrator.tar` | Pre-built container image (load with `docker load`) |
**FIPS 140-3 Builds** -- The Orchestrator offers experimental FIPS-compliant builds using a FIPS 140-3 validated cryptographic module. See [FIPS 140-3 Builds](/reference/orchestrator/experimental/fips) for current status, feature details, and availability.
### Other Resources
| Resource | File | Description |
| -------------------------------- | --------------------------------------------- | ---------------------------------------------------------- |
| Windows Client Authenticator App | `WindowsClientAuthenticatorAppforMaveric.exe` | Desktop authenticator application for Windows environments |
The Windows Client Authenticator App is also available from the Console download modal.
## Deployment Guides
Download Orchestrator packages from Artifactory for CI/CD pipelines
Platform-specific installation using RPM, DEB, MSI, or standalone binary
Load and run the Orchestrator as a container
Deploy to Kubernetes using the official Strata Helm chart
## CLI Flags
The `maverics` binary accepts the following flags. All flags use single-dash format (Go `flag` package convention).
| Flag | Type | Default | Description |
| ----------------- | ------ | ----------------------------- | --------------------------------------------------------------------------------- |
| `-config` | string | `/etc/maverics/maverics.yaml` | Configuration file path |
| `-secretProvider` | string | -- | Secret provider URL (e.g., `hashivault://vault.example.com/secret/data/maverics`) |
| `-version` | bool | false | Print the Maverics version and exit |
| `-verbose` | bool | false | Enable verbose (DEBUG) logging |
**Precedence:** CLI flag > environment variable > default value. For example, `-config /path/to/config.yaml` overrides the `MAVERICS_CONFIG` environment variable, which overrides the default path.
## Environment Variables
Environment variables provide an alternative to CLI flags for configuring the Orchestrator. This is particularly useful in containerized deployments where flags may not be practical.
| Variable | Purpose | Default |
| -------------------------- | ------------------------------------------------ | ------- |
| `MAVERICS_CONFIG` | Config file path (alternative to `-config` flag) | -- |
| `MAVERICS_SECRET_PROVIDER` | Secret provider URL | -- |
| `MAVERICS_DEBUG_MODE` | Enable DEBUG logging (`true`/`false`) | -- |
| `MAVERICS_HTTP_ADDRESS` | Override HTTP server bind address | -- |
## Post-Installation Verification
After installation, verify the Orchestrator is installed correctly and can start successfully.
```bash theme={null}
# Verify the binary is installed
maverics -version
# Start with a config file
maverics -config /etc/maverics/maverics.yaml
# Check the health endpoint (in another terminal)
curl -s https://localhost:9443/status
# Expected: {"status": "up"}
```
The health endpoint at `/status` returns a JSON response indicating the Orchestrator is running. The default listen address is `0.0.0.0:9443`, configurable via the `http.address` setting in your YAML configuration.
On Linux, the Orchestrator runs as user `maverics` under `systemd`.
## Related Pages
Configure the Orchestrator after installation
End-to-end quick-start guide
# Docker
Source: https://docs.strata.io/reference/orchestrator/installation/docker
The Orchestrator is available as a pre-built container image downloaded from the Maverics Console. You download the image as a `.tar` archive and load it into your local Docker image store with `docker load`. This approach works well for development, testing, and production environments where container orchestration is managed outside of Kubernetes.
## Load the Container Image
The Console provides a pre-built container image as a `.tar` archive (`maverics-orchestrator.tar`). Download it from the **Download Orchestrator Software** modal inside any Deployment in the Console.
Load the image into your local Docker image store:
```bash theme={null}
docker load -i maverics-orchestrator.tar
```
After loading, the image is available as `maverics-orchestrator`. Confirm the image was loaded successfully:
```bash theme={null}
docker images | grep maverics
```
Optionally, tag the image for organizational naming or version tracking:
```bash theme={null}
docker tag maverics-orchestrator:latest my-registry.example.com/maverics-orchestrator:v2026.02.1
```
## Run the Container
Start the Orchestrator container with port mappings for HTTP traffic and TLS, volume mounts for configuration and certificates, and any required environment variables:
```bash theme={null}
docker run -d \
--name maverics \
-p 8080:8080 \
-p 9443:9443 \
-v /path/to/config:/etc/maverics \
-v /path/to/certs:/etc/maverics/certs \
-e MAVERICS_HTTP_ADDRESS=":8080" \
maverics-orchestrator
```
* `-p 8080:8080` -- HTTP traffic port
* `-p 9443:9443` -- HTTPS/TLS traffic port (health endpoint default)
* `-v` -- Mounts for configuration and TLS certificates
* `-e` -- Environment variables for runtime configuration
## Volume Mounts
The following volume mounts are recommended for production deployments:
| Host Path | Container Path | Purpose |
| ----------------- | --------------------- | ---------------------------------------------------------- |
| `/path/to/config` | `/etc/maverics` | Orchestrator YAML configuration files |
| `/path/to/certs` | `/etc/maverics/certs` | TLS certificates and private keys |
| `/path/to/logs` | `/var/log/maverics` | Log output directory (if file-based logging is configured) |
Mount configuration and certificate directories as read-only where possible to follow the principle of least privilege:
```bash theme={null}
-v /path/to/config:/etc/maverics:ro \
-v /path/to/certs:/etc/maverics/certs:ro
```
## Environment Variables
Environment variables can be passed to the container individually with `-e` flags or in bulk using an environment file:
```bash theme={null}
# Individual variables
docker run -e MAVERICS_HTTP_ADDRESS=":8080" -e MAVERICS_DEBUG_MODE="true" ...
# Environment file
docker run --env-file ./maverics.env ...
```
See [Environment Variables](/reference/orchestrator/installation#environment-variables) for the complete list of supported variables.
## Docker Compose Example
A `docker-compose.yml` for running the Orchestrator with persistent configuration and TLS:
```yaml theme={null}
services:
maverics:
image: maverics-orchestrator:latest
container_name: maverics-orchestrator
ports:
- "8080:8080"
- "9443:9443"
volumes:
- ./config:/etc/maverics:ro
- ./certs:/etc/maverics/certs:ro
environment:
- MAVERICS_HTTP_ADDRESS=:8080
restart: unless-stopped
```
Start the service:
```bash theme={null}
docker compose up -d
```
Verify the Orchestrator is running:
```bash theme={null}
curl -s https://localhost:9443/status
# Expected: {"status": "up"}
```
## Stable Deployment Identity
The Orchestrator includes a [`soid`](/introduction/glossary#soid-secure-orchestrator-id) field in every log entry for identifying and correlating logs by instance. By default, each container receives a unique `soid` because containers have ephemeral machine identities -- this is the expected behavior for horizontally scaled deployments where each container is a distinct instance.
For singleton deployment scenarios where you want the same `soid` to persist across container restarts (for example, a single Orchestrator container that gets recreated during updates), mount a stable `/etc/machine-id` file into the container:
```bash theme={null}
docker run -d \
--name maverics \
-v /etc/machine-id:/etc/machine-id:ro \
-v /path/to/config:/etc/maverics:ro \
-p 8080:8080 \
-p 9443:9443 \
maverics-orchestrator
```
Or in Docker Compose:
```yaml theme={null}
services:
maverics:
image: maverics-orchestrator:latest
volumes:
- /etc/machine-id:/etc/machine-id:ro
- ./config:/etc/maverics:ro
- ./certs:/etc/maverics/certs:ro
```
See [Logging — Deployment Correlation](/reference/orchestrator/telemetry/logging#deployment-correlation) for more on how the `soid` field is used.
## In-Place Config Reload
The Orchestrator applies configuration changes in place with zero downtime when
it detects a config change. Three settings enable this in Docker:
### 1. Enable reload polling
Pass `MAVERICS_RELOAD_CONFIG=true` to the container:
```bash theme={null}
docker run -e MAVERICS_RELOAD_CONFIG=true ...
```
### 2. Ensure a writable temp directory
The Orchestrator creates a Unix domain socket under `$TMPDIR` to coordinate the
handoff. In standard Docker containers `/tmp` is writable, so no additional
configuration is needed.
If you run the container with `--read-only`, mount a writable tmpfs and point
`TMPDIR` to it:
```bash theme={null}
docker run --read-only \
--tmpfs /run/maverics:rw,noexec,nosuid \
-e TMPDIR=/run/maverics \
-e MAVERICS_RELOAD_CONFIG=true \
...
```
### 3. Mount a stable machine identity
The Orchestrator uses `/etc/machine-id` to derive the handoff socket path. If it
computes a different path across the reload (which happens when the file is missing
and it falls back to a random UUID), the reload applies the new config but
in-flight state (sessions, caches) is lost.
Mount the host's `/etc/machine-id` into the container. This is the same mount
shown in [Stable Deployment Identity](#stable-deployment-identity) — it serves
both log correlation and state-preserving reloads:
```bash theme={null}
docker run -v /etc/machine-id:/etc/machine-id:ro ...
```
### Docker Compose example
A complete `docker-compose.yml` with all three settings:
```yaml theme={null}
services:
maverics:
image: maverics-orchestrator:latest
container_name: maverics-orchestrator
ports:
- "8080:8080"
- "9443:9443"
volumes:
- ./config:/etc/maverics:ro
- ./certs:/etc/maverics/certs:ro
- /etc/machine-id:/etc/machine-id:ro
environment:
- MAVERICS_HTTP_ADDRESS=:8080
- MAVERICS_RELOAD_CONFIG=true
restart: unless-stopped
```
If your config file is mounted read-only from a host directory and you update it
in place, the Orchestrator detects the change within the polling interval (default
30s) and performs the reload automatically — no `docker restart` required.
See the [troubleshoot guide](/guides/operations/troubleshoot#configuration-issues) for diagnostic commands if reloads are not taking effect.
## Related Pages
System requirements, download options, CLI flags, and environment variables
Configure the Orchestrator after installation
End-to-end quick-start guide
# Kubernetes (Helm)
Source: https://docs.strata.io/reference/orchestrator/installation/kubernetes
Deploy the Orchestrator to Kubernetes using the [official Strata Helm chart](https://github.com/strata-io/helm-charts). The charts are available publicly on GitHub -- they are not downloaded through the Console.
## Prerequisites
* **Kubernetes** 1.24.0 or later
* **Helm** 3.x
## Container Image
The Orchestrator container image is downloaded from the Maverics Console -- it is not available from a public container registry. For Kubernetes deployments, you must push this image to a container registry accessible by your cluster.
### Load and Push to a Registry
Start by downloading the container image tarball (`maverics-orchestrator.tar`) from the **Download Orchestrator Software** modal inside any Deployment in the Console. Load it into your local Docker image store, then tag and push it to your private registry.
```bash theme={null}
# Load the Console-provided image
docker load -i maverics-orchestrator.tar
```
Push the loaded image to your cloud provider's container registry:
```bash theme={null}
# Authenticate to ECR
aws ecr get-login-password --region us-east-1 | \
docker login --username AWS --password-stdin 123456789012.dkr.ecr.us-east-1.amazonaws.com
# Create the repository (first time only)
aws ecr create-repository --repository-name maverics-orchestrator --region us-east-1
# Tag and push
docker tag maverics-orchestrator:latest \
123456789012.dkr.ecr.us-east-1.amazonaws.com/maverics-orchestrator:v2026.02.1
docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/maverics-orchestrator:v2026.02.1
```
```bash theme={null}
# Authenticate to Artifact Registry
gcloud auth configure-docker us-central1-docker.pkg.dev
# Create the repository (first time only)
gcloud artifacts repositories create maverics \
--repository-format=docker --location=us-central1
# Tag and push
docker tag maverics-orchestrator:latest \
us-central1-docker.pkg.dev/my-project/maverics/orchestrator:v2026.02.1
docker push us-central1-docker.pkg.dev/my-project/maverics/orchestrator:v2026.02.1
```
```bash theme={null}
# Authenticate to ACR
az acr login --name myregistry
# Tag and push
docker tag maverics-orchestrator:latest \
myregistry.azurecr.io/maverics-orchestrator:v2026.02.1
docker push myregistry.azurecr.io/maverics-orchestrator:v2026.02.1
```
### Configure Kubernetes Image Pull
After pushing to a private registry, configure the Helm chart to pull from it by setting the `image` values:
```yaml theme={null}
image:
repository: 123456789012.dkr.ecr.us-east-1.amazonaws.com/maverics-orchestrator
tag: "v2026.02.1"
pullPolicy: IfNotPresent
```
There are two approaches for authenticating your cluster to pull from the private registry.
**Option 1: Image pull secrets** (works with all registries):
```bash theme={null}
# Create the pull secret
kubectl create secret docker-registry maverics-pull-secret \
--docker-server=123456789012.dkr.ecr.us-east-1.amazonaws.com \
--docker-username=AWS \
--docker-password=$(aws ecr get-login-password --region us-east-1) \
-n maverics
```
Reference the secret in your Helm values:
```yaml theme={null}
imagePullSecrets:
- name: maverics-pull-secret
```
ECR tokens expire after 12 hours. For production AWS deployments, use workload IAM (Option 2) instead of image pull secrets to avoid token rotation issues.
**Option 2: Workload IAM** (recommended for cloud-managed clusters):
Workload IAM lets Kubernetes pods authenticate to your cloud provider's container registry without static credentials. This is the recommended approach for production deployments.
IAM Roles for Service Accounts (IRSA) lets Kubernetes pods assume an IAM role to pull from ECR without static credentials.
**Prerequisites:** EKS cluster with OIDC provider enabled.
**Steps:**
1. Create an IAM policy granting `ecr:GetDownloadUrlForLayer`, `ecr:BatchGetImage`, and `ecr:GetAuthorizationToken`
2. Create an IAM role with a trust policy for the EKS OIDC provider
3. Annotate the ServiceAccount via Helm values:
```yaml theme={null}
serviceAccount:
create: true
annotations:
eks.amazonaws.com/role-arn: "arn:aws:iam::123456789012:role/maverics-ecr-access"
```
With IRSA configured, no `imagePullSecrets` are needed.
GCP Workload Identity binds a Kubernetes ServiceAccount to a Google Cloud service account for keyless registry access.
**Steps:**
1. Create a Google Cloud service account with `roles/artifactregistry.reader`
2. Bind it to the Kubernetes ServiceAccount using `gcloud iam service-accounts add-iam-policy-binding`
3. Annotate the ServiceAccount via Helm values:
```yaml theme={null}
serviceAccount:
create: true
annotations:
iam.gke.io/gcp-service-account: "maverics-reader@my-project.iam.gserviceaccount.com"
```
Azure Workload Identity enables pods to authenticate to ACR using federated identity credentials.
**Steps:**
1. Create a managed identity with `AcrPull` role on the ACR
2. Establish a federated credential for the Kubernetes ServiceAccount
3. Configure Helm values:
```yaml theme={null}
serviceAccount:
create: true
annotations:
azure.workload.identity/client-id: ""
podLabels:
azure.workload.identity/use: "true"
```
The [Security](#security) subsection of Key Chart Settings mentions ServiceAccount annotations for cloud IAM integration -- this section provides the specific configuration details for each cloud provider.
## Install and Uninstall
```bash theme={null}
# Add the Strata Helm repository
helm repo add strata https://strata-io.github.io/helm-charts
helm repo update
# Install the Orchestrator
helm install my-orchestrator strata/orchestrator
# Uninstall
helm delete my-orchestrator
```
Customize the installation with a values file (`-f values.yaml`) or inline overrides (`--set key=value`).
## Key Chart Settings
The sections below surface the most commonly configured chart settings. For the complete list, see [All Available Options](#all-available-options).
### Image and Replicas
| Setting | Default | Description |
| ------------------ | --------------------- | ---------------------------------------------- |
| `replicaCount` | `1` | Number of Orchestrator pods |
| `image.repository` | `strata/orchestrator` | Container image repository |
| `image.tag` | Chart appVersion | Image tag (defaults to the chart's appVersion) |
| `image.pullPolicy` | `IfNotPresent` | Image pull policy |
| `imagePullSecrets` | `[]` | Secrets for private registries |
### Networking
| Setting | Default | Description |
| ----------------- | ----------- | ------------------------------------------------------ |
| `service.type` | `ClusterIP` | Service type (`ClusterIP`, `LoadBalancer`, `NodePort`) |
| `service.port` | `8080` | Service port |
| `ingress.enabled` | `false` | Enable Ingress resource creation |
| `hostNetwork` | `false` | Use host networking (bypasses kube-proxy) |
When Ingress is enabled, configure `ingress.hosts`, `ingress.paths`, and `ingress.tls` for TLS termination at the Ingress controller.
### Security
The chart ships with secure defaults: the container runs as a non-root user (UID 10001), drops all Linux capabilities, uses a read-only root filesystem, and applies a `RuntimeDefault` seccomp profile. A ServiceAccount is created automatically (`serviceAccount.create: true`) -- add annotations via `serviceAccount.annotations` for cloud IAM integration (e.g., AWS IRSA, GCP Workload Identity).
### Configuration
| Setting | Description |
| -------------------------------------- | ------------------------------------------------- |
| `orchestrator.baseConfig` | Base Orchestrator config (version + HTTP address) |
| `orchestrator.customConfig` | Inline YAML config overrides |
| `orchestrator.customConfigMapName` | Reference an external ConfigMap for config |
| `env` | Set environment variables directly |
| `envValueFrom` | Reference ConfigMap or Secret keys as env vars |
| `envFromSecrets` / `envFromConfigMaps` | Bulk-import all keys from a Secret or ConfigMap |
| `extraSecretMounts` | Mount Secrets as files (TLS certs, credentials) |
| `extraVolumeMounts` | Mount additional volumes |
### Resources and Scaling
| Setting | Default | Description |
| ------------------------------- | ------- | ---------------------------------------------- |
| `resources` | `{}` | CPU/memory requests and limits |
| `autoscaling.enabled` | `false` | Enable Horizontal Pod Autoscaler |
| `podDisruptionBudget` | -- | Configure PDB for availability during rollouts |
| `terminationGracePeriodSeconds` | `120` | Graceful shutdown timeout |
Set explicit resource requests and limits for production deployments (e.g., `resources.requests.cpu: 250m`, `resources.requests.memory: 256Mi`) to ensure predictable scheduling and prevent resource contention.
### Health Checks
The chart configures readiness and liveness probes against the `/status` endpoint. The liveness probe has a 25-second initial delay to allow startup. These defaults work for most deployments.
### Scheduling
Use `nodeSelector`, `tolerations`, and `affinity` to control pod placement across nodes and availability zones.
## Clustering
The Orchestrator supports multi-node clustering for high availability. Enable clustering with `orchestrator.clusters.create: true`. Clustering uses DNS service discovery with a pre-shared key (PSK) for inter-node authentication. Requires ports 9450 (TCP/UDP, membership) and 9451 (TCP, data sync) open between pods.
## Cloud Integration
For Console-managed deployments, enable `cloud.enabled: true` and configure `cloud.config` with bundle and key management settings. This mode supports S3-compatible storage for configuration bundles, allowing the Console to push configuration updates to your cluster.
## In-Place Config Reload
The Orchestrator applies configuration changes in place with zero downtime when
it detects a config change — no pod restart is required. Three settings must be
satisfied for this to work in Kubernetes:
### 1. Enable reload polling
Set `MAVERICS_RELOAD_CONFIG: "true"` in your Helm values. Without this, config
changes are ignored until the pod is restarted.
```yaml theme={null}
env:
MAVERICS_RELOAD_CONFIG: "true"
# MAVERICS_POLLING_INTERVAL_SECONDS: "30" # optional; default 30s
```
### 2. Mount a writable temp directory
The Orchestrator creates a handoff socket under `$TMPDIR`. Hardened images with
`readOnlyRootFilesystem: true` have no writable `/tmp`, so the socket cannot be
created and the reload silently fails. Mount a writable `emptyDir` and point
`TMPDIR` at it:
```yaml theme={null}
env:
TMPDIR: "/run/maverics"
extraVolumeMounts:
- name: handoff-tmp
mountPath: /run/maverics
readOnly: false
```
This keeps `readOnlyRootFilesystem: true` intact — the emptyDir provides the only
writable location.
### 3. Project a stable machine identity
The Orchestrator derives the handoff socket path from the container's machine
identity (`/etc/machine-id`). Scratch-based images ship without this file, so the
Orchestrator falls back to a random UUID and computes a different socket path
across the reload — the reload applies the new config but in-flight state
(sessions, caches) is discarded.
Fix: project the pod's StatefulSet identity as `/etc/machine-id` via the Downward
API. `metadata.name` (e.g., `orchestrator-0`) is stable across restarts and unique
per replica:
```yaml theme={null}
extraSecretMounts:
- name: machine-id
mountPath: /etc/machine-id
subPath: machine-id
readOnly: true
projected:
sources:
- downwardAPI:
items:
- path: machine-id
fieldRef:
fieldPath: metadata.name
```
Use `metadata.name` rather than `metadata.uid`. A StatefulSet pod name
(`orchestrator-0`) stays the same across reschedules, while `metadata.uid` changes
each time the pod is recreated — which would break the socket path across restarts.
### Failure-mode reference
| Missing requirement | Symptom | Log signal |
| ----------------------------- | ------------------------------------------- | ------------------------------------- |
| `MAVERICS_RELOAD_CONFIG=true` | Config changes ignored; restart required | *(no log)* |
| Writable tmpdir | Reload is a silent no-op; old config serves | `failed to create handoff listener` |
| Stable `/etc/machine-id` | New config applied; in-flight state lost | `failed to connect to handoff socket` |
See the [troubleshoot guide](/guides/operations/troubleshoot#configuration-issues) for diagnostic commands.
For a complete, copy-paste example values file covering all three requirements, see
[`supervisor-config-reload.yaml`](https://github.com/strata-io/helm-charts/blob/main/charts/orchestrator/example-values/supervisor-config-reload.yaml)
in the Helm chart repository.
## Minimal Production Example
A starter `values.yaml` for a production-ready deployment:
```yaml theme={null}
replicaCount: 2
image:
tag: "latest"
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
cpu: "1"
memory: 512Mi
service:
type: ClusterIP
port: 8080
env:
- name: MAVERICS_HTTP_ADDRESS
value: ":8080"
extraSecretMounts:
- name: tls-certs
secretName: orchestrator-tls
mountPath: /etc/maverics/certs
readOnly: true
```
## Example Configurations
The Helm chart repository includes ready-to-use example configurations in the [`examples/` directory](https://github.com/strata-io/helm-charts/tree/main/charts/orchestrator/examples):
* Standalone Orchestrator (minimal)
* Clustered Orchestrator
* OpenShift deployment
* Cloud integration with local config
* Cloud integration with S3 storage
* External ConfigMap reference
## All Available Options
Run the following command to see the complete list of configurable chart options:
```bash theme={null}
helm show values strata/orchestrator
```
## Related Pages
System requirements, download options, CLI flags, and environment variables
Configure the Orchestrator after installation
End-to-end quick-start guide
# Linux
Source: https://docs.strata.io/reference/orchestrator/installation/linux
The Orchestrator is distributed as platform-specific packages downloadable from the Maverics Console. To download the installer for your platform, open any Deployment in the Console and use the **Download Orchestrator Software** modal. See [Download the Orchestrator](/reference/orchestrator/installation#download-the-orchestrator) for details.
## Red Hat / RHEL
### Verify the RPM
Download Strata's public GPG key:
```bash theme={null}
curl --silent https://ops.strata.io/strata-pub-key.gpg --output strata-pub-key.gpg
```
Import the key into RPM:
```bash theme={null}
sudo rpm --import strata-pub-key.gpg
```
Verify the key installation by running:
```bash theme={null}
rpm --query --install gpg-pubkey-139d138e-* --queryformat '%{name}-%{version}-%{release} --> %{summary}\n'
```
Verify the RPM:
```bash theme={null}
rpm --checksig -v maverics-orchestrator.rpm
```
### Install the RPM
Install the RPM package on Red Hat Enterprise Linux and compatible distributions (Rocky Linux, AlmaLinux):
```bash theme={null}
sudo rpm -i maverics-rhlinux.rpm
```
This installs the Orchestrator binary to `/usr/bin/maverics` and creates a systemd service unit. Start the service and enable it to run on boot:
```bash theme={null}
sudo systemctl enable --now maverics
```
The default configuration file path is `/etc/maverics/maverics.yaml`. Place your configuration file at this path before starting the service, or update the service unit to point to a different location.
## Ubuntu / Debian
### Verify the DEB package
Download Strata's public GPG key:
```bash theme={null}
curl --silent https://ops.strata.io/strata-pub-key.gpg --output strata-pub-key.gpg
```
Import the key:
```bash theme={null}
gpg --import strata-pub-key.gpg
```
Verify the `.deb.sig` file:
```bash theme={null}
gpg --verify --trusted-key 32FD3F55D20A2ECA8915C1A98AD771C4BECEDF44 /path/to/maverics.deb.sig /path/to/maverics.deb
```
### Install the DEB package
Install the DEB package on Ubuntu, Debian, and compatible distributions:
```bash theme={null}
sudo dpkg -i maverics-package.deb
```
This installs the Orchestrator binary and creates a systemd service unit. Start the service and enable it to run on boot:
```bash theme={null}
sudo systemctl enable --now maverics
```
The default configuration file path is `/etc/maverics/maverics.yaml`. Check the service status with:
```bash theme={null}
sudo systemctl status maverics
```
## Related Pages
System requirements, download options, CLI flags, and environment variables
Configure the Orchestrator after installation
End-to-end quick-start guide
# macOS
Source: https://docs.strata.io/reference/orchestrator/installation/macos
The Orchestrator is distributed as platform-specific packages downloadable from the Maverics Console. To download the installer for your platform, open any Deployment in the Console and use the **Download Orchestrator Software** modal. See [Download the Orchestrator](/reference/orchestrator/installation#download-the-orchestrator) for details.
Extract the standalone binary archive:
```bash theme={null}
unzip maverics-orchestrator.zip
```
Run the Orchestrator directly, specifying your configuration file:
```bash theme={null}
./maverics -config /path/to/config.yaml
```
macOS does not have native systemd service integration. The binary runs in the foreground by default. For persistent background operation, you can manage the process with `launchd` by creating a launch daemon plist, or run it within a terminal multiplexer like `tmux` or `screen`.
## In-Place Config Reload
To enable zero-downtime config reload, set `MAVERICS_RELOAD_CONFIG=true`. On
macOS, also set `TMPDIR` to a short path such as `/tmp` — the default macOS temp
directory is a long path under `/var/folders/…/T/` that can prevent the
Orchestrator from enabling in-place reloads. You can also unset `TMPDIR`
entirely, which causes the Orchestrator to fall back to `/tmp`.
```bash theme={null}
MAVERICS_RELOAD_CONFIG=true TMPDIR=/tmp ./maverics -config /path/to/config.yaml
```
For persistent operation via launchd, set both variables in the
`EnvironmentVariables` key of your launch daemon plist.
## Related Pages
System requirements, download options, CLI flags, and environment variables
Configure the Orchestrator after installation
End-to-end quick-start guide
# Programmatic Install
Source: https://docs.strata.io/reference/orchestrator/installation/programmatic
Orchestrator assets can be downloaded programmatically from Strata's JFrog Artifactory instance for use in
CI/CD pipelines and automated provisioning workflows. This is useful when you need to script Orchestrator
installation as part of infrastructure automation rather than downloading manually from the Console.
Contact [support@strata.io](mailto:support@strata.io) to obtain a bearer token for Artifactory access.
## Available Packages
| Platform | Format | Filename | Use Case |
| --------------- | ----------- | ------------------------ | ----------------------------- |
| Docker | `container` | `maverics_container.zip` | Container-based deployments |
| Red Hat / RHEL | `rpm` | `maverics_rpm.zip` | RPM-based Linux distributions |
| Ubuntu / Debian | `deb` | `maverics_deb.zip` | DEB-based Linux distributions |
| Windows | `msi` | `maverics_msi.zip` | Windows Server deployments |
### Container
```bash theme={null}
curl -H "Authorization: Bearer {BEARER_TOKEN}" \
-L -O \
"https://strataidentity.jfrog.io/artifactory/mav-maverics/orchestrator-install/maverics/container/releases/latest/maverics_container.zip"
```
### RPM (Red Hat / RHEL)
```bash theme={null}
curl -H "Authorization: Bearer {BEARER_TOKEN}" \
-L -O \
"https://strataidentity.jfrog.io/artifactory/mav-maverics/orchestrator-install/maverics/rpm/releases/latest/maverics_rpm.zip"
```
### DEB (Ubuntu / Debian)
```bash theme={null}
curl -H "Authorization: Bearer {BEARER_TOKEN}" \
-L -O \
"https://strataidentity.jfrog.io/artifactory/mav-maverics/orchestrator-install/maverics/deb/releases/latest/maverics_deb.zip"
```
### MSI (Windows)
```bash theme={null}
curl -H "Authorization: Bearer {BEARER_TOKEN}" \
-L -O \
"https://strataidentity.jfrog.io/artifactory/mav-maverics/orchestrator-install/maverics/msi/releases/latest/maverics_msi.zip"
```
## CI/CD Example
Below is a GitHub Actions example that downloads and installs the Orchestrator on an Ubuntu runner.
```yaml theme={null}
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Download Orchestrator
run: |
curl -H "Authorization: Bearer ${{ secrets.ARTIFACTORY_TOKEN }}" \
-L -O \
"https://strataidentity.jfrog.io/artifactory/mav-maverics/orchestrator-install/maverics/deb/releases/latest/maverics_deb.zip"
- name: Install Orchestrator
run: |
unzip maverics_deb.zip
sudo dpkg -i maverics*.deb
- name: Verify Installation
run: maverics -version
```
Store your Artifactory bearer token as a secret in your CI/CD platform. Never hard-code tokens in
pipeline definitions or scripts.
## Related Pages
System requirements and platform installers
Platform-specific installation steps after downloading
Load and run the Orchestrator as a container
Deploy to Kubernetes using the official Strata Helm chart
# Windows
Source: https://docs.strata.io/reference/orchestrator/installation/windows
The Orchestrator is distributed as platform-specific packages downloadable from the Maverics Console. To download the installer for your platform, open any Deployment in the Console and use the **Download Orchestrator Software** modal. See [Download the Orchestrator](/reference/orchestrator/installation#download-the-orchestrator) for details.
Run the MSI installer (`maverics-orchestrator.msi`), which provides a guided setup wizard. The installer prompts you to configure:
* **Configuration source** -- Path to your YAML configuration file or a remote config source URL
* **TLS certificates** -- Paths to your certificate and private key files
* **Environment variables** -- Any runtime environment variables the Orchestrator needs
The installer registers the Orchestrator as a Windows service that starts automatically on boot.
Manage the service from the command line:
```powershell theme={null}
# Check service status
sc query maverics
# Start the service
sc start maverics
# Stop the service
sc stop maverics
```
Configuration is set during MSI installation and can be updated through the Windows Services management console (`services.msc`) or by modifying the service registry entries.
## In-Place Config Reload
To enable zero-downtime config reload on Windows, set `MAVERICS_RELOAD_CONFIG=true`
in the Orchestrator's service environment. When the Orchestrator detects a config
change, it applies it in place without restarting the service — the Windows service
entry stays running and `RESTARTS` remains 0.
**Windows behaves differently from Linux/macOS in two ways:**
* **Brief connection gap.** On Linux and macOS, the listening port is inherited
directly by the new process, so new connections are never refused during a
reload. On Windows, the new process must re-bind the port, which creates a short
window where new connections may be refused. In-flight requests on the old process
drain cleanly and are not dropped.
* **Weaker rollback on bad config.** On Linux and macOS, if the new process fails to
start, the old one keeps serving uninterrupted — it never released the port. On
Windows, the old process releases its listener during the reload handoff. The
Orchestrator pre-validates the config file before triggering a reload (catching
syntax and schema errors), but a runtime startup failure after the handoff carries
a small risk of a brief outage rather than a seamless fallback.
Set `MAVERICS_RELOAD_CONFIG=true` via the Windows service environment. In the MSI
installer, set it during the installation wizard under **Environment variables**. To
update it after installation, modify the service environment through
`services.msc` or the registry, then restart the service to pick up the new
environment.
## Related Pages
System requirements, download options, CLI flags, and environment variables
Configure the Orchestrator after installation
End-to-end quick-start guide
# Overview
Source: https://docs.strata.io/reference/orchestrator/overview
Orchestration is the core of the Maverics platform -- the layer that connects your applications to your [identity fabric](/reference/orchestrator/identity-fabric), translates between protocols, enforces access policies, and routes authentication traffic. Rather than modifying each application to work with each identity provider, orchestration handles all of that centrally.
The **Maverics Orchestrator** is the runtime that provides this. It's a lightweight, self-hosted binary deployed in your infrastructure that processes every identity transaction -- evaluating policies, transforming tokens, and routing requests across protocols without requiring changes to your existing applications.
## Key Capabilities
* **Protocol translation** -- Convert between OIDC, SAML, LDAP, and HTTP-based authentication without modifying applications
* **Identity fabric integration** -- Connect to your organization's [identity fabric](/reference/orchestrator/identity-fabric) -- Entra ID, Okta, Active Directory, LDAP directories, and others -- through a uniform connector interface
* **Identity routing** -- Direct authentication requests to the appropriate identity provider based on configurable policies, with automatic failover between providers
* **Session management** -- Maintain user sessions across multiple applications with configurable [storage backends](/reference/orchestrator/sessions)
* **Credential injection** -- Supply legacy applications with the credentials they expect while using modern identity providers
* **AI identity governance** -- Secure AI agent and MCP tool access through identity-aware policies and the [AI Identity Gateway](/reference/modes/ai-identity-gateway) mode
## Modes
The Orchestrator's mode determines which identity protocol it speaks to your applications. A single Orchestrator can run multiple modes simultaneously:
* [**AI Identity Gateway**](/reference/modes/ai-identity-gateway) -- Secures AI agent access with identity-aware MCP bridge and proxy capabilities
* [**OIDC Provider**](/reference/modes/oidc-provider) -- Acts as an OpenID Connect provider for modern web applications
* [**SAML Provider**](/reference/modes/saml-provider) -- Acts as a SAML identity provider for enterprise applications
* [**HTTP Proxy**](/reference/modes/http-proxy) -- Intercepts and modifies HTTP traffic for legacy application integration
* [**LDAP Provider**](/reference/modes/ldap-provider) -- Serves LDAP queries backed by modern identity sources
## Deployment Options
The Orchestrator supports multiple deployment models to fit your infrastructure:
* **Standalone binary** -- Run directly on Linux, macOS, or Windows as a single process
* **Docker container** -- Deploy as a containerized service with standard Docker tooling
* **Kubernetes** -- Run as a Kubernetes deployment with Helm charts
* **High availability** -- Deploy multiple instances behind a load balancer with sticky sessions for shared user state across nodes
See the [Installation reference](/reference/orchestrator/installation) for setup instructions across all deployment models.
## Related Pages
System requirements, installation methods, and initial verification
Delivery paths (Console bundles and YAML), secret providers, and runtime settings
Connectors for the identity providers and directories your organization uses
Platform architecture and how the Orchestrator fits in
# Service Extensions
Source: https://docs.strata.io/reference/orchestrator/service-extensions
Service extensions are custom Go functions that you inject at specific hook points in the Orchestrator's request processing pipeline. They use Go syntax but execute within an embedded Go runtime inside the Orchestrator process -- you do not compile or build plugins. Service extension code cannot run independently outside the Orchestrator. Service extensions let you customize authentication, authorization, claims building, routing, session management, and API handling without modifying the Orchestrator itself.
The Orchestrator provides 30 hook points across the request lifecycle, organized by concern in the pages below.
## How Service Extensions Work
When the Orchestrator starts, it loads your Go source code and executes it through an embedded Go runtime. At each configured hook point, the Orchestrator calls your named function, passing an `api` parameter that provides access to the full Orchestrator interface -- sessions, caches, secrets, identity providers, logging, and more.
Service extension code can be delivered in two ways:
* **File reference** -- point to an external `.go` source file on disk. Preferred for production use because it supports version control, IDE tooling, and independent testing.
* **Inline code** -- embed Go source directly in the YAML configuration. Convenient for short, self-contained extensions.
The basic function signature follows this pattern:
```go theme={null}
package main
import (
"net/http"
"github.com/strata-io/service-extension/orchestrator"
)
func MyExtension(api orchestrator.Orchestrator, rw http.ResponseWriter, req *http.Request) {
// Custom logic here
}
```
The exact function signature varies by hook point. Some hooks omit the `rw` or `req` parameters, some return an `error`. Refer to the individual hook pages below or the [SDK documentation](https://pkg.go.dev/github.com/strata-io/service-extension) for each hook's expected signature.
## Configuration
Each service extension hook accepts a `ServiceExtension` object with the following structure:
```yaml theme={null}
someHookSE:
funcName: MyFunction
file: /path/to/extension.go
metadata:
key: value
```
You can provide code inline instead of referencing a file:
```yaml theme={null}
someHookSE:
funcName: MyFunction
code: |
package main
import (
"net/http"
"github.com/strata-io/service-extension/orchestrator"
)
func MyFunction(api orchestrator.Orchestrator, rw http.ResponseWriter, req *http.Request) {
// custom logic
}
```
### Field Reference
| Key | Type | Default | Required | Description |
| -------------------------- | ---------------- | ------- | ----------------------- | --------------------------------------------------------------------- |
| `funcName` | string | -- | Yes | Name of the Go function to call |
| `code` | string | -- | One of `code` or `file` | Inline Go source code |
| `file` | string | -- | One of `code` or `file` | Path to a `.go` source file |
| `metadata` | map | -- | No | Key-value metadata passed to the service extension at runtime |
| `goPath` | string | -- | No | Go path for locating additional packages |
| `allowedProtectedPackages` | array of strings | `[]` | No | Protected packages to allow (e.g., `"os"`) -- see Runtime Environment |
Either `code` or `file` must be provided, but not both.
## The Service Extension SDK
The Service Extension SDK is a Go module that provides typed interfaces for interacting with Orchestrator services from within your extension code.
* **Module:** [`github.com/strata-io/service-extension`](https://github.com/strata-io/service-extension)
* **Documentation:** [pkg.go.dev/github.com/strata-io/service-extension](https://pkg.go.dev/github.com/strata-io/service-extension)
### SDK Interfaces
The `api` parameter passed to your extension function implements the `orchestrator.Orchestrator` interface, which provides access to all subsystem interfaces:
| Interface | Access Via | Purpose |
| ----------------------------- | ------------------------- | -------------------------------------------------------------------------------------------------------------- |
| **Orchestrator** | `api` parameter | Main entry point -- provides access to all other interfaces |
| **Session** | `api.Session()` | Read/write session attributes (GetString, SetString, GetBool, SetBool, GetInt, SetInt, GetJSON, SetJSON, Save) |
| **Logger** | `api.Logger()` | Structured logging with Debug, Info, Error and key-value pairs |
| **Cache** | `api.Cache()` | Read/write cache entries with TTL (GetBytes, SetBytes) |
| **SecretProvider** | `api.SecretProvider()` | Retrieve secrets from configured providers (Get, GetString) |
| **IdentityProvider** | `api.IdentityProvider()` | Trigger authentication flows (Login, IsAvailable) |
| **AttributeProvider** | `api.AttributeProvider()` | Query user attributes from connectors (Query) |
| **Router** | `api.Router()` | Register custom HTTP handlers (HandleFunc) |
| **HTTP** | `api.HTTP()` | Access HTTP clients for outbound requests (GetClient, SetClient, DefaultClient) |
| **App** | `api.App()` | Access current application metadata (Name) |
| **Bundle/Assets** | `api.Bundle()` | Access bundled static files (FS, ReadFile) |
| **TAI/WebLogic** (deprecated) | `api.TAI()` | WebSphere Trust Association Interceptor operations (NewSignedJWT) |
For complete interface definitions, method signatures, and type details, see the [SDK reference on pkg.go.dev](https://pkg.go.dev/github.com/strata-io/service-extension).
## Hook Points
The Orchestrator provides 30 service extension hook points organized by lifecycle area. Each hook is a field on the relevant configuration object. Select a hook name to see its full signature, parameters, and usage details.
### API Lifecycle
Custom API endpoints are managed through the **Service Extensions** area in the Console. In the Console sidebar, select **Service Extensions** and then **API** to create, edit, and manage custom API endpoints. APIs are attached to deployments from the deployment's **Settings** page alongside applications.
| Hook | Config Location | Purpose |
| ------------------------------------------------------------------- | ---------------- | ----------------------------------- |
| [`serveSE`](/reference/orchestrator/service-extensions/custom-apis) | `apis[].serveSE` | Handle custom API endpoint requests |
See [Custom APIs](/reference/orchestrator/service-extensions/custom-apis) for the `apis[]` configuration and Console UI setup steps.
### Proxy App Lifecycle
These hooks are available on apps with `type: proxy`:
| Hook | Config Location | Purpose |
| ---------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | -------------------------------------------------- |
| [`isAuthenticatedSE`](/reference/orchestrator/service-extensions/proxy) | `apps[].policies[].authentication.isAuthenticatedSE` | Custom authentication check |
| [`authenticateSE`](/reference/orchestrator/service-extensions/proxy) | `apps[].policies[].authentication.authenticateSE` | Custom authentication flow |
| [`isAuthorizedSE`](/reference/orchestrator/service-extensions/proxy) | `apps[].policies[].authorization.isAuthorizedSE` | Custom authorization logic |
| [`handleUnauthorizedSE`](/reference/orchestrator/service-extensions/proxy) | `apps[].handleUnauthorizedSE` | Customize the unauthorized response |
| [`loadAttrsSE`](/reference/orchestrator/service-extensions/proxy) | `apps[].loadAttrsSE` | Load custom attributes before request processing |
| [`createHeaderSE`](/reference/orchestrator/service-extensions/proxy) | `apps[].headers[].createHeaderSE` | Generate custom header values |
| [`modifyRequestSE`](/reference/orchestrator/service-extensions/proxy) | `apps[].modifyRequestSE` | Modify the request before proxying to the upstream |
| [`modifyResponseSE`](/reference/orchestrator/service-extensions/proxy) | `apps[].modifyResponseSE` | Modify the response before returning to the client |
| [`isLoggedInSE`](/reference/orchestrator/service-extensions/proxy) / [`loginSE`](/reference/orchestrator/service-extensions/proxy) | `apps[].upstreamLogin.isLoggedInSE` / `apps[].upstreamLogin.loginSE` | Upstream application login automation |
### OIDC App Lifecycle
These hooks are available on apps with `type: oidc`:
| Hook | Config Location | Purpose |
| ----------------------------------------------------------------------------- | -------------------------------------------------- | ---------------------------------------------------------------------- |
| [`isAuthenticatedSE`](/reference/orchestrator/service-extensions/oidc) | `apps[].authentication.isAuthenticatedSE` | Custom authentication check |
| [`authenticateSE`](/reference/orchestrator/service-extensions/oidc) | `apps[].authentication.authenticateSE` | Custom authentication flow |
| [`authenticateSE`](/reference/orchestrator/service-extensions/oidc) | `apps[].authentication.backchannel.authenticateSE` | Backchannel authentication (e.g., Resource Owner Password Credentials) |
| [`isAuthorizedSE`](/reference/orchestrator/service-extensions/oidc) | `apps[].authorization.isAuthorizedSE` | Custom authorization logic |
| [`loadAttrsSE`](/reference/orchestrator/service-extensions/oidc) | `apps[].loadAttrsSE` | Load custom attributes before token issuance |
| [`buildIDTokenClaimsSE`](/reference/orchestrator/service-extensions/oidc) | `apps[].buildIDTokenClaimsSE` | Customize ID token claims |
| [`buildAccessTokenClaimsSE`](/reference/orchestrator/service-extensions/oidc) | `apps[].buildAccessTokenClaimsSE` | Customize access token claims |
### OIDC Provider Level
| Hook | Config Location | Purpose |
| -------------------------------------------------------------------------- | ------------------------------------ | ---------------------------------------- |
| [`buildUserInfoClaimsSE`](/reference/orchestrator/service-extensions/oidc) | `oidcProvider.buildUserInfoClaimsSE` | Customize the UserInfo endpoint response |
### SAML App Lifecycle
These hooks are available on apps with `type: saml`:
| Hook | Config Location | Purpose |
| ---------------------------------------------------------------------- | -------------------------------------------- | -------------------------------------------------------- |
| [`isAuthenticatedSE`](/reference/orchestrator/service-extensions/saml) | `apps[].authentication.isAuthenticatedSE` | Custom authentication check (cannot be used with `idps`) |
| [`authenticateSE`](/reference/orchestrator/service-extensions/saml) | `apps[].authentication.authenticateSE` | Custom authentication flow (cannot be used with `idps`) |
| [`isAuthorizedSE`](/reference/orchestrator/service-extensions/saml) | `apps[].authorization.isAuthorizedSE` | Custom authorization logic |
| [`loadAttrsSE`](/reference/orchestrator/service-extensions/saml) | `apps[].loadAttrsSE` | Load custom attributes before assertion building |
| [`buildClaimsSE`](/reference/orchestrator/service-extensions/saml) | `apps[].buildClaimsSE` | Customize SAML assertion claims |
| [`buildRelayStateSE`](/reference/orchestrator/service-extensions/saml) | `apps[].idpInitiatedLogin.buildRelayStateSE` | Build custom RelayState for IdP-initiated login |
### LDAP Provider Lifecycle
These hooks are available on the `ldapProvider` configuration:
| Hook | Config Location | Purpose |
| ------------------------------------------------------------------- | ----------------------------------------------------------- | --------------------------------- |
| [`searchSE`](/reference/orchestrator/service-extensions/ldap) | `ldapProvider.search.searchSE` | Handle LDAP search operations |
| [`authenticateSE`](/reference/orchestrator/service-extensions/ldap) | `ldapProvider.authentication.methods.simple.authenticateSE` | Authenticate via simple LDAP bind |
### Session Lifecycle
| Hook | Config Location | Purpose |
| ------------------------------------------------------------------------------------ | ------------------------------------ | ----------------------------------------- |
| [`evalIdleTimeoutSE`](/reference/orchestrator/service-extensions/session-and-logout) | `session.lifetime.evalIdleTimeoutSE` | Dynamically evaluate session idle timeout |
| [`evalMaxLifetimeSE`](/reference/orchestrator/service-extensions/session-and-logout) | `session.lifetime.evalMaxLifetimeSE` | Dynamically evaluate session max lifetime |
### Single Logout
| Hook | Config Location | Purpose |
| ------------------------------------------------------------------------------- | -------------------------------------- | --------------------------------------------- |
| [`postLogoutSE`](/reference/orchestrator/service-extensions/session-and-logout) | `singleLogout.postLogout.postLogoutSE` | Custom behavior after single logout completes |
## Writing a Service Extension
The following example shows a `LoadCustomAttrs` function that queries an attribute provider for user attributes and stores the results in the session:
```go theme={null}
package main
import (
"net/http"
"github.com/strata-io/service-extension/orchestrator"
)
func LoadCustomAttrs(api orchestrator.Orchestrator, rw http.ResponseWriter, req *http.Request) error {
log := api.Logger()
attrProvider, err := api.AttributeProvider("ldap")
if err != nil {
log.Error("se", "failed to get attribute provider", "error", err.Error())
return err
}
attrs, err := attrProvider.Query("", []string{"mail", "displayName", "memberOf"})
if err != nil {
log.Error("se", "failed to query attributes", "error", err.Error())
return err
}
session, err := api.Session()
if err != nil {
log.Error("se", "failed to get session", "error", err.Error())
return err
}
session.SetString("email", attrs["mail"])
session.SetString("displayName", attrs["displayName"])
session.SetJSON("groups", attrs["memberOf"])
if err := session.Save(); err != nil {
log.Error("se", "failed to save session", "error", err.Error())
return err
}
return nil
}
```
Reference the extension from your YAML configuration:
```yaml theme={null}
apps:
- name: my-app
type: proxy
upstream: https://backend.example.com
loadAttrsSE:
funcName: LoadCustomAttrs
file: /etc/maverics/extensions/load-attrs.go
```
Use `file` for production deployments -- it keeps extension code in version control and enables IDE support. Use inline `code` for short, self-contained extensions where a separate file adds unnecessary overhead.
## Runtime Environment
Service extension code runs through the **Orchestrator's embedded Go runtime**. Code is interpreted at runtime -- there is no compile step.
### Available Packages
By default, service extensions have access to:
* **Go standard library** (except `os`, which is restricted by default)
* **Service Extension SDK** -- packages under `service-extension/` providing access to Orchestrator services:
* `orchestrator` -- access to the Orchestrator instance (session, cache, secrets, connectors, router)
* `session` -- read and write session attributes
* `cache` -- read and write cache entries
* `secret` -- retrieve secrets from configured secret providers
* `log` -- structured logging
* `router` -- request routing
* `idfabric` -- identity fabric integration
* `tai` -- WebSphere Trust Association Interceptor (deprecated)
* `weblogic` -- WebLogic integration
* **Third-party libraries** -- LDAP, JWT, UUID, AWS SDK, HTML parser, secp256k1
### Protected Packages
The `os` package is restricted by default to prevent file system and process access. To opt in, add it to `allowedProtectedPackages`:
```yaml theme={null}
someHookSE:
funcName: ReadConfig
file: /path/to/extension.go
allowedProtectedPackages:
- os
```
## Best Practices
### Error Handling
Always check and handle errors returned by SDK methods. Log errors with sufficient context to diagnose issues in production. A panicking extension can disrupt the Orchestrator's request processing for the affected hook point.
```go theme={null}
attrs, err := api.AttributeProvider("ldap").Query("", []string{"mail"})
if err != nil {
api.Logger().Error("se", "attribute query failed", "provider", "ldap", "error", err.Error())
return
}
```
### Logging
Use the SDK logger (`api.Logger()`) instead of `fmt.Println` or the standard `log` package. The SDK logger integrates with the Orchestrator's structured logging pipeline and supports key-value pairs for searchable log entries.
```go theme={null}
log := api.Logger()
log.Info("se", "processing request", "app", api.App().Name(), "user", email)
```
### Secrets Management
Use `api.SecretProvider()` to retrieve secrets at runtime from configured providers (Vault, AWS Secrets Manager, Azure Key Vault, etc.). Never hardcode credentials, API keys, or certificates in extension code.
```go theme={null}
apiKey, err := api.SecretProvider().GetString("my-api-key")
if err != nil {
api.Logger().Error("se", "failed to retrieve API key", "error", err.Error())
return
}
```
### Performance
Keep extensions lightweight, especially in hot-path hooks like `modifyRequestSE` and `modifyResponseSE` that execute on every proxied request. Use `api.Cache()` for expensive lookups to avoid redundant calls to external systems.
### HTTP Client Reuse
When making outbound HTTP requests from a service extension, always reuse HTTP clients through the `api.HTTP()` interface rather than creating a new `http.Client` per request. Creating clients per request prevents connection pooling, repeats TLS handshakes, and can lead to socket exhaustion under load.
For most use cases, `api.HTTP().DefaultClient()` provides a ready-to-use client with sensible defaults:
```go theme={null}
func CallAPI(api orchestrator.Orchestrator, rw http.ResponseWriter, req *http.Request) {
log := api.Logger()
client := api.HTTP().DefaultClient()
resp, err := client.Get("https://api.example.com/resource")
if err != nil {
log.Error("se", "request failed", "error", err.Error())
return
}
defer resp.Body.Close()
// Process the response.
}
```
When you need separate clients with different configurations (e.g., distinct timeouts or transport settings for different upstream services), use `api.HTTP().SetClient()` and `api.HTTP().GetClient()` to register and retrieve named clients:
```go theme={null}
func CallAPIs(api orchestrator.Orchestrator, rw http.ResponseWriter, req *http.Request) {
log := api.Logger()
// Register a named client once; subsequent calls to GetClient return the same instance.
_, err := api.HTTP().GetClient("payments-api")
if err != nil {
paymentsClient := &http.Client{Timeout: 5 * time.Second}
api.HTTP().SetClient("payments-api", paymentsClient)
}
client, _ := api.HTTP().GetClient("payments-api")
resp, err := client.Get("https://payments.example.com/charge")
if err != nil {
log.Error("se", "payments request failed", "error", err.Error())
return
}
defer resp.Body.Close()
// Process the response.
}
```
Named clients registered with `SetClient` persist for the lifetime of the Orchestrator process. Use descriptive names (e.g., `"payments-api"`, `"identity-service"`) to avoid collisions between extensions.
### Statelessness
Do not rely on global variables or package-level state between requests. The Orchestrator may run multiple instances, and the runtime does not guarantee state persistence across configuration reloads. Use `api.Session()` for request-scoped state and `api.Cache()` for cross-request state.
## Testing and Deployment
Follow a staged workflow to minimize risk when deploying service extensions:
1. **Develop locally** -- write and test your extension code against the SDK interfaces. Use Go tooling (formatting, linting, type checking) during development even though extensions run interpreted.
2. **Deploy to staging** -- deploy the extension to a non-production Orchestrator instance connected to test identity providers and backend services.
**Static analysis limitations:** Because service extensions execute inside the Orchestrator's embedded runtime with injected SDK interfaces, standard static code analysis tools (SAST, linters with security rules) may not produce meaningful results. The most effective way to validate security behavior is to deploy your extension to a test environment and exercise the actual authentication, authorization, and data-handling scenarios your extension participates in.
3. **Verify behavior** -- use structured logging (`api.Logger()`) to trace extension execution. Check Orchestrator logs for errors, unexpected behavior, or performance issues.
4. **Promote to production** -- after verifying correct behavior in staging, deploy the extension to production. Monitor Orchestrator logs after deployment for errors from extension code.
Service extensions execute custom user-authored code within the Orchestrator process. You are responsible for the correctness, security, and performance of your extension code. Strata provides the Service Extension SDK and runtime environment but does not audit, review, or warranty custom extension logic.
## Related Pages
Application configuration where most SE hooks are defined
Go module source and API documentation
# Custom APIs
Source: https://docs.strata.io/reference/orchestrator/service-extensions/custom-apis
Custom API endpoints let you add your own HTTP endpoints to the Orchestrator. Use custom APIs to build health checks, webhook receivers, token exchange endpoints, or any custom endpoint that needs access to sessions, caches, and other Orchestrator services.
Custom APIs are managed through the **Service Extensions** area in the Console -- they are not an application type.
## Console UI Workflow
Navigate to **Service Extensions** in the Console sidebar and select **API**.
Click **Create** and provide a **name** for the API endpoint and a **function name** that matches the Go function in your extension code (e.g., `ServeAPI`).
Use the built-in code editor to write your `serveSE` handler, or upload a `.go` source file. The editor provides syntax highlighting and access to the service extension SDK.
Go to the deployment's **Settings** page. In the **APIs** section, attach the API you created. This includes the API in the deployment's configuration bundle.
Publish the deployment to push the updated configuration bundle to your Orchestrator instances.
Custom API endpoints are defined under the `apis` top-level key in the YAML configuration. See the [Configuration](#configuration) section below.
## Request Lifecycle
Unlike other hooks that run during request processing, `serveSE` runs once when the Orchestrator starts up. Your extension registers HTTP route handlers that then execute whenever a matching request arrives.
```mermaid theme={null}
%%{init: {'theme': 'neutral', 'themeVariables': {'edgeWidth': 4}}}%%
flowchart TD
START[Orchestrator starts] --> PARSE[Load API configuration]
PARSE --> SE[serveSE — register custom endpoints]
SE -- error --> FAIL[Log startup error]
SE -- success --> READY[Endpoints ready to receive traffic]
READY --> REQ[Request arrives at custom endpoint]
REQ --> HANDLER[Your handler processes the request]
HANDLER --> RESP[Return response]
classDef hook stroke:#6A3EC8,stroke-width:6px
class SE hook
```
## Hooks
### `serveSE`
Register custom HTTP endpoints on the Orchestrator. This hook runs at startup and gives you access to the router to define your own API routes. Use this to implement custom REST endpoints, webhook receivers, or internal service APIs.
**Signature:**
```go theme={null}
func ServeAPI(api orchestrator.Orchestrator) error
```
**App types:** Top-level `apis[]`
**Config location:** `apis[].serveSE`
**Parameters:**
| Parameter | Type | Description |
| --------- | --------------------------- | ------------------------------------------------------------------------------------- |
| `api` | `orchestrator.Orchestrator` | Access to sessions, caches, secrets, logging, router, and other Orchestrator services |
**Returns:** `error` -- return `nil` on success, or an error if the API handler setup fails.
**Examples:**
When you need to receive webhooks at the Orchestrator and relay them to an
external system — such as a SIEM, logging platform, or notification
service — this extension registers a `/webhooks/forward` endpoint that
accepts incoming requests and forwards them using a reusable HTTP client.
```go webhook-forwarder.go theme={null}
package main
import (
"fmt"
"io"
"net/http"
"time"
"github.com/strata-io/service-extension/orchestrator"
)
func ServeAPI(api orchestrator.Orchestrator) error {
logger := api.Logger()
// Create a reusable HTTP client at startup. Reusing clients pools
// TCP connections and prevents resource exhaustion under load.
apiHTTP := api.HTTP()
err := apiHTTP.SetClient("forwarder", &http.Client{
Timeout: 10 * time.Second,
})
if err != nil {
return fmt.Errorf("failed to create HTTP client: %w", err)
}
// Read the destination URL from SE metadata.
metadata := api.Metadata()
targetURL := metadata["targetURL"].(string)
// Read the auth token from the secret provider.
sp := api.SecretProvider()
authToken, err := sp.GetString("webhook-auth-token")
if err != nil {
return fmt.Errorf("failed to get auth token: %w", err)
}
router := api.Router()
router.HandleFunc("/webhooks/forward", func(rw http.ResponseWriter, req *http.Request) {
client, _ := apiHTTP.GetClient("forwarder")
fwd, err := http.NewRequest(req.Method, targetURL, req.Body)
if err != nil {
logger.Error("se", "failed to create forward request", "error", err.Error())
http.Error(rw, "internal error", http.StatusInternalServerError)
return
}
fwd.Header.Set("Content-Type", req.Header.Get("Content-Type"))
fwd.Header.Set("Authorization", "Bearer "+authToken)
resp, err := client.Do(fwd)
if err != nil {
logger.Error("se", "failed to forward webhook", "error", err.Error())
http.Error(rw, "forwarding failed", http.StatusBadGateway)
return
}
defer resp.Body.Close()
rw.WriteHeader(resp.StatusCode)
io.Copy(rw, resp.Body)
})
logger.Info("se", "registered /webhooks/forward endpoint")
return nil
}
```
```yaml maverics.yaml theme={null}
apis:
- name: webhook-forwarder
serveSE:
funcName: ServeAPI
file: /etc/maverics/extensions/webhook-forwarder.go
metadata:
targetURL: https://siem.example.com/api/events
```
## Configuration
Custom API endpoints are defined under the `apis` top-level key in the deployment configuration.
```yaml maverics.yaml theme={null}
apis:
- name: my-custom-endpoint
serveSE:
funcName: ServeAPI
file: /path/to/api-handler.go
```
### Field Reference
| Key | Type | Default | Required | Description |
| ---------------- | ---------------- | ------- | -------- | -------------------------------------------------------- |
| `apis[].name` | string | -- | Yes | Unique name for the API endpoint |
| `apis[].serveSE` | ServiceExtension | -- | Yes | Service extension that handles requests to this endpoint |
The `serveSE` field accepts the standard [ServiceExtension](/reference/orchestrator/service-extensions#field-reference) object (`funcName`, `code`/`file`, `metadata`, `goPath`, `allowedProtectedPackages`).
### Validation Rules
* Each `name` must be unique across all `apis[]` entries
* The `serveSE` field is required -- an API endpoint without a handler is invalid
### Example
A custom health check endpoint and a user info endpoint:
```yaml maverics.yaml theme={null}
apis:
- name: custom-health
serveSE:
funcName: HealthCheck
file: /etc/maverics/extensions/health-check.go
metadata:
backendURL: "https://backend.example.com/health"
- name: user-info
serveSE:
funcName: GetUserInfo
file: /etc/maverics/extensions/user-info.go
```
Multiple custom APIs can be defined, each with its own service extension handler.
## Related Pages
Configuration, SDK reference, and best practices
Application configuration for proxy, OIDC, and SAML apps
# LDAP
Source: https://docs.strata.io/reference/orchestrator/service-extensions/ldap
LDAP service extensions let you customize how the Orchestrator handles directory operations when running as an LDAP provider. Use these hooks to implement custom search logic or authenticate users against external systems.
## Request Lifecycle
The LDAP provider operates over TCP using the LDAP protocol (not HTTP). Each operation type has its own processing flow and hook point.
### Search
```mermaid theme={null}
%%{init: {'theme': 'neutral', 'themeVariables': {'edgeWidth': 4}}}%%
flowchart TD
REQ[LDAP search request] --> ROOT{Root DSE query?}
ROOT -- Yes --> DSE[Return Root DSE attributes]
ROOT -- No --> BOUND{Connection authenticated?}
BOUND -- No --> ERR1[Return operations error]
BOUND -- Yes --> SE{searchSE configured?}
SE -- No --> ERR2[Return error — no search handler]
SE -- Yes --> SEARCH[searchSE]
SEARCH -- error --> ERR3[Return LDAP error]
SEARCH -- success --> RES[Return search result entries]
classDef hook stroke:#6A3EC8,stroke-width:6px
class SEARCH hook
```
### Simple Bind Authentication
```mermaid theme={null}
%%{init: {'theme': 'neutral', 'themeVariables': {'edgeWidth': 4}}}%%
flowchart TD
REQ[LDAP Bind request] --> ENABLED{Simple auth enabled?}
ENABLED -- No --> ERR1[Return auth method not supported]
ENABLED -- Yes --> UNAUTH{Password provided?}
UNAUTH -- No --> ERR2[Return error — password required]
UNAUTH -- Yes --> SE[authenticateSE]
SE -- error --> ERR3[Return error]
SE -- valid --> OK[Bind success — connection authenticated]
SE -- invalid --> DENY[Return invalid credentials]
classDef hook stroke:#6A3EC8,stroke-width:6px
class SE hook
```
## Hooks
### `searchSE`
Handle LDAP search requests by returning directory entries that match the query. Each entry maps a distinguished name (DN) to its attributes. Use this to implement custom search logic, query external directories, filter results, or build virtual directory entries from non-LDAP sources like databases or REST APIs.
**Signature:**
```go theme={null}
func Search(api orchestrator.Orchestrator, baseDN string, filter string, attrs []string) (map[string]map[string]interface{}, error)
```
**App types:** LDAP Provider
**Config location:** `ldapProvider.search.searchSE`
**Parameters:**
| Parameter | Type | Description |
| --------- | --------------------------- | ----------------------------------------------------------------------------- |
| `api` | `orchestrator.Orchestrator` | Access to sessions, caches, secrets, logging, and other Orchestrator services |
| `baseDN` | `string` | The base distinguished name for the search |
| `filter` | `string` | The LDAP search filter expression |
| `attrs` | `[]string` | The list of attribute names to return |
**Returns:**
* `map[string]map[string]interface{}` -- a map of DNs to attribute maps, where each attribute map contains the requested attribute name-value pairs
* `error` -- return `nil` on success, or an error if the search fails
***
### `authenticateSE`
Authenticate a user via LDAP simple bind. Return `true` if the credentials are valid, or `false` to deny authentication. Use this to validate credentials against an external system, implement custom password policies, or bridge LDAP authentication to a non-LDAP identity store.
**Signature:**
```go theme={null}
func Authenticate(api orchestrator.Orchestrator, dn string, password string) (bool, error)
```
**App types:** LDAP Provider
**Config location:** `ldapProvider.authentication.methods.simple.authenticateSE`
**Parameters:**
| Parameter | Type | Description |
| ---------- | --------------------------- | ----------------------------------------------------------------------------- |
| `api` | `orchestrator.Orchestrator` | Access to sessions, caches, secrets, logging, and other Orchestrator services |
| `dn` | `string` | The distinguished name of the user attempting to bind |
| `password` | `string` | The password provided by the user |
**Returns:**
* `bool` -- `true` if the credentials are valid, `false` otherwise
* `error` -- return `nil` on success, or an error if the authentication process fails
**Examples:**
When an LDAP client performs a simple bind, this extension extracts the
username from the bind DN and authenticates the user against an OIDC identity
provider using the Resource Owner Password Credentials (ROPC) grant. This
bridges LDAP authentication with a modern IdP without changes to the
client application.
```go ldap-authenticate.go theme={null}
package main
import (
"errors"
"fmt"
"strings"
"github.com/strata-io/service-extension/idfabric"
"github.com/strata-io/service-extension/orchestrator"
)
func Authenticate(
api orchestrator.Orchestrator,
dn string,
password string,
) (bool, error) {
logger := api.Logger()
logger.Debug("se", "ldap-auth", "msg", "authenticating user", "dn", dn)
// Extract the username from the bind DN.
username, err := parseUsername(dn)
if err != nil {
logger.Error("se", "ldap-auth", "msg", "failed to parse DN", "error", err.Error())
return false, err
}
// Delegate authentication to the OIDC provider via ROPC.
idp, err := api.IdentityProvider("oidc")
if err != nil {
logger.Error("se", "ldap-auth", "msg", "failed to get IdP", "error", err)
return false, err
}
var result idfabric.LoginResult
idp.Login(
nil,
nil,
idfabric.WithGrantTypeROPC(
idfabric.ROPCRequest{Username: username, Password: password},
&result,
),
)
if result.Error != nil {
logger.Error("se", "ldap-auth", "msg", "authentication failed", "error", result.Error)
return false, result.Error
}
return true, nil
}
// parseUsername extracts the value of the first RDN from a DN.
// e.g., "cn=jdoe,ou=users,dc=example,dc=com" -> "jdoe"
func parseUsername(dn string) (string, error) {
parts := strings.Split(dn, ",")
if len(parts) == 0 {
return "", errors.New("invalid DN format")
}
rdn := parts[0]
eqIdx := strings.Index(rdn, "=")
if eqIdx < 0 || eqIdx == len(rdn)-1 {
return "", fmt.Errorf("malformed RDN: %s", rdn)
}
return rdn[eqIdx+1:], nil
}
```
```yaml maverics.yaml theme={null}
connectors:
- name: oidc
type: oidc
oidcWellKnownURL: https://idp.example.com/.well-known/openid-configuration
oauthClientID: my-client
oauthClientSecret:
scopes: openid profile email
ldapProvider:
enabled: true
uri: ldaps://0.0.0.0:636
authentication:
allowAnonymous: false
methods:
simple:
enabled: true
authenticateSE:
file: /etc/maverics/service-extensions/ldap-authenticate.go
funcName: Authenticate
```
Applications that authenticate via LDAP simple bind have no built-in way
to support multi-factor authentication. This extension works around that
limitation by treating the password field as a concatenation of the real
password and a TOTP code (e.g., `myP@ssword12345678`). The password portion
is verified against an IdP via ROPC, and the TOTP code is verified against
an external MFA API.
```go ldap-authenticate-totp.go theme={null}
package main
import (
"encoding/base64"
"fmt"
"io"
"net/http"
"net/url"
"strings"
"github.com/strata-io/service-extension/idfabric"
"github.com/strata-io/service-extension/orchestrator"
)
const (
// Number of characters at the end of the password that
// contain the TOTP code.
totpCodeLength = 8
)
func Authenticate(
api orchestrator.Orchestrator,
dn string,
password string,
) (bool, error) {
logger := api.Logger()
logger.Debug("se", "ldap-auth", "msg", "authenticating user", "dn", dn)
// Split the password into the real password and appended TOTP code.
if len(password) < totpCodeLength {
logger.Debug("se", "ldap-auth", "msg", "password too short to contain TOTP code")
return false, nil
}
actualPassword := password[:len(password)-totpCodeLength]
totpCode := password[len(password)-totpCodeLength:]
// Step 1: Verify the password via ROPC against the IdP.
idp, err := api.IdentityProvider("oidc")
if err != nil {
logger.Error("se", "ldap-auth", "msg", "failed to get IdP", "error", err)
return false, err
}
username, err := parseUsername(dn)
if err != nil {
return false, err
}
var loginResult idfabric.LoginResult
idp.Login(
nil,
nil,
idfabric.WithGrantTypeROPC(
idfabric.ROPCRequest{Username: username, Password: actualPassword},
&loginResult,
),
)
if loginResult.Error != nil {
logger.Error("se", "ldap-auth", "msg", "password verification failed", "error", loginResult.Error)
return false, loginResult.Error
}
// Step 2: Verify the TOTP code against the MFA provider.
verified, err := verifyTOTP(api, totpCode)
if err != nil {
logger.Error("se", "ldap-auth", "msg", "TOTP verification error", "error", err)
return false, err
}
if !verified {
logger.Debug("se", "ldap-auth", "msg", "TOTP verification failed")
return false, nil
}
return true, nil
}
// verifyTOTP calls an external MFA provider API to verify the TOTP code.
func verifyTOTP(api orchestrator.Orchestrator, totpCode string) (bool, error) {
sp := api.SecretProvider()
accountSID, err := sp.GetString("mfa-account-sid")
if err != nil {
return false, fmt.Errorf("failed to get MFA account SID: %w", err)
}
authToken, err := sp.GetString("mfa-auth-token")
if err != nil {
return false, fmt.Errorf("failed to get MFA auth token: %w", err)
}
serviceID, err := sp.GetString("mfa-service-id")
if err != nil {
return false, fmt.Errorf("failed to get MFA service ID: %w", err)
}
entityID, err := sp.GetString("mfa-entity-id")
if err != nil {
return false, fmt.Errorf("failed to get MFA entity ID: %w", err)
}
apiURL := fmt.Sprintf(
"https://verify.example.com/v2/Services/%s/Entities/%s/Challenges",
serviceID, entityID,
)
formData := url.Values{}
formData.Set("AuthPayload", totpCode)
req, err := http.NewRequest(http.MethodPost, apiURL, strings.NewReader(formData.Encode()))
if err != nil {
return false, fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
auth := base64.StdEncoding.EncodeToString([]byte(accountSID + ":" + authToken))
req.Header.Set("Authorization", "Basic "+auth)
resp, err := api.HTTP().DefaultClient().Do(req)
if err != nil {
return false, fmt.Errorf("failed to call MFA API: %w", err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
api.Logger().Debug("se", "ldap-auth", "msg", "MFA API response", "status", resp.StatusCode, "body", string(body))
return resp.StatusCode == http.StatusCreated, nil
}
// parseUsername extracts the value of the first RDN from a DN.
func parseUsername(dn string) (string, error) {
parts := strings.Split(dn, ",")
if len(parts) == 0 {
return "", fmt.Errorf("invalid DN format")
}
rdn := parts[0]
eqIdx := strings.Index(rdn, "=")
if eqIdx < 0 || eqIdx == len(rdn)-1 {
return "", fmt.Errorf("malformed RDN: %s", rdn)
}
return rdn[eqIdx+1:], nil
}
```
```yaml maverics.yaml theme={null}
connectors:
- name: oidc
type: oidc
oidcWellKnownURL: https://idp.example.com/.well-known/openid-configuration
oauthClientID: my-client
oauthClientSecret:
scopes: openid profile email
ldapProvider:
enabled: true
uri: ldaps://0.0.0.0:636
authentication:
allowAnonymous: false
methods:
simple:
enabled: true
authenticateSE:
file: /etc/maverics/service-extensions/ldap-authenticate-totp.go
funcName: Authenticate
```
## Related Pages
Configuration, SDK reference, and best practices
LDAP provider mode configuration and setup
# OIDC
Source: https://docs.strata.io/reference/orchestrator/service-extensions/oidc
OIDC service extensions let you customize how the Orchestrator issues and manages OpenID Connect tokens. Use these hooks to control authentication, enforce authorization, load user attributes from external sources, and tailor the claims included in ID tokens, access tokens, and UserInfo responses.
## Request Lifecycle
The OIDC provider exposes multiple endpoints, each with its own hook points. The diagrams below show where service extension hooks execute in each flow.
### Authorization Endpoint
The authorization endpoint is where users log in and grant consent in their browser. This is the browser-based flow (front-channel) where most hooks execute.
```mermaid theme={null}
%%{init: {'theme': 'neutral', 'themeVariables': {'edgeWidth': 4}}}%%
flowchart TD
REQ[Authorization request] --> VAL[Validate request]
VAL --> SESS[Establish session]
SESS --> ISAUTH{isAuthenticatedSE}
ISAUTH -- "not authenticated, prompt=none" --> ERR1[Return login_required error]
ISAUTH -- "not authenticated" --> AUTH[authenticateSE]
ISAUTH -- "authenticated, re-login requested" --> AUTH
ISAUTH -- "authenticated" --> LOADATTR[loadAttrsSE]
AUTH --> REDIR[Redirect to identity provider]
LOADATTR -- error --> ERR3[Return error]
LOADATTR -- success --> AUTHZ{isAuthorizedSE}
AUTHZ -- authorized --> CACHE[Store user info in session]
AUTHZ -- denied --> ERR2[Return access_denied error]
CACHE --> TOKENS{Requested response type}
TOKENS -- code --> CODE[Generate authorization code]
TOKENS -- "token" --> ATCLAIMS[buildAccessTokenClaimsSE]
TOKENS -- "id_token" --> IDCLAIMS[buildIDTokenClaimsSE]
CODE --> REDIRECT[Redirect to application]
ATCLAIMS --> REDIRECT
IDCLAIMS --> REDIRECT
classDef hook stroke:#6A3EC8,stroke-width:6px
class ISAUTH,AUTH,LOADATTR,AUTHZ,ATCLAIMS,IDCLAIMS hook
```
The authorization step evaluates `isAuthorizedSE` if configured, along with any declarative authorization rules. Hybrid response types (e.g., `code id_token`) invoke multiple token-building paths from the response type branch.
### Token Endpoint
The token endpoint exchanges credentials or authorization codes for tokens. Your claims-building hooks run during token creation for all grant types.
```mermaid theme={null}
%%{init: {'theme': 'neutral', 'themeVariables': {'edgeWidth': 4}}}%%
flowchart TD
REQ[Token request] --> GRANT{Grant type?}
GRANT -- authorization_code --> CODE[Validate authorization code]
GRANT -- client_credentials --> CC[Authenticate client]
GRANT -- password --> ROPC[backchannel authenticateSE]
GRANT -- refresh_token --> RT[Validate refresh token]
GRANT -- token_exchange --> TE[Validate subject token]
CODE --> INFO1[Load user info from session]
ROPC -- error --> ERR[Return error]
ROPC -- success --> INFO2[Store user info in session]
RT --> INFO3[Load user info from session]
INFO1 --> AT[buildAccessTokenClaimsSE]
CC --> AT
INFO2 --> AT
INFO3 --> AT
TE --> AT
AT --> IDCHECK{OpenID scope requested?}
IDCHECK -- Yes --> IDT[buildIDTokenClaimsSE]
IDCHECK -- No --> RESP[Return tokens]
IDT --> RESP
classDef hook stroke:#6A3EC8,stroke-width:6px
class ROPC,AT,IDT hook
```
The `client_credentials`, `token_exchange`, and `refresh_token` grants only return access tokens — `buildIDTokenClaimsSE` is not called for these grant types.
### UserInfo Endpoint
The UserInfo endpoint returns profile information about the authenticated user. Applications call this endpoint with an access token to retrieve user attributes.
```mermaid theme={null}
%%{init: {'theme': 'neutral', 'themeVariables': {'edgeWidth': 4}}}%%
flowchart TD
REQ[UserInfo request] --> VAL[Validate access token]
VAL --> INFO[Load user info from session]
INFO --> CHECK{buildUserInfoClaimsSE configured?}
CHECK -- Yes --> SE[buildUserInfoClaimsSE]
CHECK -- No --> STD[Return default claims based on scopes]
SE --> RESP[Return user profile]
STD --> RESP
classDef hook stroke:#6A3EC8,stroke-width:6px
class SE hook
```
`buildUserInfoClaimsSE` is configured at the OIDC provider level (`oidcProvider.buildUserInfoClaimsSE`), not on individual OIDC apps. When configured, it replaces the default scope-based claims building entirely.
## Hooks
### `isAuthenticatedSE`
Determine whether the current user is already authenticated. Return `true` to skip the login flow, or `false` to send the user through authentication. Use this when you need custom logic to check authentication status -- for example, validating an external session token or checking a cookie from another system.
**Signature:**
```go theme={null}
func IsAuthenticated(api orchestrator.Orchestrator, rw http.ResponseWriter, req *http.Request) bool
```
**Config location:** `apps[].authentication.isAuthenticatedSE`
**Parameters:**
| Parameter | Type | Description |
| --------- | --------------------------- | ----------------------------------------------------------------------------- |
| `api` | `orchestrator.Orchestrator` | Access to sessions, caches, secrets, logging, and other Orchestrator services |
| `rw` | `http.ResponseWriter` | The HTTP response writer for the current request |
| `req` | `*http.Request` | The incoming HTTP request |
**Returns:** `bool` -- `true` if the user is authenticated, `false` otherwise.
***
### `authenticateSE`
Handle authentication when the user has not yet logged in. Use this to redirect to an external login page, validate credentials directly, or start a custom authentication flow.
**Signature:**
```go theme={null}
func Authenticate(api orchestrator.Orchestrator, rw http.ResponseWriter, req *http.Request)
```
**Config location:** `apps[].authentication.authenticateSE`
**Parameters:**
| Parameter | Type | Description |
| --------- | --------------------------- | ----------------------------------------------------------------------------- |
| `api` | `orchestrator.Orchestrator` | Access to sessions, caches, secrets, logging, and other Orchestrator services |
| `rw` | `http.ResponseWriter` | The HTTP response writer -- use to redirect or return an error response |
| `req` | `*http.Request` | The incoming HTTP request |
***
### `authenticateSE` (backchannel)
Handle direct credential-based authentication, such as the Resource Owner Password Credentials (ROPC) grant. Unlike the browser-based `authenticateSE`, this variant processes credentials server-to-server (backchannel) without user interaction and returns an error if authentication fails.
**Signature:**
```go theme={null}
func AuthenticateBackchannel(api orchestrator.Orchestrator, req *http.Request) error
```
**Config location:** `apps[].authentication.backchannel.authenticateSE`
**Parameters:**
| Parameter | Type | Description |
| --------- | --------------------------- | ----------------------------------------------------------------------------- |
| `api` | `orchestrator.Orchestrator` | Access to sessions, caches, secrets, logging, and other Orchestrator services |
| `req` | `*http.Request` | The incoming HTTP request containing credentials |
**Returns:** `error` -- return `nil` on success, or an error if authentication fails.
***
### `isAuthorizedSE`
Decide whether an authenticated user is allowed to proceed. Return `true` to allow the request or `false` to deny it. Use this to call an external policy engine, enforce attribute-based access control (ABAC), or apply custom business rules beyond what declarative authorization rules support.
**Signature:**
```go theme={null}
func IsAuthorized(api orchestrator.Orchestrator, rw http.ResponseWriter, req *http.Request) bool
```
**Config location:** `apps[].authorization.isAuthorizedSE`
**Parameters:**
| Parameter | Type | Description |
| --------- | --------------------------- | ----------------------------------------------------------------------------- |
| `api` | `orchestrator.Orchestrator` | Access to sessions, caches, secrets, logging, and other Orchestrator services |
| `rw` | `http.ResponseWriter` | The HTTP response writer for the current request |
| `req` | `*http.Request` | The incoming HTTP request |
**Returns:** `bool` -- `true` if the user is authorized, `false` otherwise.
***
### `loadAttrsSE`
Enrich the user's session with additional attributes before tokens are issued. Use this to pull in user details from external sources -- such as an LDAP directory, a database, or a REST API -- transform attribute values, or merge attributes from multiple identity providers.
**Signature:**
```go theme={null}
func LoadAttrs(api orchestrator.Orchestrator, rw http.ResponseWriter, req *http.Request) error
```
**Config location:** `apps[].loadAttrsSE`
**Parameters:**
| Parameter | Type | Description |
| --------- | --------------------------- | ----------------------------------------------------------------------------- |
| `api` | `orchestrator.Orchestrator` | Access to sessions, caches, secrets, logging, and other Orchestrator services |
| `rw` | `http.ResponseWriter` | The HTTP response writer for the current request |
| `req` | `*http.Request` | The incoming HTTP request |
**Returns:** `error` -- return `nil` on success, or an error to indicate attribute loading failed.
***
### `buildIDTokenClaimsSE`
Add custom claims to ID tokens issued by the OIDC provider. The claims you return are merged into the token alongside the standard claims. Use this to include user attributes from external sources, add computed values, or conditionally include claims based on the requested scopes.
**Signature:**
```go theme={null}
func BuildIDTokenClaims(api orchestrator.Orchestrator, req *http.Request) (map[string]interface{}, error)
```
**Config location:** `apps[].buildIDTokenClaimsSE`
**Parameters:**
| Parameter | Type | Description |
| --------- | --------------------------- | ----------------------------------------------------------------------------- |
| `api` | `orchestrator.Orchestrator` | Access to sessions, caches, secrets, logging, and other Orchestrator services |
| `req` | `*http.Request` | The incoming HTTP request (token endpoint request) |
**Returns:**
* `map[string]interface{}` -- claims to include in the ID token
* `error` -- return `nil` on success, or an error if claim building fails
***
### `buildAccessTokenClaimsSE`
Add custom claims to access tokens issued by the OIDC provider. The claims you return are merged into the token alongside the standard claims. Use this to include roles, group memberships, entitlements, or application-specific data.
**Signature:**
```go theme={null}
func BuildAccessTokenClaims(api orchestrator.Orchestrator, req *http.Request) (map[string]interface{}, error)
```
**Config location:** `apps[].buildAccessTokenClaimsSE`
**Parameters:**
| Parameter | Type | Description |
| --------- | --------------------------- | ----------------------------------------------------------------------------- |
| `api` | `orchestrator.Orchestrator` | Access to sessions, caches, secrets, logging, and other Orchestrator services |
| `req` | `*http.Request` | The incoming HTTP request (token endpoint request) |
**Returns:**
* `map[string]interface{}` -- claims to include in the access token
* `error` -- return `nil` on success, or an error if claim building fails
***
### `buildUserInfoClaimsSE`
Control what user profile information the UserInfo endpoint returns. The attributes you return become the full response body, replacing the default scope-based claims. Use this to limit which attributes are exposed, add computed values, or pull in attributes from external sources.
**Signature:**
```go theme={null}
func BuildUserInfoClaims(api orchestrator.Orchestrator, req *http.Request) (map[string]any, error)
```
**Config location:** `oidcProvider.buildUserInfoClaimsSE`
**Parameters:**
| Parameter | Type | Description |
| --------- | --------------------------- | ----------------------------------------------------------------------------- |
| `api` | `orchestrator.Orchestrator` | Access to sessions, caches, secrets, logging, and other Orchestrator services |
| `req` | `*http.Request` | The incoming UserInfo endpoint request |
**Returns:**
* `map[string]any` -- claims to include in the UserInfo response
* `error` -- return `nil` on success, or an error if claim building fails
This hook is configured at the OIDC provider level (`oidcProvider`), not on individual OIDC apps.
## Related Pages
Configuration, SDK reference, and best practices
OIDC application configuration and token settings
# Proxy
Source: https://docs.strata.io/reference/orchestrator/service-extensions/proxy
Proxy service extensions let you customize how the Orchestrator handles requests to your protected web applications. Use these hooks to control authentication, enforce authorization policies, enrich requests with user attributes, inject headers, modify requests and responses, and automate login to upstream applications.
## Request Lifecycle
The following diagram shows the Orchestrator's request processing pipeline for proxy apps. Each service extension hook is shown at the point where it executes in the flow.
```mermaid theme={null}
%%{init: {'theme': 'neutral', 'themeVariables': {'edgeWidth': 4}}}%%
flowchart TD
REQ[Incoming request] --> MATCH{Request matches a policy?}
MATCH -- No --> DENY1[Return 403 Forbidden]
MATCH -- Yes --> OPEN{Public access allowed?}
OPEN -- Yes --> ISLOGGED
OPEN -- No --> ISAUTH{isAuthenticatedSE}
ISAUTH -- "true" --> LOADATTR[loadAttrsSE]
ISAUTH -- "false" --> AUTH[authenticateSE]
AUTH --> REDIR[Redirect to identity provider]
LOADATTR --> AUTHZ{isAuthorizedSE}
AUTHZ -- authorized --> HEADERS[createHeaderSE]
AUTHZ -- denied --> UNAUTH[handleUnauthorizedSE]
HEADERS --> ISLOGGED{isLoggedInSE}
ISLOGGED -- "true" --> MODREQ[modifyRequestSE]
ISLOGGED -- "false" --> LOGIN[loginSE]
LOGIN --> UPLOGIN[Log in to upstream app]
MODREQ --> PROXY[Forward request to upstream app]
PROXY --> MODRESP[modifyResponseSE]
MODRESP --> RESP[Return response to user]
classDef hook stroke:#6A3EC8,stroke-width:6px
class ISAUTH,AUTH,LOADATTR,AUTHZ,HEADERS,UNAUTH,ISLOGGED,LOGIN,MODREQ,MODRESP hook
```
When a request arrives, the Orchestrator matches it against configured policies. For protected policies, the flow proceeds through authentication, attribute loading, authorization, header injection, optional upstream login, and request/response modification before the response is returned to the user. The authorization step evaluates `isAuthorizedSE` if configured, along with any declarative authorization rules defined on the policy.
Policy decisions (authorization result and headers) are cached in the user's session. On subsequent requests, cached decisions skip directly to the upstream login check, bypassing the authentication, attribute loading, authorization, and header building steps.
## Hooks
### `isAuthenticatedSE`
Determine whether the current user is already authenticated. Return `true` to skip the login flow, or `false` to send the user through authentication. Use this when you need custom logic to check authentication status -- for example, validating an external session token or checking a cookie from another system.
**Signature:**
```go theme={null}
func IsAuthenticated(api orchestrator.Orchestrator, rw http.ResponseWriter, req *http.Request) bool
```
**Config location:** `apps[].policies[].authentication.isAuthenticatedSE`
**Parameters:**
| Parameter | Type | Description |
| --------- | --------------------------- | ----------------------------------------------------------------------------- |
| `api` | `orchestrator.Orchestrator` | Access to sessions, caches, secrets, logging, and other Orchestrator services |
| `rw` | `http.ResponseWriter` | The HTTP response writer for the current request |
| `req` | `*http.Request` | The incoming HTTP request |
**Returns:** `bool` -- `true` if the user is authenticated, `false` otherwise.
**Examples:**
See the [full example under `authenticateSE`](#authenticatese) for a combined
implementation that uses both `isAuthenticatedSE` and `authenticateSE` to let
users choose which identity provider to authenticate with.
See the [full example under `authenticateSE`](#authenticatese) for a combined
implementation that uses both `isAuthenticatedSE` and `authenticateSE` to
authenticate users against an LDAP directory over TLS.
***
### `authenticateSE`
Handle authentication when the user has not yet logged in. Use this to redirect to an external login page, validate credentials directly, or start a custom authentication flow.
**Signature:**
```go theme={null}
func Authenticate(api orchestrator.Orchestrator, rw http.ResponseWriter, req *http.Request)
```
**Config location:** `apps[].policies[].authentication.authenticateSE`
**Parameters:**
| Parameter | Type | Description |
| --------- | --------------------------- | ----------------------------------------------------------------------------- |
| `api` | `orchestrator.Orchestrator` | Access to sessions, caches, secrets, logging, and other Orchestrator services |
| `rw` | `http.ResponseWriter` | The HTTP response writer -- use to redirect or return an error response |
| `req` | `*http.Request` | The incoming HTTP request |
**Examples:**
When multiple identity providers are available, you can give users a
choice of which one to authenticate with. This extension pairs
`isAuthenticatedSE` and `authenticateSE` to implement an IdP selector.
The `IsAuthenticated` function checks the session to determine if the user
has already authenticated with any configured IdP, while `Authenticate`
renders a selector form and delegates login to the chosen provider.
```go idp-selector.go theme={null}
package main
import (
"fmt"
"strings"
"net/http"
"github.com/strata-io/service-extension/orchestrator"
"github.com/strata-io/service-extension/session"
)
// IsAuthenticated checks whether the user has an active session with
// any of the configured identity providers. The list of IdP names is
// read from the service extension's metadata.
func IsAuthenticated(
api orchestrator.Orchestrator,
rw http.ResponseWriter,
req *http.Request,
) bool {
logger := api.Logger()
logger.Info("se", "determining if user is authenticated")
sess, err := api.Session(session.WithRequest(req))
if err != nil {
logger.Error("se", "unable to retrieve session", "error", err.Error())
http.Error(rw, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return false
}
// Read the comma-separated list of IdP names from the SE metadata.
metadata := api.Metadata()
idpNames := strings.Split(metadata["idps"].(string), ",")
for _, idpName := range idpNames {
authenticated, err := sess.GetBool(idpName + ".authenticated")
if err != nil {
logger.Error(
"se", fmt.Sprintf("unable to retrieve session value '%s.authenticated'", idpName),
"error", err.Error(),
)
}
if authenticated {
logger.Info("se", fmt.Sprintf("user is authenticated with '%s'", idpName))
return true
}
}
return false
}
```
```go idp-selector.go theme={null}
package main
import (
"fmt"
"net/http"
"github.com/strata-io/service-extension/orchestrator"
)
// Authenticate renders an IdP selector form on GET and delegates
// authentication to the selected provider on POST.
func Authenticate(
api orchestrator.Orchestrator,
rw http.ResponseWriter,
req *http.Request,
) {
logger := api.Logger()
logger.Info("se", "authenticating user")
if req.Method == http.MethodGet {
// Render the IdP selector form. In production, this markup can
// be loaded from a template file, styled to match the application,
// or dynamically generated from the configured IdP list.
_, _ = rw.Write([]byte(idpForm))
return
}
if req.Method != http.MethodPost {
http.Error(rw, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
return
}
err := req.ParseForm()
if err != nil {
logger.Error("se", "failed to parse form from request", "error", err.Error())
http.Error(rw, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
selectedIDP := req.Form.Get("idp")
logger.Info("se", fmt.Sprintf("user selected '%s' for authentication", selectedIDP))
idp, err := api.IdentityProvider(selectedIDP)
if err != nil {
logger.Error("se", "unable to lookup IdP", "error", err.Error())
http.Error(rw, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
idp.Login(rw, req)
}
const idpForm = `
IdP Selector
`
```
```yaml maverics.yaml theme={null}
connectors:
- name: entra
type: oidc
oidcWellKnownURL: https://login.microsoftonline.com//v2.0/.well-known/openid-configuration
oauthClientID:
oauthClientSecret:
scopes: openid profile email
- name: okta
type: oidc
oidcWellKnownURL: https://dev-123456.okta.com/.well-known/openid-configuration
oauthClientID:
oauthClientSecret:
scopes: openid profile email
apps:
- name: my-app
type: proxy
upstream: https://app.example.com
policies:
- location: /
authentication:
idps:
- entra
- okta
isAuthenticatedSE:
funcName: IsAuthenticated
file: /etc/maverics/extensions/idp-selector.go
metadata:
idps: entra,okta
authenticateSE:
funcName: Authenticate
file: /etc/maverics/extensions/idp-selector.go
```
Some applications require the user to actively re-authenticate at the
identity provider on every login -- for example, when returning after
logging out of a sensitive application -- rather than silently reusing an
existing IdP session. This extension pairs `isAuthenticatedSE` and
`authenticateSE`: `IsAuthenticated` checks whether the SAML connector has
already authenticated the user, and `Authenticate` starts login with the
`WithForceAuthentication` option, which sets `ForceAuthn="true"` on the SAML
AuthnRequest so the IdP prompts for credentials again.
Forced re-authentication is driven entirely by the service extension. Call
`idp.Login` with `idfabric.WithForceAuthentication()` on every login to
always re-prompt, or apply it conditionally -- for example, only for step-up
scenarios -- to decide per request.
```go force-authn.go theme={null}
package main
import (
"net/http"
"github.com/strata-io/service-extension/orchestrator"
"github.com/strata-io/service-extension/session"
)
// IsAuthenticated reports whether the user has already authenticated
// with the "saml" connector. The connector records this as the session
// boolean ".authenticated".
func IsAuthenticated(
api orchestrator.Orchestrator,
rw http.ResponseWriter,
req *http.Request,
) bool {
logger := api.Logger()
sess, err := api.Session(session.WithRequest(req))
if err != nil {
logger.Error("se", "unable to retrieve session", "error", err.Error())
return false
}
authenticated, _ := sess.GetBool("saml.authenticated")
return authenticated
}
```
```go force-authn.go theme={null}
package main
import (
"net/http"
"github.com/strata-io/service-extension/idfabric"
"github.com/strata-io/service-extension/orchestrator"
)
// Authenticate starts login against the "saml" connector, forcing the
// IdP to actively re-authenticate the user even if they already have an
// IdP session. WithForceAuthentication sets ForceAuthn="true" on the
// SAML AuthnRequest.
func Authenticate(
api orchestrator.Orchestrator,
rw http.ResponseWriter,
req *http.Request,
) {
logger := api.Logger()
idp, err := api.IdentityProvider("saml")
if err != nil {
logger.Error("se", "unable to lookup IdP", "error", err.Error())
http.Error(rw, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
idp.Login(rw, req, idfabric.WithForceAuthentication())
}
```
```yaml maverics.yaml theme={null}
connectors:
- name: saml
type: saml
samlMetadataURL: https://idp.example.com/metadata
samlConsumerServiceURL: https://orch.example.com/saml/callback
samlEntityID: https://orch.example.com
apps:
- name: my-app
type: proxy
upstream: https://app.example.com
policies:
- location: /
authentication:
idps:
- saml
isAuthenticatedSE:
funcName: IsAuthenticated
file: /etc/maverics/extensions/force-authn.go
authenticateSE:
funcName: Authenticate
file: /etc/maverics/extensions/force-authn.go
```
When an application relies on HTTP Basic Auth, this extension intercepts
the credentials and authenticates the user against an LDAP directory over
TLS. The `IsAuthenticated` function checks the session for a previous
successful bind, while `Authenticate` extracts the Basic Auth credentials,
connects to LDAP with StartTLS, and performs a bind to verify them.
```go ldap-tls-auth.go theme={null}
package main
import (
"fmt"
"net/http"
"github.com/strata-io/service-extension/orchestrator"
"github.com/strata-io/service-extension/session"
)
// IsAuthenticated checks whether the user has already authenticated
// against the LDAP directory in a previous request.
func IsAuthenticated(
api orchestrator.Orchestrator,
rw http.ResponseWriter,
req *http.Request,
) bool {
logger := api.Logger()
sess, err := api.Session(session.WithRequest(req))
if err != nil {
logger.Error("se", "unable to retrieve session", "error", err.Error())
http.Error(rw, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return false
}
metadata := api.Metadata()
idpName := metadata["idpName"].(string)
authenticated, err := sess.GetBool(fmt.Sprintf("%s.authenticated", idpName))
if err != nil {
logger.Error("se", "unable to check authentication status", "error", err.Error())
return false
}
return authenticated
}
```
```go ldap-tls-auth.go theme={null}
package main
import (
"crypto/tls"
"crypto/x509"
"fmt"
"net/http"
ldap3 "github.com/go-ldap/ldap/v3"
"github.com/strata-io/service-extension/orchestrator"
"github.com/strata-io/service-extension/session"
)
// Authenticate extracts HTTP Basic Auth credentials from the request
// and verifies them by binding against an LDAP directory over TLS.
func Authenticate(
api orchestrator.Orchestrator,
rw http.ResponseWriter,
req *http.Request,
) {
logger := api.Logger()
sess, err := api.Session(session.WithRequest(req))
if err != nil {
logger.Error("se", "unable to retrieve session", "error", err.Error())
http.Error(rw, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
sp := api.SecretProvider()
metadata := api.Metadata()
idpName := metadata["idpName"].(string)
ldapURL := metadata["ldapURL"].(string)
ldapServerName := metadata["ldapServerName"].(string)
ldapBaseDN := metadata["ldapBaseDN"].(string)
username, password, ok := req.BasicAuth()
if !ok {
logger.Error("se", "unable to read Basic Auth headers")
http.Error(rw, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
return
}
// Load the CA certificate for the LDAP server from the secret provider.
caCert, err := sp.GetString("ldapCACert")
if err != nil {
logger.Error("se", "unable to get LDAP CA cert", "error", err.Error())
http.Error(rw, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
certPool, err := x509.SystemCertPool()
if err != nil {
logger.Error("se", "unable to load system cert pool", "error", err.Error())
http.Error(rw, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
certPool.AppendCertsFromPEM([]byte(caCert))
// Connect to LDAP with TLS.
conn, err := ldap3.DialURL(ldapURL, ldap3.DialWithTLSConfig(&tls.Config{
ServerName: ldapServerName,
RootCAs: certPool,
}))
if err != nil {
logger.Error("se", "unable to dial LDAP", "error", err.Error())
http.Error(rw, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
defer conn.Close()
// Bind with the user's credentials to verify them.
bindDN := fmt.Sprintf("uid=%s,%s", username, ldapBaseDN)
err = conn.Bind(bindDN, password)
if err != nil {
logger.Error("se", "LDAP bind failed", "error", err.Error())
http.Error(rw, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
return
}
// Store authentication status in the session.
_ = sess.SetBool(fmt.Sprintf("%s.authenticated", idpName), true)
_ = sess.SetString(fmt.Sprintf("%s.cn", idpName), username)
if err := sess.Save(); err != nil {
logger.Error("se", "unable to save session", "error", err.Error())
http.Error(rw, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
logger.Info("se", "user authenticated via LDAP", "username", username)
}
```
```yaml maverics.yaml theme={null}
apps:
- name: my-app
type: proxy
upstream: https://app.example.com
policies:
- location: /
authentication:
isAuthenticatedSE:
funcName: IsAuthenticated
file: /etc/maverics/extensions/ldap-tls-auth.go
metadata:
idpName: ldap
authenticateSE:
funcName: Authenticate
file: /etc/maverics/extensions/ldap-tls-auth.go
metadata:
idpName: ldap
ldapURL: "ldaps://ldap.example.com"
ldapServerName: ldap.example.com
ldapBaseDN: "ou=People,dc=example,dc=com"
authorization:
allowAll: true
```
***
### `isAuthorizedSE`
Decide whether an authenticated user is allowed to access the requested resource. Return `true` to allow the request or `false` to deny it. Use this to call an external policy engine, enforce attribute-based access control (ABAC), or apply custom business rules beyond what declarative authorization rules support.
**Signature:**
```go theme={null}
func IsAuthorized(api orchestrator.Orchestrator, rw http.ResponseWriter, req *http.Request) bool
```
**Config location:** `apps[].policies[].authorization.isAuthorizedSE`
**Parameters:**
| Parameter | Type | Description |
| --------- | --------------------------- | ----------------------------------------------------------------------------- |
| `api` | `orchestrator.Orchestrator` | Access to sessions, caches, secrets, logging, and other Orchestrator services |
| `rw` | `http.ResponseWriter` | The HTTP response writer for the current request |
| `req` | `*http.Request` | The incoming HTTP request |
**Returns:** `bool` -- `true` if the user is authorized, `false` otherwise.
***
### `handleUnauthorizedSE`
Customize the response when a user fails authorization. Use this to redirect to a custom error page, return a specific error code, or log additional context about the denied request.
**Signature:**
```go theme={null}
func HandleUnauthorized(api orchestrator.Orchestrator, rw http.ResponseWriter, req *http.Request)
```
**Config location:** `apps[].handleUnauthorizedSE`
**Parameters:**
| Parameter | Type | Description |
| --------- | --------------------------- | ----------------------------------------------------------------------------- |
| `api` | `orchestrator.Orchestrator` | Access to sessions, caches, secrets, logging, and other Orchestrator services |
| `rw` | `http.ResponseWriter` | The HTTP response writer -- use to write a custom error response or redirect |
| `req` | `*http.Request` | The incoming HTTP request that was denied |
***
### `loadAttrsSE`
Enrich the user's session with additional attributes before the request is processed. Use this to pull in user details from external sources -- such as an LDAP directory, a database, or a REST API -- transform attribute values, or merge attributes from multiple identity providers.
**Signature:**
```go theme={null}
func LoadAttrs(api orchestrator.Orchestrator, rw http.ResponseWriter, req *http.Request) error
```
**Config location:** `apps[].loadAttrsSE`
**Parameters:**
| Parameter | Type | Description |
| --------- | --------------------------- | ----------------------------------------------------------------------------- |
| `api` | `orchestrator.Orchestrator` | Access to sessions, caches, secrets, logging, and other Orchestrator services |
| `rw` | `http.ResponseWriter` | The HTTP response writer for the current request |
| `req` | `*http.Request` | The incoming HTTP request |
**Returns:** `error` -- return `nil` on success, or an error to indicate attribute loading failed.
**Examples:**
When authorization decisions depend on group memberships stored in an LDAP
directory, this extension queries LDAP for the authenticated user's groups
and stores them in the session. Downstream hooks like `isAuthorizedSE` or
`createHeaderSE` can then read the groups from the session without
repeating the LDAP lookup.
```go load-ldap-groups.go theme={null}
package main
import (
"crypto/tls"
"crypto/x509"
"errors"
"fmt"
"net/http"
"strings"
ldap3 "github.com/go-ldap/ldap/v3"
"github.com/strata-io/service-extension/orchestrator"
"github.com/strata-io/service-extension/secret"
"github.com/strata-io/service-extension/session"
)
func LoadAttrs(
api orchestrator.Orchestrator,
_ http.ResponseWriter,
req *http.Request,
) error {
logger := api.Logger()
logger.Info("se", "loading attributes from LDAP")
sess, err := api.Session(session.WithRequest(req))
if err != nil {
return fmt.Errorf("unable to retrieve session: %w", err)
}
sp := api.SecretProvider()
metadata := api.Metadata()
ldapServerName := metadata["ldapServerName"].(string)
ldapBaseDN := metadata["ldapBaseDN"].(string)
ldapFilterFmt := metadata["ldapFilterFmt"].(string)
delimiter := metadata["delimiter"].(string)
// Look up the authenticated user's email to build the LDAP filter.
uid, err := sess.GetString("entra.email")
if err != nil {
return fmt.Errorf("failed to find user email for LDAP query: %w", err)
}
filter := fmt.Sprintf(ldapFilterFmt, uid)
groups, err := queryLDAPGroups(ldapServerName, ldapBaseDN, filter, sp)
if err != nil {
return fmt.Errorf("unable to get groups: %w", err)
}
list := strings.Join(groups, delimiter)
logger.Debug("se", "setting groups attribute", "se.groups", list)
err = sess.SetString("se.groups", list)
if err != nil {
return fmt.Errorf("unable to set 'se.groups' in session: %w", err)
}
return sess.Save()
}
// queryLDAPGroups connects to the LDAP server with TLS, binds with a
// service account, and searches for group CNs matching the filter.
func queryLDAPGroups(
serverName, baseDN, filter string,
sp secret.Provider,
) ([]string, error) {
conn, err := ldap3.DialURL(fmt.Sprintf("ldap://%s", serverName))
if err != nil {
return nil, fmt.Errorf("unable to dial LDAP: %w", err)
}
defer conn.Close()
// Upgrade to TLS using the CA certificate from the secret provider.
caCert, err := sp.GetString("ldapCACert")
if err != nil {
return nil, fmt.Errorf("unable to get LDAP CA cert: %w", err)
}
certPool, err := x509.SystemCertPool()
if err != nil {
return nil, fmt.Errorf("unable to get system cert pool: %w", err)
}
if ok := certPool.AppendCertsFromPEM([]byte(caCert)); !ok {
return nil, errors.New("unable to append CA cert to pool")
}
err = conn.StartTLS(&tls.Config{
RootCAs: certPool,
ServerName: serverName,
})
if err != nil {
return nil, fmt.Errorf("unable to start TLS: %w", err)
}
// Bind with the service account credentials.
username, err := sp.GetString("serviceAccountUsername")
if err != nil {
return nil, fmt.Errorf("unable to get service account username: %w", err)
}
password, err := sp.GetString("serviceAccountPassword")
if err != nil {
return nil, fmt.Errorf("unable to get service account password: %w", err)
}
err = conn.Bind(username, password)
if err != nil {
return nil, fmt.Errorf("unable to bind: %w", err)
}
searchReq := ldap3.NewSearchRequest(
baseDN,
ldap3.ScopeWholeSubtree, ldap3.NeverDerefAliases, 0, 0, false,
filter,
[]string{"cn"},
nil,
)
result, err := conn.Search(searchReq)
if err != nil {
return nil, fmt.Errorf("unable to search LDAP: %w", err)
}
groups := make([]string, 0, len(result.Entries))
for _, entry := range result.Entries {
groups = append(groups, entry.GetAttributeValue("cn"))
}
return groups, nil
}
```
```yaml maverics.yaml theme={null}
connectors:
- name: entra
type: oidc
oidcWellKnownURL: https://login.microsoftonline.com//v2.0/.well-known/openid-configuration
oauthClientID:
oauthClientSecret:
scopes: openid profile email
apps:
- name: my-app
type: proxy
upstream: https://app.example.com
# Pass the loaded groups to the upstream app as a header.
headers:
- name: X-User-Groups
value: "{{ se.groups }}"
loadAttrsSE:
funcName: LoadAttrs
file: /etc/maverics/extensions/load-ldap-groups.go
metadata:
ldapServerName: ldap.example.com
ldapBaseDN: dc=example,dc=com
ldapFilterFmt: "(&(uniquemember=uid=%s,ou=users,dc=example,dc=com))"
delimiter: ","
policies:
- location: /
authentication:
idps:
- entra
authorization:
allowAll: true
```
***
### `createHeaderSE`
Build custom HTTP headers to send to the upstream application along with the proxied request. Use this when header values need to be computed dynamically -- for example, constructing a header from session attributes, looking up a value from an external service, or encoding user information for the upstream app.
**Signature:**
```go theme={null}
func CreateHeader(api orchestrator.Orchestrator, rw http.ResponseWriter, req *http.Request) (http.Header, error)
```
**Config location:** `apps[].headers[].createHeaderSE`
**Parameters:**
| Parameter | Type | Description |
| --------- | --------------------------- | ----------------------------------------------------------------------------- |
| `api` | `orchestrator.Orchestrator` | Access to sessions, caches, secrets, logging, and other Orchestrator services |
| `rw` | `http.ResponseWriter` | The HTTP response writer for the current request |
| `req` | `*http.Request` | The incoming HTTP request |
**Returns:**
* `http.Header` -- a map of header names to values to inject into the upstream request
* `error` -- return `nil` on success, or an error if header creation fails
On [open routes](/reference/orchestrator/applications/proxy#header-security-on-open-routes) (`allowUnauthenticated` + `allowAll`), this extension does not run, and the header names it would emit are not known when configuration loads. As a result, a client-supplied copy of a header this extension normally sets is **not** stripped and is forwarded to the upstream. Do not mark a route open if the upstream trusts an identity header produced by a `createHeaderSE`.
**Examples:**
When an upstream application expects user identity in specific HTTP headers,
this extension reads attributes from the user's session and constructs the
required headers. Each `createHeaderSE` entry handles one header, allowing
you to transform or combine attribute values as needed.
```go create-headers.go theme={null}
package main
import (
"fmt"
"net/http"
"github.com/strata-io/service-extension/orchestrator"
"github.com/strata-io/service-extension/session"
)
// CreateDisplayNameHeader builds a display name header by combining the
// user's first and last name from the session.
func CreateDisplayNameHeader(
api orchestrator.Orchestrator,
_ http.ResponseWriter,
req *http.Request,
) (http.Header, error) {
sess, err := api.Session(session.WithRequest(req))
if err != nil {
return nil, fmt.Errorf("unable to retrieve session: %w", err)
}
firstName, err := sess.GetString("entra.given_name")
if err != nil {
return nil, fmt.Errorf("unable to retrieve attribute 'entra.given_name': %w", err)
}
lastName, err := sess.GetString("entra.family_name")
if err != nil {
return nil, fmt.Errorf("unable to retrieve attribute 'entra.family_name': %w", err)
}
header := make(http.Header)
header["X-Display-Name"] = []string{firstName + " " + lastName}
return header, nil
}
// CreateEmailHeader reads the user's email from the session and sets it
// as a header for the upstream application.
func CreateEmailHeader(
api orchestrator.Orchestrator,
_ http.ResponseWriter,
req *http.Request,
) (http.Header, error) {
sess, err := api.Session(session.WithRequest(req))
if err != nil {
return nil, fmt.Errorf("unable to retrieve session: %w", err)
}
email, err := sess.GetString("entra.email")
if err != nil {
return nil, fmt.Errorf("unable to retrieve attribute 'entra.email': %w", err)
}
header := make(http.Header)
header["X-User-Email"] = []string{email}
return header, nil
}
```
```yaml maverics.yaml theme={null}
connectors:
- name: entra
type: oidc
oidcWellKnownURL: https://login.microsoftonline.com//v2.0/.well-known/openid-configuration
oauthClientID:
oauthClientSecret:
scopes: openid profile email
apps:
- name: my-app
type: proxy
upstream: https://app.example.com
headers:
- createHeaderSE:
funcName: CreateDisplayNameHeader
file: /etc/maverics/extensions/create-headers.go
- createHeaderSE:
funcName: CreateEmailHeader
file: /etc/maverics/extensions/create-headers.go
```
***
### `modifyRequestSE`
Modify the HTTP request before it is forwarded to the upstream application. Use this to add authentication headers, rewrite paths, inject tracing headers, or transform the request body.
**Signature:**
```go theme={null}
func ModifyRequest(api orchestrator.Orchestrator, req *http.Request)
```
**Config location:** `apps[].modifyRequestSE`
**Parameters:**
| Parameter | Type | Description |
| --------- | --------------------------- | ----------------------------------------------------------------------------- |
| `api` | `orchestrator.Orchestrator` | Access to sessions, caches, secrets, logging, and other Orchestrator services |
| `req` | `*http.Request` | The outbound HTTP request to the upstream -- modify this object directly |
This hook runs on every proxied request. Keep it lightweight to avoid adding latency. Use `api.Cache()` to avoid repeating expensive lookups.
This hook runs on every request, including [open routes](/reference/orchestrator/applications/proxy#header-security-on-open-routes), and it runs *after* the Orchestrator strips managed headers. If your extension reads a client-supplied header and forwards it to the upstream, it can reintroduce attacker-controlled input that stripping would otherwise have removed. Do not pass through client-supplied identity headers on routes that reach a header-trusting upstream.
***
### `modifyResponseSE`
Modify the response from the upstream application before it reaches the user's browser. Use this to add security headers, transform response content, adjust status codes, or inject additional content.
**Signature:**
```go theme={null}
func ModifyResponse(api orchestrator.Orchestrator, resp *http.Response)
```
**Config location:** `apps[].modifyResponseSE`
**Parameters:**
| Parameter | Type | Description |
| --------- | --------------------------- | ----------------------------------------------------------------------------- |
| `api` | `orchestrator.Orchestrator` | Access to sessions, caches, secrets, logging, and other Orchestrator services |
| `resp` | `*http.Response` | The HTTP response from the upstream -- modify this object directly |
This hook runs on every proxied response. Keep it lightweight to avoid adding latency. Use `api.Cache()` to avoid repeating expensive lookups.
**Examples:**
Some applications lack single logout functionality. When the Orchestrator
sits in front of such an application, there is no built-in way for users to
trigger a federated logout because the upstream UI has no logout control
that integrates with the Orchestrator.
This service extension solves the problem by injecting a fixed-position
"Single Logout" button into every HTML page returned by the upstream
application. The button links to the Orchestrator's `/single-logout`
endpoint, giving users a way to initiate federated logout without any changes
to the upstream application's source code.
```go inject-slo-button.go theme={null}
package main
import (
"bytes"
"io"
"net/http"
"strconv"
"strings"
"github.com/strata-io/service-extension/orchestrator"
)
// ModifyResponse intercepts HTML responses from the upstream
// application and injects a fixed-position "Single Logout" button
// before the closing