Research: candidate OIDC providers and non-interactive token flows for CI publishers #33

Closed
opened 2026-09-19 19:59:02 +00:00 by toasterson · 1 comment
Owner

Part of #24

Question

Survey, from primary documentation: Forgejo's OAuth2/OIDC provider (does it issue JWT access tokens or opaque ones? JWKS endpoint? client-credentials or only authorization-code? custom claims?), Keycloak, Authentik and Zitadel (client-credentials support, custom role/group claims, device-code flow), and Forgejo Actions OIDC/ID tokens. For each, state how a Solstice CI job would obtain a bearer token non-interactively and how a human maintainer would from a CLI.

Capture as docs/research/oidc-providers.md, with a recommendation table. This feeds the provider decision.

Part of #24 ## Question Survey, from primary documentation: Forgejo's OAuth2/OIDC provider (does it issue JWT access tokens or opaque ones? JWKS endpoint? client-credentials or only authorization-code? custom claims?), Keycloak, Authentik and Zitadel (client-credentials support, custom role/group claims, device-code flow), and Forgejo Actions OIDC/ID tokens. For each, state how a Solstice CI job would obtain a bearer token non-interactively and how a human maintainer would from a CLI. Capture as `docs/research/oidc-providers.md`, with a recommendation table. This feeds the provider decision. ## Links - Informs #18
Author
Owner

Resolution

Findings, sources cited in docs/research/oidc-providers.md:

  • Forgejo 16.0.2 on code.aopc.cloud exposes /.well-known/openid-configuration + /login/oauth/keys (RS256), but only authorization_code and refresh_token grants; no client_credentials, no device flow (routers/web/auth/oauth.go). Access tokens are JWTs carrying only gnt/tt/exp/iat (no iss/aud/sub), so pkg6depotd cannot validate them; ID tokens do carry iss/aud/sub plus groups (org, org:team). Docs warn OAuth2 scopes are "not yet implemented" (token = full user rights).
  • Forgejo Actions has GitHub-style OIDC ID tokens since v15 (PR #10481): enable-openid-connect: true, curl $ACTIONS_ID_TOKEN_REQUEST_URL&audience=..., issuer https://code.aopc.cloud/api/actions, JWKS /api/actions/.well-known/keys (verified live), RS256, 1 h lifetime, claims repository, ref, ref_protected, event_name, actor, sha, etc.; disabled for fork PRs.
  • Keycloak/authentik/ZITADEL all offer client_credentials for CI and device flow for humans, with configurable roles/groups claims and JWKS rotation. Keycloak: JVM + SQL DB, 2 GB recommended, external-token exchange is deprecated preview. authentik: server+worker+PostgreSQL (Redis dropped in 2025.10), default profile scope emits groups, and federated client_credentials accepts Forgejo Actions ID tokens as client assertions. ZITADEL: opaque tokens by default (JWT opt-in), roles under urn-prefixed claims, extra login container + immutable masterkey, keys rotate "without any prior notice".

Recommendation: (1) CI publishing: trust the Forgejo Actions OIDC issuer directly, secretless, gating on repository/ref claims; pkg6depotd needs multi-issuer support with per-issuer aud and a claim-to-role policy. Verify the Solstice runner injects ACTIONS_ID_TOKEN_REQUEST_*. (2) Humans: Forgejo OAuth2 auth-code+PKCE public client (loopback redirect), presenting the ID token with groups mapped to roles. (3) Only if a real IdP is later needed, pick authentik: lightest footprint and it federates the Forgejo Actions tokens natively.

Full findings: docs/research/oidc-providers.md on branch research/oidc-providers (research branch, not merged; cherry-pick the file when the decision it feeds is recorded).

## Resolution **Findings, sources cited in docs/research/oidc-providers.md:** - Forgejo 16.0.2 on code.aopc.cloud exposes `/.well-known/openid-configuration` + `/login/oauth/keys` (RS256), but only `authorization_code` and `refresh_token` grants; no client_credentials, no device flow (`routers/web/auth/oauth.go`). Access tokens are JWTs carrying only `gnt`/`tt`/`exp`/`iat` (no iss/aud/sub), so pkg6depotd cannot validate them; ID tokens do carry iss/aud/sub plus `groups` (org, org:team). Docs warn OAuth2 scopes are "not yet implemented" (token = full user rights). - Forgejo Actions has GitHub-style OIDC ID tokens since v15 (PR #10481): `enable-openid-connect: true`, curl `$ACTIONS_ID_TOKEN_REQUEST_URL&audience=...`, issuer `https://code.aopc.cloud/api/actions`, JWKS `/api/actions/.well-known/keys` (verified live), RS256, 1 h lifetime, claims `repository`, `ref`, `ref_protected`, `event_name`, `actor`, `sha`, etc.; disabled for fork PRs. - Keycloak/authentik/ZITADEL all offer client_credentials for CI and device flow for humans, with configurable roles/groups claims and JWKS rotation. Keycloak: JVM + SQL DB, 2 GB recommended, external-token exchange is deprecated preview. authentik: server+worker+PostgreSQL (Redis dropped in 2025.10), default `profile` scope emits `groups`, and federated `client_credentials` accepts Forgejo Actions ID tokens as client assertions. ZITADEL: opaque tokens by default (JWT opt-in), roles under urn-prefixed claims, extra login container + immutable masterkey, keys rotate "without any prior notice". **Recommendation:** (1) CI publishing: trust the Forgejo Actions OIDC issuer directly, secretless, gating on `repository`/`ref` claims; pkg6depotd needs multi-issuer support with per-issuer `aud` and a claim-to-role policy. Verify the Solstice runner injects `ACTIONS_ID_TOKEN_REQUEST_*`. (2) Humans: Forgejo OAuth2 auth-code+PKCE public client (loopback redirect), presenting the ID token with `groups` mapped to roles. (3) Only if a real IdP is later needed, pick authentik: lightest footprint and it federates the Forgejo Actions tokens natively. **Full findings:** [docs/research/oidc-providers.md](https://code.aopc.cloud/OpenIndiana/ips/src/branch/research/oidc-providers/docs/research/oidc-providers.md) on branch `research/oidc-providers` (research branch, not merged; cherry-pick the file when the decision it feeds is recorded).
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Reference
OpenIndiana/ips#33
No description provided.