fix(identity-webhook): map allowance rejects to 483/503 + publish 0.4.2#9
fix(identity-webhook): map allowance rejects to 483/503 + publish 0.4.2#9eliteprox wants to merge 13 commits into
Conversation
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.
…at/composite-app-token-exchange
📝 WalkthroughWalkthroughThe 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. ChangesIdentity webhook authorization
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
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
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
⛔ Files ignored due to path filters (1)
identity-webhook/package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (12)
.env.exampleREADME.mdidentity-webhook/balance-gate.d.tsidentity-webhook/balance-gate.mjsidentity-webhook/balance-gate.test.mjsidentity-webhook/legacy-env.test.mjsidentity-webhook/package.jsonidentity-webhook/protocol.d.tsidentity-webhook/protocol.mjsidentity-webhook/protocol.test.mjsidentity-webhook/verifiers.mjsidentity-webhook/verifiers.test.mjs
| 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, |
There was a problem hiding this comment.
🔒 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 explicitOIDC_TOKEN_EXCHANGE_BASE_URL(or an explicit opt-in flag) instead of implicitly reusingNEXTAUTH_URL, or at minimum log a warning when the fallback is used..env.example#L42-L49: add a comment notingOIDC_TOKEN_EXCHANGE_BASE_URLfalls back toNEXTAUTH_URLwhen unset.README.md#L160-L167: update theOIDC_AUDIENCErow to note it's optional (defaults to the JWT issuer) and update theOIDC_TOKEN_EXCHANGE_BASE_URLrow to mention theNEXTAUTH_URLfallback.
📝 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-L49README.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.
|
Closing; reopening as a stacked PR based on |
bd52332 to
5270feb
Compare
|



Summary
app_*_*exchange no longer collapses mint-gate HTTP 402 to webhook 401.authLivePayment— matchingcreateBalanceGate:402/trial_credits_exhausted→ webhook483insufficient_balancebilling_unavailable→ webhook503error_descriptionas webhookreason(go-livepeer returns that string to the gateway).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)v0.4.2to publish/generate-live-paymentreturns HTTP 483 (not 401) when allowance is exhausted with a composite Bearer