Skip to content

fix(auth): bind JWT trust by issuer - #19

Merged
rschlaefli merged 5 commits into
mainfrom
rs/codeapi-issuer-trust
Sep 1, 2026
Merged

fix(auth): bind JWT trust by issuer#19
rschlaefli merged 5 commits into
mainfrom
rs/codeapi-issuer-trust

Conversation

@rschlaefli

@rschlaefli rschlaefli commented Aug 31, 2026

Copy link
Copy Markdown
Member

What This Fixes

This PR adds one reusable issuer-scoped JWT trust boundary:

  1. Selects verification policy by issuer, then binds signature key, algorithm,
    issuer, audience, and principal source before accepting a principal.
  2. Keeps the existing single-issuer LibreChat configuration when no modern
    trust table is set.
  3. Supports external issuers through a bounded external:<slug> namespace
    without embedding a consumer-specific source.
  4. Isolates external storage/session tenant namespaces by that validated source.

This is an independent draft package extracted from PR #18. It has no source
dependency on the logging or public-contract packages.

How It Works

  • CODEAPI_JWT_TRUST_ENTRIES_JSON defines modern issuer entries with accepted
    audiences, key IDs, algorithms, and principal sources.
  • An unverified iss claim only selects a trust entry. Its assigned key and all
    configured constraints are enforced before claims become a principal.
  • Loaded key IDs are globally unique, every key belongs to exactly one entry,
    and each external source belongs to exactly one entry.
  • External sources are lowercase external:<slug> values. Reserved internal
    values cannot be configured through that namespace.
  • External tenant IDs become <principal-source>:<tenant-id>. Internal tenant
    IDs remain unchanged.

Important Details

  • Modern and legacy policy inputs are mutually exclusive. Malformed, duplicate,
    orphaned, cross-entry, or algorithm-incompatible configuration fails startup.
  • The branch adds no dependency, remote key provider, secret value, deployment,
    database schema, or rate-limit change.
  • docs/fork/patches.md records the eighth active UZH fork behavior and its
    replay/drop condition.
  • Rollback is an ordinary source revert. No deployment or data migration is
    included.

Branch Coverage

  • Base: main@83c4f7b
  • Head: 40cde7d
  • Reviewed: 83c4f7b..40cde7d, 5 commits.
  • Changed: 5 files, +459/-43 substantive lines; no lockfile, generated output,
    or project-plan delta.
  • Covered: verifier/configuration, focused auth tests, Docker/Helm configuration
    documentation, fork ledger, simplifier cleanup, and review corrections.

Review Focus

  • Confirm unverified issuer selection cannot widen key, algorithm, audience, or
    principal-source trust.
  • Confirm modern configuration fails closed while legacy LibreChat behavior
    remains equivalent.
  • Confirm external:<slug> validation and tenant namespace derivation prevent
    cross-issuer storage/session collisions.
  • Confirm the fork ledger accurately separates this patch from PR fix(codeapi): bind issuer trust and sanitize public boundaries #18.

Verification

Current head:

  • bun test src/auth/librechat-jwt.test.ts from service/ -> 21 pass, 0 fail.
  • bun run test from service/ -> 559 pass, 0 fail.
  • bun run build from service/ -> exit 0.
  • git diff --check origin/main...HEAD -> pass.
  • Simplifier and authentication/security slice review findings -> corrected.
  • Exact-head integrated final review -> approved after scoped re-check.
  • CI run 33420742642
    -> all five required jobs passed at 40cde7d.

Failed/Warning:

  • The service build retains existing Rollup export/circular-dependency warnings
    and two pre-existing TS2352 warnings outside this package.

Not run:

  • No production issuer, key, secret-store, deployment, cluster, or live
    authentication proof was used. Those remain separate rollout actions.

Security / Privacy

  • Review: dedicated authentication/security slice review and integrated final
    review.
  • Result: no unresolved findings at 40cde7d.
  • Sensitive data: configuration and tests use synthetic names and keys. No
    credentials, personal data, production token, or execution payload is
    included.

Blocking Before Merge

  • All five exact-head draft-PR CI jobs passed.
  • Human review and explicit merge approval remain required.

Follow-Up After Merge

  • Configure approved issuer trust through the secret store in a separate
    deployment change.
  • Update the Klicker W2 source gate only after every accepted replacement
    package is present on an exact UZH main SHA.

Local Session Artifacts

Machine-local pointers for a session resuming this branch, not review evidence.

  • Machine: Rolands-Mac-Studio.local
  • Worktree: trees/codeapi-trust-contract-logging in repository
    code-interpreter
  • Plan/progress:
    ~/Git/klicker/klicker-uzh/trees/rs-codeapi-upstream-simplification/project/2026-08-31-codeapi-source-simplification-plan.md

@rschlaefli
rschlaefli marked this pull request as ready for review September 1, 2026 06:17
Copilot AI lite review requested due to automatic review settings September 1, 2026 06:17
@rschlaefli
rschlaefli merged commit a12ce00 into main Sep 1, 2026
5 checks passed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The external principal-source validation does not currently reserve internal principal-source names in the external:<slug> namespace, which conflicts with the PR’s stated constraint and should be enforced before merge.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR introduces issuer-scoped JWT trust configuration for the librechat-jwt auth provider, so an unverified iss claim can only select a predefined verification policy (keys, algorithms, audiences, and principal sources) before any principal is accepted, while preserving the legacy single-issuer LibreChat behavior when the modern trust table is not configured.

Changes:

  • Add CODEAPI_JWT_TRUST_ENTRIES_JSON support with strict parsing/validation and per-issuer binding of kid, alg, audience, and principal_source.
  • Expand auth tests to cover modern multi-issuer mode, config failure cases, and cache reload behavior.
  • Document the new configuration in Helm/Docker Compose and record the fork patch behavior.
File summaries
File Description
service/src/auth/librechat-jwt.ts Implements issuer-keyed trust entries, key ID uniqueness checks, and issuer-bound verification/claim validation.
service/src/auth/librechat-jwt.test.ts Adds focused tests for modern trust-table behavior, rejection cases, and reload semantics.
helm/codeapi/README.md Documents how to configure CODEAPI_JWT_TRUST_ENTRIES_JSON and issuer-scoped constraints.
docs/fork/patches.md Records the new fork behavior and its owned/shared paths and drop criteria.
docker-compose.yaml Exposes CODEAPI_JWT_TRUST_ENTRIES_JSON for local/container configuration.
Review details
  • Files reviewed: 5/5 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

'openid_reuse',
]);
const EXTERNAL_PRINCIPAL_SOURCE = /^external:([a-z0-9](?:[a-z0-9._-]{0,62}[a-z0-9])?)$/;
const RESERVED_EXTERNAL_SOURCE_SLUGS = new Set(['synthetic_test', 'none', 'api_key']);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants