Skip to content

feat(oidc): infer dynamic OIDC issuer parameters#200

Merged
halvaradop merged 2 commits into
masterfrom
feat/infer-oidc-issuer-params
Jun 26, 2026
Merged

feat(oidc): infer dynamic OIDC issuer parameters#200
halvaradop merged 2 commits into
masterfrom
feat/infer-oidc-issuer-params

Conversation

@halvaradop

@halvaradop halvaradop commented Jun 26, 2026

Copy link
Copy Markdown
Member

Description

This pull request adds TypeScript inference for dynamic parameters in OpenID Connect (OIDC) provider issuers.

Any issuer URL containing dynamic segments (path or host segments prefixed with :) is now automatically analyzed, and the corresponding parameters become required when configuring the provider. This improves type safety by ensuring that all dynamic issuer parameters are provided at compile time.

Usage

import { User } from "@aura-stack/auth"

type Profile = Record<string, any>

const oidc: OpenIDProvider<
  Profile,
  User,
  "https://app.com/issuer/:teamId/apps/:appId"
> = {
  id: "oidc",
  name: "OIDC",
  issuer: "https://app.com/issuer/:teamId/apps/:appId",
  teamId: 1,
  appId: 2,
}

@coderabbitai ignore

@halvaradop halvaradop added the oauth Changes related to OAuth flows, providers, tokens, or authentication integration. label Jun 26, 2026
@vercel

vercel Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
auth Skipped Skipped Jun 26, 2026 2:21am

@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

OIDC provider issuers can now include :param segments that are resolved from config values. The provider type reflects issuer-derived route params, resolution applies substitutions before discovery, and a new validation error code and tests cover the path.

Changes

OIDC dynamic issuer parameters

