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 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:- Traffic interception — The Orchestrator listens on configured route patterns (hostname/path combinations) and intercepts all matching HTTP requests before they reach the upstream application.
- Policy evaluation — Each request is matched against location-based policies. The Orchestrator determines which authentication and authorization rules apply based on the request path.
- 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.
- Authorization check — The Orchestrator evaluates authorization rules against the authenticated user’s attributes. Rules use
and/orconditions with operators likeequals,contains, etc. Unauthorized users are redirected or receive a 403 response. - 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. - 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, orX-Remote-Userinto 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 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 bothallowUnauthenticated: 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’sheaders:— before proxying. All other client headers are forwarded unchanged.
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.
location is a URL path used to map application resources to a policy. A request is matched to the most specific location, with regular expression (regex) locations taking priority.
Simple policy location matching is case-insensitive. If you define a location of /EXAMPLE, it matches requests with a path of /example or /Example. If you want the policy match to be case-sensitive, use a regex.
To apply regex matching to a location, add ~ before the pattern (note the trailing space). For example:
Matching order
The Orchestrator evaluates locations in this order and uses the first match:- Regex locations, in the order they appear in the configuration.
- Prefix (non-regex) locations, longest first.
Securing locations
- Prefer default-deny. Protect
/and use regex locations only to open specific exceptions, such as static assets. A request that misses the regex falls through to a stricter policy, which fails safe for any path trick, including ones not listed on this page. - Protect locations with a prefix. To protect a path, prefer a prefix location such as
/adminover a regex. - If a regex must protect a location, add
(?i)for case-insensitive matching, for example~ (?i)^/admin, and do not end the pattern with$or/. An end anchor lets any trailing variation the upstream ignores fall through to the next policy. A pattern such as^/admin/can be dodged by/admin./xin the same way$is dodged by/admin.. - Switch case sensitivity back on inside a pattern with the inline
(?-i)flag. Go regex supports inline flags such as(?i)and(?-i).
Examples
Open static assets and protect everything else
Open static assets and protect everything else
/ and use a regex location only to open the asset extensions. A request that misses the regex, including one using a path trick, falls through to / and requires authentication.Restrict an admin area to a group
Restrict an admin area to a group
/admin should be limited to administrators. Use a prefix location, which is case-insensitive and is not dodged by paths such as /ADMIN or /admin/. The longer prefix wins over /, so the stricter rules apply under /admin.Open a health check endpoint
Open a health check endpoint
/healthz without credentials. Open only that path with a prefix location and keep / protected.Protect part of an open asset tree with ordered regexes
Protect part of an open asset tree with ordered regexes
/assets/ but keep /assets/private protected, define the more specific regex first. The protecting regex uses (?i) so /ASSETS/PRIVATE cannot bypass it, and it does not end with $ or /.Avoid: a case-sensitive regex protecting /admin over an open /
Avoid: a case-sensitive regex protecting /admin over an open /
/admin, but it can be bypassed. The regex is case-sensitive, so a request for /ADMIN does not match it and falls through to /, which is open. On a case-insensitive upstream (for example Windows/IIS), /ADMIN reaches the same resource as /admin, and the Orchestrator proxies it without authentication./ so that a missed match fails safe, and by using a prefix location for /admin. Prefix locations are case-insensitive and cover everything under the path.If you must use a regex, make it case-insensitive and do not end it with $, for example ~ (?i)^/admin, and still keep / protected.Requests refused with a 403 instead of falling through
Requests refused with a 403 instead of falling through
/admin. as /admin. A request like that could reach a protected page while the Orchestrator applies a different, weaker policy to it. To prevent this, the Orchestrator returns a 403 when a path could mean a different location on the upstream than the one it appears to be.In this configuration, / is open and /admin is protected by an anchored regex:403:~ ^/admin$ as sent, so without this check each would fall through to the open / policy and be proxied without authentication.The 403 is a safety net, not a substitute for a secure configuration. Because / is open in this example, it is what lets these requests through when they miss the regex. Prefer a protected / so that a request that matches nothing more specific fails safe.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
- Console UI
- Configuration
Navigate to Applications
Set the application name
Set the upstream URL
https://internal-hr.example.com).Add route patterns
example.com), paths (/app), or both (example.com/app).Configure TLS settings
Configure mTLS (optional)
Set the unauthorized page
https://example.com/403).Configure preserve host
Configure logout settings (optional)
Save
Troubleshooting
Headers not arriving at the upstream application
Headers not arriving at the upstream application
- Header template syntax error — missing
{{ }}delimiters or incorrect spacing. - Connector name typo in the template (e.g.,
{{ my_idp.email }}when the connector is namedmy-idp). - The upstream application or an intermediate proxy is stripping custom or
X-headers.
- 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[].nameentry 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.
Authentication redirect loop
Authentication redirect loop
- 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.urlsconfigured on the connector. - The
routePatternsdo not cover the callback path, so the Orchestrator does not intercept the callback.
- Verify
session.cookie.domaincovers the Orchestrator’s hostname (e.g.,.example.comforapp.example.com). - Ensure the callback URL registered at the IdP is listed in
oauthLoginRedirect.urlson the connector. - Check that
routePatternsinclude the callback path so the Orchestrator can process the authentication response.
Upstream connection refused or timeout
Upstream connection refused or timeout
- The
upstreamURL is unreachable from the Orchestrator host. - TLS certificate mismatch on the upstream — the Orchestrator cannot verify the upstream’s certificate.
- Wrong port in the
upstreamURL.
- Verify the Orchestrator can reach the upstream URL from its host (test with
curlor 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
upstreamURL matches the port the backend application is listening on.
Session expires too quickly
Session expires too quickly
session.lifetime.idleTimeoutormaxTimeoutis 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.
- Adjust
session.lifetime.idleTimeoutandsession.lifetime.maxTimeoutto match your expected user session duration. - Configure sticky sessions on the load balancer using the
maverics_sessioncookie so that requests from the same user are routed to the same Orchestrator instance.