docs(guides): add GitHub Actions JWT bearer token guide - #2346
Merged
Conversation
…okens & JWTs Add a cohesive capabilities page introducing how clients present an Authorization: Bearer token to Pomerium to reach upstreams without an interactive sign-in, covering all four bearer_token_format modes (default, idp_access_token, idp_identity_token, jwt) as a single feature. - New capabilities page with Kubernetes service account example - New reference pages for jwt_allowed_issuers and jwt_allowed_audiences - Document the new jwt option on the bearer-token-format reference - Register the capabilities page in the sidebar
Reduce emphasis to structural labels, thin em-dashes, de-bold inline HTTP status codes, and recast the two parallel no-X-no-Y-no-Z fragments. Prose-only; no content or link changes.
The JWT bearer-token feature shipped with a consolidated identity_providers
map rather than the flat jwt_allowed_issuers + jwt_allowed_audiences settings
these pages originally documented. Rewrite the pages to match:
- identity_providers is a map keyed by provider name; audiences are
per-provider (required, non-empty, fail-closed). Drop the old 'name' field.
- Routes select providers via an optional per-route identity_providers
allowlist; bearer_token_format: jwt remains the gate.
- Document the identity model: session idp_id = provider name, user id =
<provider-name>/<sub>, sub required, session TTL capped to
min(token exp, cookie_expire), raw JWT not persisted.
- supported_algs rejects none/HS*; JWKS TLS reuses the global
certificate_authority_file.
Replace reference/jwt-allowed-issuers with reference/identity-providers
("JWT Identity Providers"), delete reference/jwt-allowed-audiences, and add
reference/routes/identity-providers for the per-route allowlist.
The capabilities page split format coverage: it pointed to Bearer Token Format for the IdP formats while covering the jwt format itself, a false symmetry since the reference is the setting's home for all four formats. Move the format-agnostic mechanics and the four-format table to the Bearer Token Format reference, and the caller-identity behavior to JWT Identity Providers. The capabilities page becomes a pure jwt/M2M workflow guide that references those, collapsing duplication that already existed between it and the identity_providers reference.
Add a guide for letting a GitHub Actions workflow call a Pomerium-protected route with the OIDC token GitHub issues to each job, verified against the trusted issuer declared in identity_providers on a route using bearer_token_format: jwt, and authorized on the token's claims. AI usage disclosure (AI_POLICY.md): drafted and revised with Claude Code. The workflow, config, status codes, and log output were verified against a live Pomerium deployment and the Pomerium source before publishing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
✅ Deploy Preview for pomerium-docs ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
Greptile SummaryAdds documentation for authenticating GitHub Actions and other machine workloads to Pomerium-protected routes using verified JWT bearer tokens.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| content/docs/guides/github-actions.mdx | Adds the end-to-end GitHub Actions OIDC configuration, workflow, verification steps, troubleshooting, and security guidance. |
| content/docs/capabilities/bearer-token-access.mdx | Adds an overview of JWT bearer authentication with Kubernetes, SPIFFE, and GitHub Actions examples. |
| content/docs/reference/identity-providers.mdx | Documents global JWT identity-provider configuration, verification behavior, session derivation, and platform-specific syntax. |
| content/docs/reference/routes/identity-providers.mdx | Documents the per-route identity-provider allowlist for JWT bearer-token routes. |
| content/docs/reference/bearer-token-format.mdx | Extends the bearer-token reference with the JWT format and explains extraction, verification, session creation, and authorization. |
| sidebars.js | Adds the bearer-token capability page to the primary documentation sidebar. |
Sequence Diagram
sequenceDiagram
participant W as GitHub Actions workflow
participant G as GitHub OIDC provider
participant P as Pomerium
participant U as Protected upstream
W->>G: Request JWT for route audience
G-->>W: Short-lived signed JWT
W->>P: Request with Bearer JWT
P->>G: Fetch and cache signing keys
P->>P: Verify issuer, signature, expiry, and audience
P->>P: Authorize repository and optional ref claims
P->>U: Proxy authorized request
U-->>W: Response
Reviews (4): Last reviewed commit: "docs(guides): mark github-actions guide ..." | Re-trigger Greptile
revisions to github actions guide page Reorder and streamline the introduction, reduce some duplication, and remove some details that might be more confusing than helpful.
…dation (#2346) The fixture harness seals a guide into Docker Compose with an in-network Keycloak. Neither half of this flow survives that: a GitHub Actions OIDC token can only be minted inside a runner, where GitHub injects the ACTIONS_ID_TOKEN_REQUEST_* variables, and Pomerium must reach token.actions.githubusercontent.com for the issuer's JWKS. Add validate/SKIP with that reason and the manual validation record, plus validate/screenshots-skip, which the media policy requires because the guide references no screenshot. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
kenjenkins
approved these changes
Aug 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
docs/guides/github-actions, a guide for letting a GitHub Actions workflow call a Pomerium-protected route using the OIDC token GitHub issues to every job, with no stored credentials.The route uses
bearer_token_format: jwtand trustshttps://token.actions.githubusercontent.comthrough anidentity_providersentry; the workflow requests a token for the route's audience and presents it as a bearer token. Authorization is entirely policy-driven on the token's claims, and the guide is explicit that any GitHub repository can mint a token from this issuer, so pinningclaim/repositoryis the whole authorization boundary.This is stacked on #2279 — it links to the
identity_providers, per-routeidentity_providers, and bearer-token-access pages introduced there, so it cannot build againstmainuntil that merges.Not yet released. The feature landed in pomerium/pomerium@69d7f68f (2026-08-10), after v0.32.5, so no tagged release supports this guide. Worth holding publication until a release includes it.
Verified against a live deployment rather than written from the reference alone: the guide's workflow, copied verbatim, returns
Pomerium answered: HTTP 200, and Pomerium logsallow: truewithallow-why-true: ["claim-ok"]and the identitygithub-actions/repo:.... Both thepushandworkflow_dispatchtriggers were exercised.An independent review pass against the Pomerium source and GitHub's OIDC documentation caught two errors that are fixed here:
curl --failonly fails on status 400 and above, so a302sign-in redirect would have passed the workflow step silently. The call now also sendsAccept: application/jsonso denials arrive as401/403.The guide also avoids pinning the
subclaim, because repositories created after 2026-07-15 get the immutable format embedding numeric owner and repository IDs — confirmed in the live token captured during testing.Related
AI disclosure
Claude Code. The guide was AI-drafted, then fact-checked by a separate adversarial review pass against the Pomerium source and GitHub's current OIDC documentation, which produced the two corrections listed above. Every configuration snippet, status code, and log line was verified against a live Pomerium deployment before submission. Reviewed and edited by me.
Checklist