Conversation
Document JWT proxy authentication for reverse proxy setups (Pomerium, Cloudflare Access, etc). Covers auth flow, config file/env vars, Docker example, options table, supported algorithms, and JWKS retry. Ref: semaphoreui/semaphore#3719
There was a problem hiding this comment.
Pull request overview
Adds end-user documentation for configuring JWT-based authentication when Semaphore is deployed behind an authenticating reverse proxy (e.g., Pomerium / Cloudflare Access), and exposes the new page in the Admin Guide sidebar.
Changes:
- Adds a new Admin Guide page describing JWT proxy auth flow, configuration (config file + env vars), and behavior details.
- Registers the new doc in the Docusaurus sidebar navigation.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
sidebars.js |
Adds the new JWT proxy auth doc to the Admin Guide sidebar items. |
docs/admin-guide/jwt-proxy-auth.md |
New documentation page covering JWT proxy auth setup, options, and JWKS behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| 1. The reverse proxy authenticates the user and adds a signed JWT to a configured HTTP header. | ||
| 2. Semaphore checks for this header on every request. If present, the token is validated against the JWKS endpoint. | ||
| 3. If the token is valid, the user is loaded by email. If no matching user exists, an external user is created automatically (same as OIDC). | ||
| 4. If the header is present but the token is invalid, Semaphore returns `401 Unauthorized` immediately -- existing bearer token and session auth are not attempted. | ||
| 5. If the header is absent, normal authentication (bearer token, session cookie) proceeds as usual. |
There was a problem hiding this comment.
JWT-in-header auth is sensitive to header spoofing / DoS if the upstream proxy forwards client-supplied values. Consider adding a short Security considerations note stating that the reverse proxy must strip any incoming JWT header from clients and only set/overwrite it after authentication (and ensure Semaphore isn’t reachable directly, bypassing the proxy).
|
|
||
| ## JWKS availability | ||
|
|
||
| Semaphore fetches the JWKS on startup. If the JWKS endpoint is unreachable, the server still starts and retries in the background (5s, 10s, 30s, then every 60s). JWT auth returns an error until the JWKS is loaded. |
There was a problem hiding this comment.
The JWKS retry schedule is documented with exact timings (5s, 10s, 30s, 60s). Unless these intervals are intended as a stable contract, consider describing it more generally (for example, “retries with backoff in the background”) or linking to a config/constant reference, so the docs don’t become stale if the implementation changes.
| Semaphore fetches the JWKS on startup. If the JWKS endpoint is unreachable, the server still starts and retries in the background (5s, 10s, 30s, then every 60s). JWT auth returns an error until the JWKS is loaded. | |
| Semaphore fetches the JWKS on startup. If the JWKS endpoint is unreachable, the server still starts and retries in the background with increasing backoff. JWT auth returns an error until the JWKS is loaded. |
Document JWT proxy authentication for reverse proxy
setups (Pomerium, Cloudflare Access, etc).
Covers auth flow, config file/env vars, Docker example,
options table, supported algorithms, and JWKS retry.
Ref: semaphoreui/semaphore#3719