Skip to content

fix(api): enable PKCE for Unraid OIDC - #2061

Merged
Eli Bosley (elibosley) merged 5 commits into
mainfrom
codex/api-oidc-code-binding-pkce
Aug 12, 2026
Merged

fix(api): enable PKCE for Unraid OIDC#2061
Eli Bosley (elibosley) merged 5 commits into
mainfrom
codex/api-oidc-code-binding-pkce

Conversation

@elibosley

@elibosley Eli Bosley (elibosley) commented Aug 12, 2026

Copy link
Copy Markdown
Member

Summary

The API now generates and preserves an S256 PKCE verifier for the built-in Unraid.net OIDC flow so Account can bind code redemption to the initiating client transaction.

Why This Exists

The Account issuer can enforce S256 PKCE after the client rollout. Without the verifier, a party that obtains an authorization code cannot redeem it at the token endpoint.

Resolution

Generate a verifier per authorization request, send its challenge, carry the verifier through the existing signed transient state, and supply it to openid-client during code exchange. Custom providers remain unchanged unless their internal PKCE capability is enabled.

Reviewer Considerations

  • Unraid intentionally permits arbitrary self-hosted callback destinations; this PR does not add a browser-cookie protocol or redirect allowlist.
  • Account now binds the authorization code to the exact client and redirect URI, while this PR supplies the matching S256 proof.
  • The existing cache state read/delete sequence is not an atomic distributed one-use claim. That residual risk is explicitly accepted for this bounded patch and is tracked in CLD-868.

Behavior Changes

  • The built-in unraid.net provider opts into S256 PKCE by default.
  • The per-request verifier is stored in the signed transient state and used during token exchange.
  • Existing redirect URI and state validation continue to use the current API services.

Implementation Summary

  • Added the PKCE capability to provider configuration and discovery authorization paths.
  • Extended the existing OIDC state envelope and token exchange with the verifier.
  • Added coverage for custom and discovery authorization endpoints and valid RFC PKCE fixtures.

Verification

  • API OIDC focused suites: 47 tests passed after the shared-package build.
  • API typecheck: passed.
  • API lint: passed.
  • API Test, CodeQL, artifact builds, plugin build, and coverage checks: passed.
  • The dependency audit reports existing transitive advisories and remains advisory for this PR.

Risk

The accepted residual risk is that concurrent callback state redemption can race before cache deletion is observed. This PR does not claim strict distributed exactly-once state consumption. CLD-868 tracks the stronger atomic consume guarantee in the Account project.

Linear

Review Status

Limetech AI review was run with delegated security, architecture, checklist, type/modeling, tests, documentation, maintenance, and data-safety lenses. The atomic state-consumption limitation is documented, risk-accepted, and tracked in CLD-868. The final AI review marker records that disposition.

Summary by CodeRabbit

  • New Features

    • Added PKCE support for OpenID Connect sign-in flows.
    • Enabled PKCE by default for the built-in Unraid.net provider.
    • Added provider configuration to enable or disable PKCE.
    • Securely preserves the PKCE verifier throughout authorization and token exchange.
  • Bug Fixes

    • Improved validation of OIDC authorization requests and callback exchanges.
  • Tests

    • Added coverage for PKCE authorization, state handling, callback processing, and token exchange.

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 76fd451f-0be0-42bb-8f92-ff973170d1ac

📥 Commits

Reviewing files that changed from the base of the PR and between a147b7c and 454bad9.

📒 Files selected for processing (1)
  • .limetech/ai-review-markers/codex-api-oidc-code-binding-pkce-6db58e97e7b8.json

Walkthrough

The OIDC flow supports optional S256 PKCE. It generates and caches a verifier, adds the challenge to authorization requests, extracts the verifier during callbacks, and passes it to token exchange. The built-in Unraid.net provider enables PKCE by default. Tests cover discovery, custom endpoints, state, and token exchange.

Changes

OIDC PKCE flow

Layer / File(s) Summary
Provider PKCE configuration
api/src/unraid-api/graph/resolvers/sso/models/oidc-provider.model.ts, api/src/unraid-api/graph/resolvers/sso/core/oidc-config.service.ts, .limetech/ai-review-markers/...
OidcProvider exposes optional usePkce validation. The built-in provider enables PKCE by default. Provider upserts preserve this setting.
Secure state verifier storage
api/src/unraid-api/graph/resolvers/sso/session/*
Secure OIDC state stores and returns the optional codeVerifier. Tests validate state preservation and extraction.
Authorization and token exchange
api/src/unraid-api/graph/resolvers/sso/core/oidc.service.ts, api/src/unraid-api/graph/resolvers/sso/auth/oidc-token-exchange.service.ts, api/src/unraid-api/graph/resolvers/sso/core/oidc.service.test.ts, api/src/unraid-api/graph/resolvers/sso/auth/oidc-token-exchange.service.test.ts
Authorization requests include S256 PKCE parameters when enabled. Callback handling passes the verifier to token exchange. Tests cover discovery, custom endpoints, callbacks, and grant checks.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant OidcService
  participant OidcStateService
  participant OpenIDProvider
  participant OidcTokenExchangeService
  OidcService->>OidcStateService: Store codeVerifier in secure state
  OidcService->>OpenIDProvider: Send code_challenge with S256
  OpenIDProvider-->>OidcService: Return authorization code and state
  OidcService->>OidcStateService: Validate state and extract codeVerifier
  OidcService->>OidcTokenExchangeService: Exchange code with verifier
  OidcTokenExchangeService->>OpenIDProvider: Submit pkceCodeVerifier
Loading

Poem

I’m a rabbit guarding the state,
With a verifier cached at the gate.
S256 hops in line,
The callback stays fine,
And tokens arrive safely in fate.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes enabling PKCE for the Unraid OIDC provider, which is the main change.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/api-oidc-code-binding-pkce

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
api/src/unraid-api/graph/resolvers/sso/auth/oidc-token-exchange.service.test.ts (1)

206-224: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use precise types for the grant response and grant call.

Line 206 adds as any. Lines 219-220 add casts that can hide an incorrect grant call shape. Define a typed token response or typed test factory. Assert authorizationCodeGrant with URL and checks matchers instead of casting indexed mock-call values.

As per coding guidelines, “Never use the any type; prefer precise typing” and “Avoid type casting where possible; prefer establishing correct types at the source.”

🤖 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
`@api/src/unraid-api/graph/resolvers/sso/auth/oidc-token-exchange.service.test.ts`
around lines 206 - 224, Update the OIDC token exchange test around
exchangeCodeForTokens to replace the mockResolvedValue any cast with a precisely
typed token response or typed test factory, and avoid casting indexed
authorizationCodeGrant mock arguments. Assert the grant call using URL and
authorization-check matchers that validate the expected redirect URI, state, and
PKCE verifier without hiding an incorrect call shape.

Source: Coding guidelines

🤖 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.

Nitpick comments:
In
`@api/src/unraid-api/graph/resolvers/sso/auth/oidc-token-exchange.service.test.ts`:
- Around line 206-224: Update the OIDC token exchange test around
exchangeCodeForTokens to replace the mockResolvedValue any cast with a precisely
typed token response or typed test factory, and avoid casting indexed
authorizationCodeGrant mock arguments. Assert the grant call using URL and
authorization-check matchers that validate the expected redirect URI, state, and
PKCE verifier without hiding an incorrect call shape.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 5f5591a3-f055-4d6c-8873-b1f2169009aa

📥 Commits

Reviewing files that changed from the base of the PR and between 8f6134e and a147b7c.

📒 Files selected for processing (11)
  • .limetech/ai-review-markers/codex-api-oidc-code-binding-pkce-6db58e97e7b8.json
  • api/src/unraid-api/graph/resolvers/sso/auth/oidc-token-exchange.service.test.ts
  • api/src/unraid-api/graph/resolvers/sso/auth/oidc-token-exchange.service.ts
  • api/src/unraid-api/graph/resolvers/sso/core/oidc-config.service.ts
  • api/src/unraid-api/graph/resolvers/sso/core/oidc.service.test.ts
  • api/src/unraid-api/graph/resolvers/sso/core/oidc.service.ts
  • api/src/unraid-api/graph/resolvers/sso/models/oidc-provider.model.ts
  • api/src/unraid-api/graph/resolvers/sso/session/oidc-state-extractor.util.spec.ts
  • api/src/unraid-api/graph/resolvers/sso/session/oidc-state-extractor.util.ts
  • api/src/unraid-api/graph/resolvers/sso/session/oidc-state.service.spec.ts
  • api/src/unraid-api/graph/resolvers/sso/session/oidc-state.service.ts

@linear-code
linear-code Bot marked this pull request as ready for review August 12, 2026 17:43
@codecov

codecov Bot commented Aug 12, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.91837% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 53.14%. Comparing base (8f6134e) to head (454bad9).

Files with missing lines Patch % Lines
.../graph/resolvers/sso/models/oidc-provider.model.ts 0.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2061      +/-   ##
==========================================
+ Coverage   53.13%   53.14%   +0.01%     
==========================================
  Files        1041     1041              
  Lines       72425    72462      +37     
  Branches     8354     8360       +6     
==========================================
+ Hits        38482    38513      +31     
- Misses      33816    33822       +6     
  Partials      127      127              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a147b7c0d7

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "Codex (@codex) review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "Codex (@codex) address that feedback".

id_token: 'test-id-token',
};

vi.mocked(client.authorizationCodeGrant).mockResolvedValue(mockTokens as any);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Replace the untyped token mock cast

In this new PKCE test, mockTokens as any removes type checking from the mocked token response, so the test can keep passing even if the fixture stops satisfying client.TokenEndpointResponse. Please type the fixture/mock instead of casting away checking to match the repo rule against any and avoidable casts.

Useful? React with 👍 / 👎.

@github-actions

Copy link
Copy Markdown
Contributor

This plugin has been deployed to Cloudflare R2 and is available for testing.
Download it at this URL:

https://preview.dl.unraid.net/unraid-api/tag/PR2061/dynamix.unraid.net.plg

@elibosley
Eli Bosley (elibosley) merged commit 5f87782 into main Aug 12, 2026
13 of 14 checks passed
@elibosley
Eli Bosley (elibosley) deleted the codex/api-oidc-code-binding-pkce branch August 12, 2026 18:56
@github-actions

Copy link
Copy Markdown
Contributor

🔄 PR Merged - Plugin Redirected to Staging

This PR has been merged and the preview plugin has been updated to redirect to the staging version.

For users testing this PR:

  • Your plugin will automatically update to the staging version on the next update check
  • The staging version includes all merged changes from this PR
  • No manual intervention required

Staging URL:

https://preview.dl.unraid.net/unraid-api/dynamix.unraid.net.plg

Thank you for testing! 🚀

Eli Bosley (elibosley) pushed a commit that referenced this pull request Aug 12, 2026
🤖 I have created a release *beep* *boop*
---


## [4.37.1](v4.37.0...v4.37.1)
(2026-08-12)


### Bug Fixes

* **api:** enable PKCE for Unraid OIDC
([#2061](#2061))
([5f87782](5f87782))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
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