Skip to content

fix(identity-webhook): map allowance rejects to 483/503 + publish 0.4.2#9

Closed
eliteprox wants to merge 13 commits into
mainfrom
feat/balance-gate
Closed

fix(identity-webhook): map allowance rejects to 483/503 + publish 0.4.2#9
eliteprox wants to merge 13 commits into
mainfrom
feat/balance-gate

Conversation

@eliteprox

@eliteprox eliteprox commented Jul 14, 2026

Copy link
Copy Markdown

Summary

  • Composite app_*_* exchange no longer collapses mint-gate HTTP 402 to webhook 401.
  • Remaps allowance rejects onto the identity-hook statuses go-livepeer already passthroughs from authLivePayment — matching createBalanceGate:
    • mint 402 / trial_credits_exhausted → webhook 483 insufficient_balance
    • billing_unavailable → webhook 503
  • Preserves upstream error_description as webhook reason (go-livepeer returns that string to the gateway).
  • Bumps package to 0.4.2.

go-livepeer itself only defines signer ops codes 480/481/482; webhook rejects are opaque status+reason passthrough (remote_signer.go).

Test plan

  • cd identity-webhook && npm test (83 passing)
  • Merge → tag v0.4.2 to publish
  • Gateway /generate-live-payment returns HTTP 483 (not 401) when allowance is exhausted with a composite Bearer