Layer / File(s) Summary
Issuer template resolution
packages/core/src/oauth/index.ts, packages/core/src/shared/errors.ts, packages/core/test/oauth.test.ts, packages/core/CHANGELOG.md
setDynamicParams resolves :param segments in issuer templates during OAuth config creation, registers the missing-parameter error code, and adds tests for substitution and validation.
Issuer type and resolution flow
packages/core/src/@types/oidc.ts, packages/core/src/actions/oidc/resolve-provider.ts, packages/core/test/actions/oidc/*
OpenIDProvider now carries issuer-derived route params, and provider resolution applies dynamic issuer values before discovery metadata fetches; tests cover the new issuer-aware flow.

Sequence Diagram(s)

sequenceDiagram
  participant defineOpenIDProviderConfig
  participant setDynamicParams
  participant resolveOpenIDProvider
  participant discoveryMetadata
  participant fetch

  defineOpenIDProviderConfig->>setDynamicParams: resolve config.issuer placeholders
  resolveOpenIDProvider->>setDynamicParams: resolve provider.oidc.issuer placeholders
  resolveOpenIDProvider->>discoveryMetadata: request discovery metadata
  discoveryMetadata->>fetch: GET /.well-known/openid-configuration
  fetch-->>discoveryMetadata: JSON metadata
  discoveryMetadata-->>resolveOpenIDProvider: issuer metadata
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested labels

feature

Poem

A rabbit hopped through issuer trees,
Replacing :params with graceful ease.
The path resolved, the metadata shone,
And OIDC found its proper home. 🐇

🚥 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 matches the main change: inferring dynamic OIDC issuer parameters, though it slightly understates the runtime and validation updates.
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
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/infer-oidc-issuer-params

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

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (3)
packages/core/test/actions/oidc/resolve-provider.test.ts (1)

73-93: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add explicit assertions.

This test only awaits resolveOpenIDProvider(placeholder) and asserts nothing; it passes as long as nothing throws. The dynamic-param substitution is validated only indirectly via the discovery issuer-match. Assert the substituted URL was used (e.g. expect(fetchMock).toHaveBeenCalledWith("https://app.com/issuer/1/apps/2/.well-known/openid-configuration", ...)) and/or the resolved oidc.issuer.

🤖 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 `@packages/core/test/actions/oidc/resolve-provider.test.ts` around lines 73 -
93, The dynamic-params OIDC test in resolveOpenIDProvider does not assert
anything, so add explicit expectations to verify the placeholder substitution
actually happened. Use fetchMock and/or the resolved provider from
resolveOpenIDProvider(placeholder) to assert the discovery URL was called with
https://app.com/issuer/1/apps/2/.well-known/openid-configuration and that the
resolved issuer matches the substituted value.
packages/core/src/actions/oidc/resolve-provider.ts (1)

20-24: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Re-resolving an already-resolved issuer here is fragile.

provider is a RuntimeOAuthProvider placeholder whose oidc.issuer was already substituted in createOpenIDPlaceholder, and the runtime provider does not carry the original :param keys (teamId/appId). This call is a no-op only because the issuer is already concrete; if any unresolved :param ever reached here, it would throw OIDC_INVALID_ISSUER_PARAMS since the values aren't present on provider. Consider resolving issuer params in exactly one place to avoid relying on idempotency. Related to the double-resolution noted in packages/core/src/oauth/index.ts.

🤖 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 `@packages/core/src/actions/oidc/resolve-provider.ts` around lines 20 - 24, The
issuer in resolveProvider is being resolved twice, which is fragile because the
RuntimeOAuthProvider no longer contains the original dynamic param keys. Update
the flow so issuer params are resolved in exactly one place, and in this
function just read and validate provider.oidc.issuer without calling
setDynamicParams again. Keep the existing missing-issuer check and make sure the
resolution logic is centralized with createOpenIDPlaceholder and the related
OAuth provider handling in oauth/index.ts.
packages/core/src/oauth/index.ts (1)

104-114: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Redundant re-resolution and mutation of the caller's config.

Line 110 mutates the input config.issuer in place (an observable side effect on the caller's object), and createOpenIDPlaceholder (line 111) already calls setDynamicParams(config.issuer, config) internally, so substitution runs twice. The second pass is a no-op only because resolution happens to be idempotent on an already-resolved URL. Prefer resolving once without mutating the argument.

♻️ Suggested change
-    const envConfig = !config.clientId || !config.clientSecret ? defineOAuthEnvironment(config.id) : undefined
-    config.issuer = setDynamicParams(config.issuer, config)
-    return createOpenIDPlaceholder(config, {
+    const envConfig = !config.clientId || !config.clientSecret ? defineOAuthEnvironment(config.id) : undefined
+    return createOpenIDPlaceholder(config, {
         clientId: config.clientId || envConfig!.clientId,
         clientSecret: config.clientSecret || envConfig!.clientSecret,
     })

(createOpenIDPlaceholder already applies setDynamicParams to config.issuer.)

🤖 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 `@packages/core/src/oauth/index.ts` around lines 104 - 114, The OpenID provider
setup in defineOpenIDProviderConfig is resolving the issuer twice and mutating
the caller’s config object in place. Remove the direct assignment to
config.issuer, and instead pass an untouched config through to
createOpenIDPlaceholder, which already applies setDynamicParams to config.issuer
internally. Keep the clientId/clientSecret fallback logic using envConfig, but
avoid any observable side effects on the input OpenIDProvider.
🤖 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 `@packages/core/src/oauth/index.ts`:
- Around line 94-102: The issuer templating logic is incorrectly treating URL
authority ports as placeholder parameters, causing valid issuer URLs with
explicit ports to fail. Update setDynamicParams() so it only substitutes real
template segments and does not match the host:port portion of an issuer URL,
then adjust defineOpenIDProviderConfig() and createOpenIDPlaceholder() to work
from a derived issuer value instead of mutating config.issuer and resolving it
twice.

In `@packages/core/src/shared/errors.ts`:
- Around line 802-808: The OIDC_INVALID_ISSUER_PARAMS error definition in
errors.ts currently has empty message and userMessage fields, which causes blank
output through the AuraAuthError flow. Update that error entry with a clear
internal message and a user-facing message, keeping the existing OIDC validation
mapping and 502 statusCode intact so callers like AuraAuthError receive
meaningful content.

---

Nitpick comments:
In `@packages/core/src/actions/oidc/resolve-provider.ts`:
- Around line 20-24: The issuer in resolveProvider is being resolved twice,
which is fragile because the RuntimeOAuthProvider no longer contains the
original dynamic param keys. Update the flow so issuer params are resolved in
exactly one place, and in this function just read and validate
provider.oidc.issuer without calling setDynamicParams again. Keep the existing
missing-issuer check and make sure the resolution logic is centralized with
createOpenIDPlaceholder and the related OAuth provider handling in
oauth/index.ts.

In `@packages/core/src/oauth/index.ts`:
- Around line 104-114: The OpenID provider setup in defineOpenIDProviderConfig
is resolving the issuer twice and mutating the caller’s config object in place.
Remove the direct assignment to config.issuer, and instead pass an untouched
config through to createOpenIDPlaceholder, which already applies
setDynamicParams to config.issuer internally. Keep the clientId/clientSecret
fallback logic using envConfig, but avoid any observable side effects on the
input OpenIDProvider.

In `@packages/core/test/actions/oidc/resolve-provider.test.ts`:
- Around line 73-93: The dynamic-params OIDC test in resolveOpenIDProvider does
not assert anything, so add explicit expectations to verify the placeholder
substitution actually happened. Use fetchMock and/or the resolved provider from
resolveOpenIDProvider(placeholder) to assert the discovery URL was called with
https://app.com/issuer/1/apps/2/.well-known/openid-configuration and that the
resolved issuer matches the substituted value.
🪄 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

Run ID: 59c444d0-fd6b-44e8-a361-5e3b5dd39517

📥 Commits

Reviewing files that changed from the base of the PR and between 99a5419 and b85f2fe.

📒 Files selected for processing (8)
  • packages/core/CHANGELOG.md
  • packages/core/src/@types/oidc.ts
  • packages/core/src/actions/oidc/resolve-provider.ts
  • packages/core/src/oauth/index.ts
  • packages/core/src/shared/errors.ts
  • packages/core/test/actions/oidc/discovery.test.ts
  • packages/core/test/actions/oidc/resolve-provider.test.ts
  • packages/core/test/oauth.test.ts

Comment thread packages/core/src/oauth/index.ts
Comment thread packages/core/src/shared/errors.ts
@halvaradop halvaradop changed the title feat(types): infer dynamic OIDC issuer parameters feat(oidc): infer dynamic OIDC issuer parameters Jun 26, 2026
@halvaradop halvaradop merged commit d82a096 into master Jun 26, 2026
7 checks passed
@halvaradop halvaradop deleted the feat/infer-oidc-issuer-params branch June 26, 2026 02:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

oauth Changes related to OAuth flows, providers, tokens, or authentication integration.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant