Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CONTEXT.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,7 @@ Per-attempt records of token usage and cost attribution, linked to the client re

**SSO identity binding**:
An administrator-approved association between a company SSO issuer and subject identity and an OpenGranter principal.

**SSO management access token**:
A company SSO token intended to identify a human caller of the OpenGranter management API before policy evaluation.
_Avoid_: Proxy API token
13 changes: 13 additions & 0 deletions contracts/sso-access-tokens.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# RFC 9068 SSO management access-token verifier

Plan: [488-sso-token-management](../docs/plans/488-sso-token-management.md).

createRfc9068SsoAccessTokenVerifier({ issuer, audience, jwks, now }) returns verifyAccessToken(token). Administrator configuration is captured once and projected into a private local public-key snapshot; request data cannot select trust configuration. Configured issuer is exact HTTPS without userinfo/query/fragment/whitespace, 1–2048 UTF-16 units. The API audience is an exact opaque 1–256-unit identifier. jwks has 1–16 own indexed public RSA keys with unique own kid values; keys have own kty/n/e/kid and only optional own alg/use/key_ops. Reject private/unknown own key fields, noncanonical base64url integers, unsupported signing metadata and RSA moduli outside 2048–4096 bits. Missing metadata projects to RS256/sig/verify. No key/header URL fetch, discovery or request-provided key import occurs. Invalid config/getters throw InvalidSsoAccessTokenConfiguration / Invalid SSO access token configuration without raw data or cause.

Tokens are bounded nonempty opaque strings up to 16384 UTF-16 units without NUL/ill-formed Unicode. Real jose signature verification permits RS256 only and local matching public keys; ambiguous/missing key selection rejects rather than trying every key. RFC media-type semantics accept at+jwt case-insensitively with optional application/ prefix, rejecting ID/generic JWT types. Require iss/sub/aud/exp/iat/jti/client_id plus the confirmed local auth_time restriction. Exact configured issuer and audience membership apply; audience arrays have at most 64 nonempty bounded identifiers. Subject/client_id/jti are 1–256-unit well-formed non-NUL strings. Extra claims/header key URLs confer no identity or policy authority.

NumericDates are finite nonnegative numbers; fractional dates are supported. Require exp > iat, exp-iat <= 3600 seconds and auth_time <= iat. Optional nbf must be valid and precede exp. With one captured current millisecond clock (converted to whole epoch seconds by jose), jose applies 60-second tolerance to expiry, future iat/nbf and a maximum 3600-second age since iat. Duration bound receives no extra skew. auth_time describes original end-user login and may precede refreshed issuance; no maximum login age is imposed. Clock must be a nonnegative safe integer representable as a Date.

Valid verification returns only a frozen { issuer, subject }. Invalid/malformed/unsupported/expired tokens return undefined without exposing raw token, claims, library errors or causes. Clock/unexpected verifier failures throw SsoAccessTokenVerificationUnavailable / SSO access token verification unavailable. Local key snapshots do not refresh: rebuild a verifier to add/remove keys and overlap registered keys for manual rotation. No introspection, jti replay cache or access-token revocation mechanism is introduced.

The contributor selected RFC 9068, local RS256 public keys, one-hour limits/60-second tolerance and required auth_time on 2026-10-11. RFC auth_time is optional, not generic human-grant proof. Administrators must trust an issuer that emits this claim only for actual end-user authentication; tokens without it reject under this local profile. Existing active-human binding and current IAM remain additional requirements. This module neither grants management policy nor exposes a public HTTP/authentication-audit contract. See [RFC 9068](https://www.rfc-editor.org/rfc/rfc9068.html#section-2.2) and [JWT confusion guidance](https://www.rfc-editor.org/rfc/rfc8725.html#section-3.12).
6 changes: 3 additions & 3 deletions contracts/sso-management-foundation.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# SSO management foundation: planning status

SSO JWT verification and public management authentication remain pending implementation. The binding read foundation is delivered under #486, and lifetime caps are enforced at the existing internal service under the [lifetime contract](proxy-token-lifetimes.md). This is not an implemented public HTTP contract:
The internal RFC 9068 JWT verifier and token-management composition are delivered under #488; public management HTTP authentication remains pending. The binding read foundation is delivered under #486, and lifetime caps are enforced at the existing internal service under the [lifetime contract](proxy-token-lifetimes.md). This is not an implemented public HTTP contract:

- Company SSO uses OIDC.
- The first management API authenticates SSO human users only. Service accounts continue using the LLM proxy; service management credentials require a later decision.
- Newly issued proxy tokens have a mandatory expiry and maximum lifetime of 30 days for human owners or 90 days for service owners.
- Existing iam:Manage policy evaluation on the target principal and required metadata decision audit remain in force. SSO authentication supplies identity, not an authorization bypass.

Confirmed on 2026-10-11: administrator-pre-registered issuer/subject bindings and API-specific SSO JWT access tokens; no automatic first-login creation. The [binding read foundation](sso-identity-bindings.md) is implemented under #486. HTTP paths, authentication profiles, migration handling for existing credentials, and implementation error contracts remain to be specified before their implementation. Recommendations are not requirements until confirmed.
Confirmed on 2026-10-11: administrator-pre-registered issuer/subject bindings, API-specific SSO JWT access tokens and the RFC 9068 access-token profile; no automatic first-login creation. The [binding read foundation](sso-identity-bindings.md) is implemented under #486 and [internal token-management composition](sso-token-management.md) under #488. The contributor also confirmed registered RS256 public keys, maximum one-hour lifetime/age with 60-second clock tolerance, and required auth_time. Administrators must trust its end-user semantics. HTTP paths/errors/audit and credential migration handling remain separate. Recommendations are not requirements until confirmed.

The current internal facade, opaque credential primitives, and proxy HTTP endpoints remain as documented in [token management](token-management.md). JWT verification and the public management API remain pending; the binding read foundation and internal lifetime enforcement are delivered separately.
The current internal facade, opaque credential primitives, and proxy HTTP endpoints remain as documented in [token management](token-management.md). The public management HTTP API remains pending; the binding read foundation and internal lifetime enforcement are delivered separately.
15 changes: 15 additions & 0 deletions contracts/sso-token-management.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Internal SSO token-management service

Plan: [488-sso-token-management](../docs/plans/488-sso-token-management.md).

`createPostgresSsoTokenManagementService({ client, now, verifyAccessToken })` exposes `issue({ accessToken, requestId, principalId, expiresAt })` and `revoke({ accessToken, requestId, credentialId })` to trusted internal application code. It returns existing one-time issued credentials or the existing revocation result. It exposes no HTTP route. createPostgresRfc9068SsoTokenManagementService wires the real [RFC 9068 verifier](sso-access-tokens.md) from administrator issuer/audience/public-key configuration and the same clock. The configured factory captures its five own required settings once, ignores extra authority and reports invalid/missing/getter-failed configuration through the fixed InvalidSsoAccessTokenConfiguration error.

The trusted access-token verifier returns an already verified `{ issuer, subject }` or `undefined`. Only verified identities reach the [binding reader](sso-identity-bindings.md); exact current active human bindings derive the actor ID. The configured verifier enforces the selected RFC 9068 profile and required auth_time restriction; decoding a JWT or accepting caller-supplied claims is not verification. Injected verifiers are trusted internal deployment code, not request data. Proxy tokens and ID tokens are not management access tokens. The registered issuer must use auth_time only for actual end-user authentication; this local restriction is not universal human-grant proof.

Capture all own required operation fields once before any verifier/SQL await. Extra actor IDs, kind/active state, policy statements/versions, owner and verification claims are ignored. Access tokens are opaque strings of 1–16384 UTF-16 units; metadata IDs are 1–256. Reject NUL/ill-formed Unicode, preserve exact spelling and require a nonnegative safe-integer expiry. Invalid inputs throw `InvalidSsoTokenManagementInput` / `Invalid SSO token management input` before verification or SQL.

Verifier rejection and missing/inactive/service/unbound identity throw `SsoManagementUnauthenticated` / `SSO management unauthenticated`. Verifier throws, malformed verified identity and binding failures throw `SsoManagementAuthenticationUnavailable` / `SSO management authentication unavailable`. Both are fixed errors without raw tokens, claims, driver messages or causes. An error thrown by an injected verifier is always a dependency failure, even if it has a domain-error name. Failed authentication reads no actor policies, writes no token-management decision and performs no credential or lifecycle mutation. Public authentication auditing is still a separate contract.

After authentication, the [existing management service](token-management.md) reloads current actor policies and enforces `iam:Manage` on the stored credential owner or requested issuance principal. Implicit/explicit Deny, required authorization decision audit, owner-kind lifetime caps and atomic lifecycle writes remain unchanged. Authentication supplies no permissions, extra audit kinds, secrets, inference or usage calls. Neither access tokens nor issuer/subject claims are included in management decisions/lifecycle events; only existing nonsecret actor/target/request/credential/policy identifiers appear. Issued raw proxy tokens return once under the existing contract.

Each operation re-verifies its access token and reloads binding/kind/active and policy state; no authentication cache. Request mutation during verification/SQL cannot change the captured operation. Changes between calls take effect. Binding and policy reads are separate and state changes after a read are not transactionally revalidated. Audited administrator provisioning, public API paths/errors/audit, automatic JWKS rotation/introspection/replay controls and full release gates remain pending.
2 changes: 2 additions & 0 deletions contracts/token-management.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

`test/postgres-token-management-service.test.ts` covers persisted role grants, direct Deny precedence, next-operation policy/attachment/active-state changes, missing actors, ignored forged fields, immutable owner scoping, malformed/unavailable snapshots, required decision-store failure, and invalid inputs before SQL.

The [internal SSO composition](sso-token-management.md) derives this trusted actor ID from an injected verified access-token identity and a current pre-registered human binding. It retains these authorization/mutation controls and has a configured RFC 9068 verifier; public HTTP authentication remains pending.

## Operation snapshots

Capture validated service request fields before actor resolution. The coordinator captures operation fields and projects immutable actor/policy context before owner lookup or audit; decision events and evaluated policy versions are frozen. Caller updates during asynchronous work cannot change this operation's target, expiry, credential, or attribution. Subsequent calls inspect current caller values and reload persisted policies. See [snapshot contract](token-management-snapshots.md).
Loading
Loading