eliteprox added 13 commits July 10, 2026 20:30
Replace the incorrect default {issuer}/.well-known/jwks.json with
issuer-relative OIDC discovery (openid-configuration → jwks_uri).
Validate discovery issuer, wrap JWKS fetch errors with the URL, and
keep OIDC_JWKS_URI as an explicit override. Unit tests cover discovery
and leave api_key mode unchanged.
Accept Bearer app_<24hex>_<secret> when OIDC_TOKEN_EXCHANGE_BASE_URL is set:
RFC 8693 exchange at the app-scoped token endpoint, then jwtVerify the minted
access token (same JWKS discovery path as livepeer#62). Secret segment is opaque
(operator prefixes allowed); reject cs_ / _cs_ client-secret shapes. Harden
cache keys (salted HKDF) and log sanitization. Document exchange env vars.
Add createBalanceGate / parseUsdMicros and an optional checkBalance hook on
handleAuthorize so consumers can enforce live credit at sign time (483
insufficient_balance, optional expiry cap for mid-stream reauth).
Publish BalanceCheck / createBalanceGate so pymthouse can import
@pymthouse/clearinghouse-identity-webhook/balance-gate.
…Y_ISSUER

Allow either IDENTITY_ISSUER or OIDC_ISSUER, default OIDC_AUDIENCE to the
JWT issuer, and derive OIDC_TOKEN_EXCHANGE_BASE_URL from NEXTAUTH_URL.
Clear the in-flight discovery promise on failure so later verifies can
retry, and wrap createLocalJWKSet errors with the JWKS URL.
Move the OIDC discovery docs off normalizeIssuer and align the non-ok
HTTP error message with response.ok (2xx).
Trim issuers, reject blank jwtIssuer, require jwks to be a jose key
function, and align JWKS non-ok HTTP errors with response.ok.
Wrap createRemoteJWKSet URL construction so Invalid URL failures retain
the offending jwks_uri / OIDC_JWKS_URI in the verify warn log.
@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The webhook package adds configurable balance checks, new billing-related rejection codes, updated OIDC discovery and token exchange behavior, composite API key parsing, package exports, tests, and environment documentation.

Changes

Identity webhook authorization

Layer / File(s) Summary
Balance-check authorization contract
identity-webhook/protocol.*, identity-webhook/protocol.test.mjs
Adds balance-check types and configuration, payment and trial-credit error constants, and expiry/rejection handling in handleAuthorize.
Balance gate implementation and publication
identity-webhook/balance-gate.*, identity-webhook/package.json, .env.example
Adds balance parsing and enforcement with configurable thresholds, expiry, and failure behavior; publishes the module and documents related configuration.
OIDC discovery and verifier configuration
identity-webhook/verifiers.mjs, identity-webhook/verifiers.test.mjs, README.md
Normalizes and validates OIDC discovery, improves JWKS errors and retries, supports issuer aliases and token-exchange URL defaults, and updates OIDC documentation.
Composite API key exchange and error mapping
identity-webhook/verifiers.mjs, identity-webhook/verifiers.test.mjs, identity-webhook/legacy-env.test.mjs
Changes composite API key parsing to app_<24hex>_<secret>, maps exchange failures to billing/payment errors, and updates exchange and authorization coverage.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Request
  participant handleAuthorize
  participant createBalanceGate
  participant BalanceResolver
  Request->>handleAuthorize: authorize with verified identity
  handleAuthorize->>createBalanceGate: check balance and expiry
  createBalanceGate->>BalanceResolver: getBalanceUsdMicros(identity, context)
  BalanceResolver-->>createBalanceGate: balance result
  createBalanceGate-->>handleAuthorize: allow, reject, or shortened expiry
  handleAuthorize-->>Request: authorization response
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately highlights the main behavior change and version bump in this PR.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/balance-gate

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@eliteprox eliteprox changed the title fix(identity-webhook): propagate exchange 402 + publish 0.4.2 fix(identity-webhook): map allowance rejects to 483/503 + publish 0.4.2 Jul 14, 2026

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@identity-webhook/verifiers.mjs`:
- Around line 685-693: Update createEndUserVerifierFromEnv in
identity-webhook/verifiers.mjs:685-693 to require an explicit
OIDC_TOKEN_EXCHANGE_BASE_URL or an explicit opt-in before enabling token
exchange, rather than implicitly using NEXTAUTH_URL; preserve the jwtAudience
fallback to jwtIssuer and document it. In .env.example:42-49, explain the
token-exchange configuration and fallback behavior if retained. In
README.md:160-167, mark OIDC_AUDIENCE as optional with the JWT issuer default
and document the OIDC_TOKEN_EXCHANGE_BASE_URL behavior and any opt-in
requirement.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d63b7893-34c9-4a5b-b4ae-62546a610986

📥 Commits

Reviewing files that changed from the base of the PR and between a036e9d and 53896c5.

⛔ Files ignored due to path filters (1)
  • identity-webhook/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (12)
  • .env.example
  • README.md
  • identity-webhook/balance-gate.d.ts
  • identity-webhook/balance-gate.mjs
  • identity-webhook/balance-gate.test.mjs
  • identity-webhook/legacy-env.test.mjs
  • identity-webhook/package.json
  • identity-webhook/protocol.d.ts
  • identity-webhook/protocol.mjs
  • identity-webhook/protocol.test.mjs
  • identity-webhook/verifiers.mjs
  • identity-webhook/verifiers.test.mjs

Comment on lines +685 to +693
const jwtAudience = envTrim(env, "OIDC_AUDIENCE") || jwtIssuer;
const tokenExchangeBaseUrl =
envTrim(env, "OIDC_TOKEN_EXCHANGE_BASE_URL") ||
envTrim(env, "NEXTAUTH_URL") ||
undefined;

return createOidcVerifier({
jwtIssuer: envTrim(env, "OIDC_ISSUER"),
jwtAudience: envTrim(env, "OIDC_AUDIENCE"),
jwtIssuer,
jwtAudience,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Undocumented NEXTAUTH_URL/audience defaults can silently enable composite key exchange. createEndUserVerifierFromEnv now defaults jwtAudience to jwtIssuer and tokenExchangeBaseUrl to NEXTAUTH_URL when the dedicated OIDC vars are unset — neither .env.example nor README.md were updated to reflect this. Since NEXTAUTH_URL is commonly set for unrelated (Next.js/Auth.js) reasons, an operator who never configured OIDC_TOKEN_EXCHANGE_BASE_URL can unknowingly enable the composite app_<24hex>_<secret> exchange path, sending caller-supplied "secrets" to ${NEXTAUTH_URL}/api/v1/apps/{clientId}/oidc/token.

  • identity-webhook/verifiers.mjs#L685-L693: this is the root cause — consider requiring an explicit OIDC_TOKEN_EXCHANGE_BASE_URL (or an explicit opt-in flag) instead of implicitly reusing NEXTAUTH_URL, or at minimum log a warning when the fallback is used.
  • .env.example#L42-L49: add a comment noting OIDC_TOKEN_EXCHANGE_BASE_URL falls back to NEXTAUTH_URL when unset.
  • README.md#L160-L167: update the OIDC_AUDIENCE row to note it's optional (defaults to the JWT issuer) and update the OIDC_TOKEN_EXCHANGE_BASE_URL row to mention the NEXTAUTH_URL fallback.
📝 Proposed doc fixes
--- .env.example
-# OIDC_TOKEN_EXCHANGE_BASE_URL=        # optional; enables app_<24hex>_<secret> composite key exchange
+# OIDC_TOKEN_EXCHANGE_BASE_URL=        # optional; enables app_<24hex>_<secret> composite key exchange.
+#                                      # Falls back to NEXTAUTH_URL when unset — set explicitly (or leave
+#                                      # NEXTAUTH_URL unset) to avoid unintentionally enabling exchange.
--- README.md
-| `OIDC_AUDIENCE` | `oidc` | Expected JWT audience |
+| `OIDC_AUDIENCE` | `oidc`, optional | Expected JWT audience; defaults to `OIDC_ISSUER`/`IDENTITY_ISSUER` when unset |
-| `OIDC_TOKEN_EXCHANGE_BASE_URL` | `oidc`, optional | Enables composite `Bearer app_<24hex>_<secret>`: RFC 8693 exchange at `/api/v1/apps/{clientId}/oidc/token`, then JWT verify |
+| `OIDC_TOKEN_EXCHANGE_BASE_URL` | `oidc`, optional | Enables composite `Bearer app_<24hex>_<secret>`: RFC 8693 exchange at `/api/v1/apps/{clientId}/oidc/token`, then JWT verify. Falls back to `NEXTAUTH_URL` when unset |
📍 Affects 3 files
  • identity-webhook/verifiers.mjs#L685-L693 (this comment)
  • .env.example#L42-L49
  • README.md#L160-L167
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@identity-webhook/verifiers.mjs` around lines 685 - 693, Update
createEndUserVerifierFromEnv in identity-webhook/verifiers.mjs:685-693 to
require an explicit OIDC_TOKEN_EXCHANGE_BASE_URL or an explicit opt-in before
enabling token exchange, rather than implicitly using NEXTAUTH_URL; preserve the
jwtAudience fallback to jwtIssuer and document it. In .env.example:42-49,
explain the token-exchange configuration and fallback behavior if retained. In
README.md:160-167, mark OIDC_AUDIENCE as optional with the JWT issuer default
and document the OIDC_TOKEN_EXCHANGE_BASE_URL behavior and any opt-in
requirement.

@eliteprox

Copy link
Copy Markdown
Author

Closing; reopening as a stacked PR based on feat/balance-gate.

@eliteprox
eliteprox force-pushed the feat/balance-gate branch from bd52332 to 5270feb Compare July 14, 2026 23:54
@eliteprox eliteprox closed this Jul 14, 2026
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant