Skip to content

fix(oidc): trust Fastify proxy metadata#1982

Merged
elibosley merged 5 commits intomainfrom
codex/fix-oidc-proxy-redirect-uri
Apr 2, 2026
Merged

fix(oidc): trust Fastify proxy metadata#1982
elibosley merged 5 commits intomainfrom
codex/fix-oidc-proxy-redirect-uri

Conversation

@elibosley
Copy link
Copy Markdown
Member

@elibosley elibosley commented Mar 31, 2026

Summary

  • trust local proxy metadata through Fastify while keeping the OIDC authorize flow on one shared request-origin derivation path
  • tighten the request-origin contract so downstream OIDC code always receives a defined host and no longer re-derives origin data
  • harden the new regression coverage by relaxing brittle async exception assertions and making the authorize integration reply mock pass strict type-checking

Problem

A valid callback like https://nas.domain.com/graphql/api/auth/oidc/callback could fail behind the built-in proxy path even though it was allowed in Management Access. The authorize flow had duplicated origin derivation, one layer previously relied on raw forwarded headers, and the follow-up regression coverage still had a few reviewable rough edges around proxy trust clarity and test contracts.

Fix

Use Fastify's explicit loopback trust proxy alias, centralize OIDC request-origin extraction, and pass only normalized protocol/host information through the authorize flow. The request-origin utilities now guarantee a defined host, and the OIDC tests assert rejection behavior and reply interactions without coupling to exception classes or unsafe mock casts.

Testing

  • pnpm --filter ./api type-check
  • pnpm --filter ./api exec vitest run src/unraid-api/main.test.ts src/unraid-api/graph/resolvers/sso/client/oidc-redirect-uri.service.test.ts src/unraid-api/graph/resolvers/sso/utils/oidc-request-origin.util.test.ts src/unraid-api/graph/resolvers/sso/utils/oidc-request-handler.util.spec.ts src/unraid-api/rest/rest.controller.oidc.integration.test.ts
  • pnpm --filter ./api exec vitest run src/unraid-api/main.test.ts src/unraid-api/graph/resolvers/sso/utils/oidc-request-origin.util.test.ts src/unraid-api/graph/resolvers/sso/client/oidc-redirect-uri.service.test.ts src/unraid-api/graph/resolvers/sso/utils/oidc-request-handler.util.spec.ts src/unraid-api/graph/resolvers/sso/core/oidc.service.test.ts src/unraid-api/graph/resolvers/sso/core/oidc.service.integration.test.ts src/unraid-api/rest/rest.controller.test.ts src/unraid-api/rest/rest.controller.oidc.integration.test.ts

Deployment Note

  • The built-in webgui mount proxies /graphql to the API over unix:/var/run/unraid-api.sock and forwards Host, so these changes should not disrupt existing users on the standard nginx/socket path.
  • If a separate deployment relies on trusted X-Forwarded-* over a non-loopback TCP proxy hop, trustProxy may need to be widened to that explicit trusted network instead of loopback.

Work Intent

  • Reference: [UNRD] from the reported issue context

Summary by CodeRabbit

  • New Features & Improvements

    • Centralized and improved derivation of request origin (protocol/host), with better handling of proxied/forwarded values and trusted request info.
    • Fastify proxy trust tightened to loopback for more accurate client/proxy behavior.
  • Tests

    • Added and updated unit/integration tests for OIDC/SSO flows: redirect-URI validation, authorization URL building, request-origin utilities, and proxied-request scenarios.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 31, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Centralizes request-origin extraction into new utilities, updates OIDC flows to consume precomputed origin info (protocol/host/fullUrl/baseUrl), refactors handler/service/controller interactions and redirect-URI validation to use extracted origin, sets Fastify trustProxy to "loopback", and updates tests accordingly.

Changes

