Split out from #255. The CLI side of OIDC (sign-in, PKCE, keychain storage, Bearer tokens, per-agent API keys) has landed. This issue covers the remaining piece: letting a self-hosted open-source cq server verify access tokens issued by an external IdP (Keycloak, Okta, Entra ID, etc.), so an enterprise can run their own server against their own identity provider.
Today, the server authenticates requests two ways (server/backend/src/cq_server/api/deps.py):
get_current_user — decodes a JWT signed by the server itself with a symmetric secret (CQ_JWT_SECRET, HS256).
require_api_key — HMAC-compares a long-lived API key.
Neither validates a token minted by an external IdP.
Proposed scope (minimal, configurable):
- New optional config:
CQ_OIDC_ISSUER, CQ_OIDC_AUDIENCE, and optional CQ_OIDC_JWKS_URL (default to {issuer}/.well-known/openid-configuration discovery).
- A verification path that validates
iss, aud, exp, and signature against the issuer's JWKS (asymmetric, RS256/ES256), with JWKS cached and refreshed on kid miss.
- Map a configurable claim (
sub, or email/preferred_username) onto the identity recorded as created_by on knowledge units.
- When OIDC config is absent, behaviour is unchanged (symmetric JWT + API keys), so this is purely additive.
Out of scope for this issue: IdP federation, multi-issuer trust, rotation-policy enforcement, and fine-grained authorization/roles. These are larger pieces of work and would be tracked as separate issues if and when there's demand.
Before writing code: because this touches identity trust and token lifecycle, we'd like to agree the design up front. If you're interested in taking it on, comment here and we'll work with you to open an RFC (our RFC process is maintainer-initiated, so please don't open one unprompted). Maintainers will provide design guidance and review, and can point at the exact call sites and test layout once we get going.
Split out from #255. The CLI side of OIDC (sign-in, PKCE, keychain storage, Bearer tokens, per-agent API keys) has landed. This issue covers the remaining piece: letting a self-hosted open-source
cqserver verify access tokens issued by an external IdP (Keycloak, Okta, Entra ID, etc.), so an enterprise can run their own server against their own identity provider.Today, the server authenticates requests two ways (
server/backend/src/cq_server/api/deps.py):get_current_user— decodes a JWT signed by the server itself with a symmetric secret (CQ_JWT_SECRET, HS256).require_api_key— HMAC-compares a long-lived API key.Neither validates a token minted by an external IdP.
Proposed scope (minimal, configurable):
CQ_OIDC_ISSUER,CQ_OIDC_AUDIENCE, and optionalCQ_OIDC_JWKS_URL(default to{issuer}/.well-known/openid-configurationdiscovery).iss,aud,exp, and signature against the issuer's JWKS (asymmetric, RS256/ES256), with JWKS cached and refreshed onkidmiss.sub, oremail/preferred_username) onto the identity recorded ascreated_byon knowledge units.Out of scope for this issue: IdP federation, multi-issuer trust, rotation-policy enforcement, and fine-grained authorization/roles. These are larger pieces of work and would be tracked as separate issues if and when there's demand.
Before writing code: because this touches identity trust and token lifecycle, we'd like to agree the design up front. If you're interested in taking it on, comment here and we'll work with you to open an RFC (our RFC process is maintainer-initiated, so please don't open one unprompted). Maintainers will provide design guidance and review, and can point at the exact call sites and test layout once we get going.