Cohort / File(s) Summary
Request-origin utilities
api/src/unraid-api/graph/resolvers/sso/utils/oidc-request-origin.util.ts, api/src/unraid-api/graph/resolvers/sso/utils/oidc-request-origin.util.test.ts
Add RequestOriginInfo/RequestInfo types and extractRequestOriginInfo/extractRequestInfo helpers; tests cover precedence (req.protocol/req.host) and correct fullUrl/baseUrl construction.
Request handler delegation
api/src/unraid-api/graph/resolvers/sso/utils/oidc-request-handler.util.ts, api/src/unraid-api/graph/resolvers/sso/utils/oidc-request-handler.util.spec.ts
Remove inline forwarded-header parsing; delegate origin extraction to new helpers; handler now passes requestOriginInfo/RequestInfo (protocol/host/fullUrl/baseUrl) to OIDC flows; tests updated to expect request-derived values.
Redirect URI service signature
api/src/unraid-api/graph/resolvers/sso/client/oidc-redirect-uri.service.ts, api/src/unraid-api/graph/resolvers/sso/client/oidc-redirect-uri.service.test.ts
Change getRedirectUri to accept RequestOriginInfo instead of raw headers; remove header-parsing helper; tests updated to pass explicit origin info, adjust validation expectations, and simplify header-array/header-precedence cases.
OIDC core service params
api/src/unraid-api/graph/resolvers/sso/core/oidc.service.ts, api/src/unraid-api/graph/resolvers/sso/core/oidc.service.test.ts, api/src/unraid-api/graph/resolvers/sso/core/oidc.service.integration.test.ts
Replace requestHeaders with requestOriginInfo in GetAuthorizationUrlParams and call sites; update tests to assert protocol/host forwarded to redirect service.
Controller integration & tests
api/src/unraid-api/rest/rest.controller.ts, api/src/unraid-api/rest/rest.controller.test.ts, api/src/unraid-api/rest/rest.controller.oidc.integration.test.ts
oidcAuthorize now uses OidcRequestHandler.extractRequestInfo(req)-derived origin for redirect validation and passes origin info to services; test helpers accept optional protocol/host overrides and integration tests simulate proxied requests asserting 302 and correct redirect_uri/state.
Handler/service adjustments
api/src/unraid-api/rest/rest.controller.ts
Redirect validation updated to pull protocol/host from requestInfo returned by extractRequestInfo (call site change only).
Bootstrap/trust-proxy
api/src/unraid-api/main.ts, api/src/unraid-api/main.test.ts
Fastify adapter now instantiated with new FastifyAdapter({ trustProxy: 'loopback' }); added/updated test verifying adapter options during bootstrap.
Tests & integrations (misc)
api/src/unraid-api/graph/resolvers/sso/.../*.test.ts, api/src/unraid-api/rest/.../*.test.ts, api/src/unraid-api/main.test.ts
Various tests updated to use requestOriginInfo/RequestInfo shapes, prefer request-derived protocol/host, add cases for proxy header arrays and port-preserving behavior, and adjust expectations to new argument shapes.
New integration
api/src/unraid-api/rest/rest.controller.oidc.integration.test.ts
Add end-to-end-style integration test for RestController OIDC authorize flow asserting 302 and redirect parameters when request includes proxied headers and trusted request origin fields.

Sequence Diagram(s)

sequenceDiagram
  participant Client as Client
  participant RestController as RestController
  participant RequestHandler as OidcRequestHandler
  participant OidcService as OidcService
  participant RedirectService as RedirectUriService

  Client->>RestController: GET /auth/authorize?provider=...&callback=...
  RestController->>RequestHandler: extractRequestInfo(req)
  RequestHandler-->>RestController: RequestInfo { protocol, host, fullUrl, baseUrl }
  RestController->>OidcService: getAuthorizationUrl({ providerId, requestOriginInfo })
  OidcService->>RedirectService: getRedirectUri(requestOrigin, requestOriginInfo)
  RedirectService-->>OidcService: validated redirect URI
  OidcService-->>RestController: authorization URL (with redirect_uri & state)
  RestController-->>Client: 302 Redirect -> authorization URL
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I sniffed the scheme and nibbled on the host,

I hopped through requests till the origin I chose most.
Helpers tidy routes and tests hop in line,
Redirects now land neat, every single time.
Carrots for CI when the pipelines shine!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(oidc): trust Fastify proxy metadata' is specific, concise, and directly reflects the main change—configuring Fastify to trust proxy metadata for OIDC origin derivation.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 codex/fix-oidc-proxy-redirect-uri

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

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 31, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 52.36%. Comparing base (160c5b1) to head (182f27d).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1982      +/-   ##
==========================================
+ Coverage   52.21%   52.36%   +0.14%     
==========================================
  Files        1032     1033       +1     
  Lines       71646    71626      -20     
  Branches     8146     8144       -2     
==========================================
+ Hits        37412    37508      +96     
+ Misses      34109    33993     -116     
  Partials      125      125              

☔ View full report in Codecov by Sentry.
📢 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.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

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 the current code and only fix it if needed.

Inline comments:
In `@api/src/unraid-api/rest/rest.controller.ts`:
- Around line 80-87: The code in rest.controller.ts reads x-forwarded-proto and
x-forwarded-host into forwardedProto/forwardedHost and uses them to set
protocol/host for redirect validation, but these headers are untrusted unless
Fastify's trustProxy is enabled or the headers are validated; either enable
trustProxy on the FastifyAdapter when creating the Nest app (so Fastify will
safely trust and parse forwarded headers) or add a validation step before using
forwardedProto/forwardedHost: verify the request source (e.g., check req.ip or
req.raw.socket.remoteAddress) against your trusted proxy list and only use
forwardedProto/forwardedHost when the source is a trusted proxy, otherwise fall
back to req.headers.host/req.hostname; update the logic around forwardedProto,
forwardedHost, protocol, and host to enforce this.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 2af04daa-3023-4514-8b98-7787b80bf87f

📥 Commits

Reviewing files that changed from the base of the PR and between 160c5b1 and 555fc0f.

📒 Files selected for processing (2)
  • api/src/unraid-api/rest/rest.controller.test.ts
  • api/src/unraid-api/rest/rest.controller.ts

@elibosley elibosley changed the title fix(oidc): normalize forwarded redirect host headers fix(oidc): trust Fastify proxy metadata Apr 1, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (3)
api/src/unraid-api/graph/resolvers/sso/utils/oidc-request-origin.util.ts (2)

20-32: Redundant fallback in extractRequestInfo.

Line 23 applies host || 'localhost:3000' but extractRequestOriginInfo on line 21 already guarantees host will never be falsy (it has the same fallback). This is dead code given the current implementation.

♻️ Suggested simplification
 export function extractRequestInfo(req: FastifyRequest): RequestInfo {
     const { protocol, host } = extractRequestOriginInfo(req);

-    const resolvedHost = host || 'localhost:3000';
-    const fullUrl = `${protocol}://${resolvedHost}${req.url}`;
-    const baseUrl = `${protocol}://${resolvedHost}`;
+    const fullUrl = `${protocol}://${host}${req.url}`;
+    const baseUrl = `${protocol}://${host}`;

     return {
         protocol,
-        host: resolvedHost,
+        host,
         fullUrl,
         baseUrl,
     };
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/src/unraid-api/graph/resolvers/sso/utils/oidc-request-origin.util.ts`
around lines 20 - 32, The assignment in extractRequestInfo redundantly falls
back to 'localhost:3000' even though extractRequestOriginInfo already returns a
non-falsy host; remove the redundant fallback by using the host value returned
from extractRequestOriginInfo directly (i.e., change resolvedHost = host ||
'localhost:3000' to resolvedHost = host or just use host when building
fullUrl/baseUrl), keeping function names extractRequestInfo and
extractRequestOriginInfo intact and leaving protocol, fullUrl, and baseUrl
construction unchanged.

3-6: Type inconsistency: host is always defined but typed as optional.

The RequestOriginInfo interface declares host: string | undefined, but extractRequestOriginInfo always returns a defined string due to the fallback chain (req.host || req.hostname || req.headers.host || 'localhost:3000'). This discrepancy can cause unnecessary null checks downstream and makes the contract confusing.

Consider aligning the type with the actual behavior:

♻️ Suggested fix
 export interface RequestOriginInfo {
     protocol: string;
-    host: string | undefined;
+    host: string;
 }

Also applies to: 13-18

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/src/unraid-api/graph/resolvers/sso/utils/oidc-request-origin.util.ts`
around lines 3 - 6, The RequestOriginInfo interface declares host as possibly
undefined but extractRequestOriginInfo always returns a defined string; change
RequestOriginInfo.host from "string | undefined" to "string" and update any
other matching declarations/usages (e.g., where RequestOriginInfo is consumed)
so consumers no longer check for undefined; verify extractRequestOriginInfo (and
any other function returning RequestOriginInfo) continues to supply a fallback
like req.host || req.hostname || req.headers.host || 'localhost:3000' to
guarantee a string.
api/src/unraid-api/graph/resolvers/sso/utils/oidc-request-handler.util.ts (1)

6-10: Reuse the already-normalized requestInfo here.

Line 44 already computes the trusted protocol/host for this flow. Re-extracting from req on Line 55 creates a second normalization path to keep in sync; building requestOriginInfo from requestInfo keeps the logged, validated, and forwarded values locked together.

Suggested refactor
 import {
     extractRequestInfo,
-    extractRequestOriginInfo,
     RequestInfo,
 } from '@app/unraid-api/graph/resolvers/sso/utils/oidc-request-origin.util.js';
...
-            requestOriginInfo: extractRequestOriginInfo(req),
+            requestOriginInfo: {
+                protocol: requestInfo.protocol,
+                host: requestInfo.host,
+            },

Also applies to: 44-55

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/src/unraid-api/graph/resolvers/sso/utils/oidc-request-handler.util.ts`
around lines 6 - 10, The code currently computes requestInfo via
extractRequestInfo(...) and then re-extracts origin info from req again; instead
use the already-normalized requestInfo to build requestOriginInfo by calling
extractRequestOriginInfo(requestInfo) (replace the second
extractRequestOriginInfo(req) call), ensuring you pass the RequestInfo object
and adjust any typings/uses of requestOriginInfo accordingly so
logged/validated/forwarded values remain consistent with requestInfo.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@api/src/unraid-api/graph/resolvers/sso/client/oidc-redirect-uri.service.test.ts`:
- Around line 68-73: Replace the assertions that pass UnauthorizedException into
.rejects.toThrow with bare .rejects.toThrow() in the async error tests for the
OIDC redirect URI service tests: update the expect calls that invoke
service.getRedirectUri(...) and the other failing test that asserts on
getClient(...) to use .rejects.toThrow() (no argument) so they only assert
rejection without coupling to a specific exception type.

In `@api/src/unraid-api/main.ts`:
- Around line 66-75: The trustProxy value passed into new FastifyAdapter is
using an incorrect base address for the /8 CIDR ("127.0.0.1/8"); update the
FastifyAdapter options in the NestFactory.create call (where FastifyAdapter is
instantiated for AppModule in main.ts) to use the correct CIDR "127.0.0.0/8" or,
even better for clarity, replace the array/string with Fastify's predefined
alias "loopback" (equivalent to ['127.0.0.0/8','::1/128']) so loopback proxy
trust is correctly and explicitly configured.

In `@api/src/unraid-api/rest/rest.controller.oidc.integration.test.ts`:
- Line 32: The test currently uses a weak Partial<FastifyReply> for mockReply
causing runtime guards and an as FastifyReply cast; replace it with a concrete
mock type that only includes the methods/properties you call (e.g., an
interface/type with header: (name: string, value: string) => FastifyReply & {
status: (code: number) => FastifyReply }, status: (code: number) =>
FastifyReply, send: (body?: any) => void) and declare mockReply with that type,
or alternatively keep a separate headerSpy/headerMock variable for the header
function and type mockReply without header to avoid casting; update the
beforeEach to initialize mockReply and headerSpy concretely and remove the as
FastifyReply cast when passing mockReply into the controller.

---

Nitpick comments:
In `@api/src/unraid-api/graph/resolvers/sso/utils/oidc-request-handler.util.ts`:
- Around line 6-10: The code currently computes requestInfo via
extractRequestInfo(...) and then re-extracts origin info from req again; instead
use the already-normalized requestInfo to build requestOriginInfo by calling
extractRequestOriginInfo(requestInfo) (replace the second
extractRequestOriginInfo(req) call), ensuring you pass the RequestInfo object
and adjust any typings/uses of requestOriginInfo accordingly so
logged/validated/forwarded values remain consistent with requestInfo.

In `@api/src/unraid-api/graph/resolvers/sso/utils/oidc-request-origin.util.ts`:
- Around line 20-32: The assignment in extractRequestInfo redundantly falls back
to 'localhost:3000' even though extractRequestOriginInfo already returns a
non-falsy host; remove the redundant fallback by using the host value returned
from extractRequestOriginInfo directly (i.e., change resolvedHost = host ||
'localhost:3000' to resolvedHost = host or just use host when building
fullUrl/baseUrl), keeping function names extractRequestInfo and
extractRequestOriginInfo intact and leaving protocol, fullUrl, and baseUrl
construction unchanged.
- Around line 3-6: The RequestOriginInfo interface declares host as possibly
undefined but extractRequestOriginInfo always returns a defined string; change
RequestOriginInfo.host from "string | undefined" to "string" and update any
other matching declarations/usages (e.g., where RequestOriginInfo is consumed)
so consumers no longer check for undefined; verify extractRequestOriginInfo (and
any other function returning RequestOriginInfo) continues to supply a fallback
like req.host || req.hostname || req.headers.host || 'localhost:3000' to
guarantee a string.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: f9842c35-3e6e-48e1-a10b-6b079ca381e7

📥 Commits

Reviewing files that changed from the base of the PR and between 555fc0f and e546254.

📒 Files selected for processing (14)
  • api/src/unraid-api/graph/resolvers/sso/client/oidc-redirect-uri.service.test.ts
  • api/src/unraid-api/graph/resolvers/sso/client/oidc-redirect-uri.service.ts
  • api/src/unraid-api/graph/resolvers/sso/core/oidc.service.integration.test.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/utils/oidc-request-handler.util.spec.ts
  • api/src/unraid-api/graph/resolvers/sso/utils/oidc-request-handler.util.ts
  • api/src/unraid-api/graph/resolvers/sso/utils/oidc-request-origin.util.test.ts
  • api/src/unraid-api/graph/resolvers/sso/utils/oidc-request-origin.util.ts
  • api/src/unraid-api/main.test.ts
  • api/src/unraid-api/main.ts
  • api/src/unraid-api/rest/rest.controller.oidc.integration.test.ts
  • api/src/unraid-api/rest/rest.controller.test.ts
  • api/src/unraid-api/rest/rest.controller.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • api/src/unraid-api/rest/rest.controller.ts
  • api/src/unraid-api/rest/rest.controller.test.ts

- Purpose: make OIDC authorize redirect URI validation work when requests arrive through reverse proxies that send forwarded header chains.
- Before: the REST authorize endpoint used raw x-forwarded-host and x-forwarded-proto header values, so comma-separated or array-style forwarded headers could be passed straight into URL validation.
- Problem: proxied domain-based logins could fail with a misleading 'Invalid redirect_uri format' error even when the callback URI in Management Access was correct, while direct IP-based access still worked.
- Change: trim forwarded header chains to the first hop before validation and preserve the endpoint's existing host/protocol fallback behavior for non-proxied localhost and IP flows.
- Verification: added controller tests covering comma-separated and array-valued forwarded headers and ran the focused Vitest suites for the REST controller and redirect URI validator.
- Purpose: make OIDC authorize redirect validation rely on trusted Fastify request origin data instead of raw forwarded headers.
- Before: the REST authorize path and redirect URI service could derive origin information differently, so proxied custom-domain requests could pass one validation layer and fail the next with a generic provider/configuration error.
- Why: using raw x-forwarded-* values in a security decision is unsafe unless the proxy is trusted, and duplicating origin parsing across layers made the bug easy to reintroduce.
- What: configure Fastify trustProxy for loopback proxies, centralize request-origin extraction in a shared helper, pass normalized origin info through the OIDC authorize flow, and add controller/service/bootstrap regression coverage.
- How: RestController, OidcRequestHandler, OidcService, and OidcRedirectUriService now consume the same trusted protocol/host values from Fastify request metadata, with focused Vitest coverage for proxied domain flows and bootstrap configuration.
- Purpose: align the recent OIDC proxy-trust changes with the formatter output used by the API package.
- Before: several touched files still had non-Prettier wrapping and import ordering from the manual edits.
- Why: leaving formatting drift in the PR adds noise to review and makes later diffs less clear.
- What: ran Prettier on the changed OIDC files and committed the resulting formatting-only updates.
- How: applied package-local Prettier output to the touched tests and utilities without changing runtime behavior.
- Purpose: unblock the failing API CI type-check after adding the proxied-domain integration coverage.
- Before: the new integration test read the mocked Location header through an optional chained lookup that Vitest handled at runtime but strict TypeScript rejected in CI.
- Why: the API workflow runs Version 4.8.4
tsc: The TypeScript Compiler - Version 4.8.4

COMMON COMMANDS

  tsc
  Compiles the current project (tsconfig.json in the working directory.)

  tsc app.ts util.ts
  Ignoring tsconfig.json, compiles the specified files with default compiler options.

  tsc -b
  Build a composite project in the working directory.

  tsc --init
  Creates a tsconfig.json with the recommended settings in the working directory.

  tsc -p ./path/to/tsconfig.json
  Compiles the TypeScript project located at the specified path.

  tsc --help --all
  An expanded version of this information, showing all possible compiler options

  tsc --noEmit
  tsc --target esnext
  Compiles the current project, with additional settings.

COMMAND LINE FLAGS

--help, -h
Print this message.

--watch, -w
Watch input files.

--all
Show all compiler options.

--version, -v
Print the compiler's version.

--init
Initializes a TypeScript project and creates a tsconfig.json file.

--project, -p
Compile the project given the path to its configuration file, or to a folder with a 'tsconfig.json'.

--build, -b
Build one or more projects and their dependencies, if out of date

--showConfig
Print the final configuration instead of building.

COMMON COMPILER OPTIONS

--pretty
Enable color and formatting in TypeScript's output to make compiler errors easier to read.
type: boolean
default: true

--target, -t
Set the JavaScript language version for emitted JavaScript and include compatible library declarations.
one of: es3, es5, es6/es2015, es2016, es2017, es2018, es2019, es2020, es2021, es2022, esnext
default: es3

--module, -m
Specify what module code is generated.
one of: none, commonjs, amd, umd, system, es6/es2015, es2020, es2022, esnext, node16, nodenext
default: undefined

--lib
Specify a set of bundled library declaration files that describe the target runtime environment.
one or more: es5, es6/es2015, es7/es2016, es2017, es2018, es2019, es2020, es2021, es2022, esnext, dom, dom.iterable, webworker, webworker.importscripts, webworker.iterable, scripthost, es2015.core, es2015.collection, es2015.generator, es2015.iterable, es2015.promise, es2015.proxy, es2015.reflect, es2015.symbol, es2015.symbol.wellknown, es2016.array.include, es2017.object, es2017.sharedmemory, es2017.string, es2017.intl, es2017.typedarrays, es2018.asyncgenerator, es2018.asynciterable/esnext.asynciterable, es2018.intl, es2018.promise, es2018.regexp, es2019.array, es2019.object, es2019.string, es2019.symbol/esnext.symbol, es2020.bigint/esnext.bigint, es2020.date, es2020.promise, es2020.sharedmemory, es2020.string, es2020.symbol.wellknown, es2020.intl, es2020.number, es2021.promise/esnext.promise, es2021.string, es2021.weakref/esnext.weakref, es2021.intl, es2022.array/esnext.array, es2022.error, es2022.intl, es2022.object, es2022.sharedmemory, es2022.string/esnext.string, esnext.intl
default: undefined

--allowJs
Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files.
type: boolean
default: false

--checkJs
Enable error reporting in type-checked JavaScript files.
type: boolean
default: false

--jsx
Specify what JSX code is generated.
one of: preserve, react, react-native, react-jsx, react-jsxdev
default: undefined

--declaration, -d
Generate .d.ts files from TypeScript and JavaScript files in your project.
type: boolean
default: `false`, unless `composite` is set

--declarationMap
Create sourcemaps for d.ts files.
type: boolean
default: false

--emitDeclarationOnly
Only output d.ts files and not JavaScript files.
type: boolean
default: false

--sourceMap
Create source map files for emitted JavaScript files.
type: boolean
default: false

--outFile
Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output.

--outDir
Specify an output folder for all emitted files.

--removeComments
Disable emitting comments.
type: boolean
default: false

--noEmit
Disable emitting files from a compilation.
type: boolean
default: false

--strict
Enable all strict type-checking options.
type: boolean
default: false

--types
Specify type package names to be included without being referenced in a source file.

--esModuleInterop
Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility.
type: boolean
default: false

You can learn about all of the compiler options at https://aka.ms/tsc, so the test suite must satisfy compile-time nullability rules even when runtime assertions already guarantee the value.
- What: narrowed the reply header mock explicitly before reading call arguments and removed the unsafe cast when constructing the redirect URL.
- How: assert the header mock exists, derive the matching  call from the narrowed mock, and guard the extracted header value before passing it to .
- Purpose: address the remaining review feedback on proxy trust configuration, request-origin typing, and OIDC regression test brittleness.
- Before: Fastify trustProxy used a misleading loopback CIDR string, request-origin utilities still carried an unnecessary optional host contract, and a few tests were more tightly coupled to implementation details than needed.
- Why: the runtime behavior was mostly correct, but the follow-up cleanup reduces ambiguity around trusted proxy behavior and keeps the new OIDC coverage maintainable under strict type-checking.
- What: switch Fastify trustProxy to the explicit loopback alias, make RequestOriginInfo.host always defined, reuse normalized request info in the authorize handler, relax async error assertions, and harden the authorize integration reply mock.
- How: update the bootstrap/test expectations, simplify request-origin construction, pass only protocol/host from normalized request info, and rework the integration test spies so they satisfy both Vitest and TypeScript without unsafe call-site assumptions.
@elibosley elibosley force-pushed the codex/fix-oidc-proxy-redirect-uri branch from 637aad5 to 182f27d Compare April 1, 2026 17:23
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 1, 2026

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/PR1982/dynamix.unraid.net.plg

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
api/src/unraid-api/graph/resolvers/sso/utils/oidc-request-handler.util.ts (1)

35-58: Pass the already-normalized RequestInfo into handleAuthorize().

oidcAuthorize() now normalizes the request once before validation, but handleAuthorize() immediately recomputes it from req. Threading the existing requestInfo through here would keep validation and authorization pinned to the same trusted object and remove the last duplicated origin derivation in this path.

♻️ Proposed refactor
     static async handleAuthorize(
         providerId: string,
         state: string,
         redirectUri: string,
-        req: FastifyRequest,
+        requestInfo: RequestInfo,
         oidcService: OidcService,
         logger: Logger
     ): Promise<string> {
-        const requestInfo = this.extractRequestInfo(req);
-
         logger.debug(`Authorization request - Provider: ${providerId}`);
         logger.debug(`Authorization request - Full URL: ${requestInfo.fullUrl}`);
         logger.debug(`Authorization request - Redirect URI: ${redirectUri}`);

The controller can then pass the requestInfo it already computed.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/src/unraid-api/graph/resolvers/sso/utils/oidc-request-handler.util.ts`
around lines 35 - 58, handleAuthorize currently re-extracts RequestInfo via
extractRequestInfo(req) causing a duplicate origin derivation; change
handleAuthorize signature to accept a pre-normalized RequestInfo (e.g., add
parameter requestInfo: RequestInfo) and use that value when calling
oidcService.getAuthorizationUrl (pass requestInfo.protocol and requestInfo.host
and requestInfo.fullUrl to logs) instead of calling extractRequestInfo; update
the caller (oidcAuthorize) to pass the already-computed RequestInfo into
handleAuthorize and remove the redundant extractRequestInfo invocation inside
handleAuthorize, ensuring types for RequestInfo are imported/kept consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@api/src/unraid-api/rest/rest.controller.test.ts`:
- Around line 20-34: The headers parameter in createMockRequest is currently
typed as Record<string, any>, which weakens type safety; change its type to
FastifyRequest['headers'] and update the default value to an empty object casted
or typed as that same Headers type (e.g., headers: FastifyRequest['headers'] =
{} as FastifyRequest['headers']). Ensure the FastifyRequest type is
imported/available in the test file and keep the rest of createMockRequest
(hostname, options, returned object cast to FastifyRequest) unchanged.

---

Nitpick comments:
In `@api/src/unraid-api/graph/resolvers/sso/utils/oidc-request-handler.util.ts`:
- Around line 35-58: handleAuthorize currently re-extracts RequestInfo via
extractRequestInfo(req) causing a duplicate origin derivation; change
handleAuthorize signature to accept a pre-normalized RequestInfo (e.g., add
parameter requestInfo: RequestInfo) and use that value when calling
oidcService.getAuthorizationUrl (pass requestInfo.protocol and requestInfo.host
and requestInfo.fullUrl to logs) instead of calling extractRequestInfo; update
the caller (oidcAuthorize) to pass the already-computed RequestInfo into
handleAuthorize and remove the redundant extractRequestInfo invocation inside
handleAuthorize, ensuring types for RequestInfo are imported/kept consistent.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 9719c4c9-7d30-4eb1-8ca8-e8282fe5d5f2

📥 Commits

Reviewing files that changed from the base of the PR and between 637aad5 and 182f27d.

📒 Files selected for processing (14)
  • api/src/unraid-api/graph/resolvers/sso/client/oidc-redirect-uri.service.test.ts
  • api/src/unraid-api/graph/resolvers/sso/client/oidc-redirect-uri.service.ts
  • api/src/unraid-api/graph/resolvers/sso/core/oidc.service.integration.test.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/utils/oidc-request-handler.util.spec.ts
  • api/src/unraid-api/graph/resolvers/sso/utils/oidc-request-handler.util.ts
  • api/src/unraid-api/graph/resolvers/sso/utils/oidc-request-origin.util.test.ts
  • api/src/unraid-api/graph/resolvers/sso/utils/oidc-request-origin.util.ts
  • api/src/unraid-api/main.test.ts
  • api/src/unraid-api/main.ts
  • api/src/unraid-api/rest/rest.controller.oidc.integration.test.ts
  • api/src/unraid-api/rest/rest.controller.test.ts
  • api/src/unraid-api/rest/rest.controller.ts
✅ Files skipped from review due to trivial changes (3)
  • api/src/unraid-api/main.test.ts
  • api/src/unraid-api/graph/resolvers/sso/utils/oidc-request-origin.util.test.ts
  • api/src/unraid-api/graph/resolvers/sso/utils/oidc-request-handler.util.spec.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • api/src/unraid-api/graph/resolvers/sso/core/oidc.service.integration.test.ts
  • api/src/unraid-api/graph/resolvers/sso/core/oidc.service.ts
  • api/src/unraid-api/graph/resolvers/sso/utils/oidc-request-origin.util.ts
  • api/src/unraid-api/graph/resolvers/sso/core/oidc.service.test.ts

Comment on lines +20 to 34
const createMockRequest = (
hostname?: string,
headers: Record<string, any> = {},
options: {
host?: string;
protocol?: string;
} = {}
): FastifyRequest => {
return {
headers,
hostname,
host: options.host ?? hostname ?? headers.host,
url: '/test',
protocol: 'https',
protocol: options.protocol ?? 'https',
} as FastifyRequest;
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.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cat -n api/src/unraid-api/rest/rest.controller.test.ts | head -50

Repository: unraid/api

Length of output: 2294


🏁 Script executed:

rg -A 5 "const createMockRequest" api/src/unraid-api/rest/rest.controller.test.ts

Repository: unraid/api

Length of output: 232


🏁 Script executed:

rg "import.*Fastify" api/src/unraid-api/rest/rest.controller.test.ts -A 2 -B 2

Repository: unraid/api

Length of output: 396


🏁 Script executed:

cat api/src/unraid-api/types/fastify.ts | head -100

Repository: unraid/api

Length of output: 894


🏁 Script executed:

rg "headers" api/src/unraid-api/types/fastify.ts -A 2 -B 2

Repository: unraid/api

Length of output: 349


🏁 Script executed:

rg "createMockRequest" api/src/unraid-api/rest/rest.controller.test.ts -A 2 -B 1

Repository: unraid/api

Length of output: 4445


🏁 Script executed:

cat api/src/unraid-api/types/fastify.ts

Repository: unraid/api

Length of output: 894


Tighten the mock header type.

Record<string, any> violates the coding guideline and weakens type safety in these proxy regression tests. Use FastifyRequest['headers'] to properly reference the project's custom Headers type, which constrains headers to the correct shape.

♻️ Proposed fix
-        headers: Record<string, any> = {},
+        headers: FastifyRequest['headers'] = {},
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const createMockRequest = (
hostname?: string,
headers: Record<string, any> = {},
options: {
host?: string;
protocol?: string;
} = {}
): FastifyRequest => {
return {
headers,
hostname,
host: options.host ?? hostname ?? headers.host,
url: '/test',
protocol: 'https',
protocol: options.protocol ?? 'https',
} as FastifyRequest;
const createMockRequest = (
hostname?: string,
headers: FastifyRequest['headers'] = {},
options: {
host?: string;
protocol?: string;
} = {}
): FastifyRequest => {
return {
headers,
hostname,
host: options.host ?? hostname ?? headers.host,
url: '/test',
protocol: options.protocol ?? 'https',
} as FastifyRequest;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/src/unraid-api/rest/rest.controller.test.ts` around lines 20 - 34, The
headers parameter in createMockRequest is currently typed as Record<string,
any>, which weakens type safety; change its type to FastifyRequest['headers']
and update the default value to an empty object casted or typed as that same
Headers type (e.g., headers: FastifyRequest['headers'] = {} as
FastifyRequest['headers']). Ensure the FastifyRequest type is imported/available
in the test file and keep the rest of createMockRequest (hostname, options,
returned object cast to FastifyRequest) unchanged.

@elibosley elibosley merged commit ad494d7 into main Apr 2, 2026
13 checks passed
@elibosley elibosley deleted the codex/fix-oidc-proxy-redirect-uri branch April 2, 2026 03:11
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