Skip to content

feat: support for the prompt parameter in the oidc flow#948

Merged
steveiliop56 merged 6 commits into
mainfrom
feat/oidc-prompt
Jun 19, 2026
Merged

feat: support for the prompt parameter in the oidc flow#948
steveiliop56 merged 6 commits into
mainfrom
feat/oidc-prompt

Conversation

@steveiliop56

@steveiliop56 steveiliop56 commented Jun 19, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features

    • Added end-to-end support for the OpenID Connect prompt parameter (none/login), including URL handling and backend enforcement.
    • ID tokens now include auth_time.
  • Improvements

    • prompt=none now returns a standardized “login required” error when silent sign-in isn’t possible.
    • Requests that combine prompt=none with other prompt values are rejected as invalid.
    • Updated login/authorize page behavior for auto-authorization, redirects, and disabling actions during auto-authorization.

@dosubot dosubot Bot added the size:M This PR changes 30-99 lines, ignoring generated files. label Jun 19, 2026
@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

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

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: e075106e-6bed-421f-999c-321f16d7d4e7

📥 Commits

Reviewing files that changed from the base of the PR and between dcec803 and 2f46ff7.

📒 Files selected for processing (1)
  • internal/service/oidc_service.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • internal/service/oidc_service.go

📝 Walkthrough

Walkthrough

Adds auth_time to OIDC ID tokens by threading session creation time through UserContext, AuthorizeCodeEntry, and ClaimSet. Implements prompt parameter support in the OIDC authorize endpoint: prompt=none returns login_required for unauthenticated users, and prompt=login sets an oidc_prompt flag forwarded to the frontend, which uses it to control auto-authorization in authorize-page and suppress login-page redirect behavior in login-page.

Changes

OIDC prompt support, auth_time claim, and oidc_prompt frontend parameter

Layer / File(s) Summary
auth_time data model and ID token claim
internal/model/context.go, internal/service/oidc_service.go
UserContext gains AuthTime from session.CreatedAt; AuthorizeCodeEntry and ClaimSet are extended to carry and embed auth_time; generateIDToken accepts an authTime argument and conditionally sets the claim when non-nil.
prompt parameter types and parsing
internal/service/oidc_service.go
OIDCPrompt type with login/none constants and SupportedPrompts list; AuthorizeRequest gains Prompt field; DecodeAuthorizeJWT extracts prompt and new GetPrompt helper selects supported prompts from space-delimited list.
auth_time propagation through token generation
internal/service/oidc_service.go, internal/controller/oidc_controller.go
GenerateAccessToken signature adds authTime parameter and passes it to generateIDToken; RefreshAccessToken calls generateIDToken with authTime set to nil; Token endpoint for authorization_code flow passes entry.AuthTime to GenerateAccessToken.
authorize endpoint prompt handling and oidc_prompt propagation
internal/controller/oidc_controller.go, internal/service/oidc_service.go
AuthorizeScreenParams gains OIDCPrompt field; authorize endpoint loads UserContext to reject prompt=none for unauthenticated users with login_required error, includes effective prompt in redirect query; authorizeComplete standardizes UserContext error handling and messaging.
Frontend oidc_prompt parameter and authorization flow
frontend/src/lib/hooks/screen-params.ts, frontend/src/pages/authorize-page.tsx, frontend/src/pages/login-page.tsx
ScreenParams and zodScreenParams gain optional oidc_prompt field; authorize-page computes shouldAutoAuthorize when authenticated with oidc_prompt=none and required ticket/scope, uses useEffect to auto-invoke authorization mutation, and disables buttons; login-page recompiles params with oidc_prompt cleared and suppresses authenticated-user redirect when oidc_prompt=login; both pages handle login redirect based on oidc_prompt value.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant authorize as /authorize handler
  participant AuthorizePage
  participant LoginPage
  participant authorizeComplete as /authorize-complete
  
  Client->>authorize: GET with prompt parameter
  alt prompt=none and unauthenticated
    authorize-->>Client: OIDC error login_required
  else prompt=none and authenticated
    authorize->>AuthorizePage: redirect with oidc_prompt=none&oidc_ticket=...
    AuthorizePage->>AuthorizePage: shouldAutoAuthorize=true
    AuthorizePage->>authorizeComplete: useEffect invokes authorization mutation
    authorizeComplete->>Client: return token with auth_time claim
  else prompt=login
    authorize->>LoginPage: redirect with oidc_prompt=login
    LoginPage->>LoginPage: suppress post-auth redirect
    LoginPage->>authorizeComplete: proceed after login with oidc_prompt cleared
    authorizeComplete->>Client: return token with auth_time claim
  else normal flow
    authorize->>LoginPage: redirect to /login with oidc_prompt cleared
    LoginPage->>authorizeComplete: proceed with oidc_prompt absent
    authorizeComplete->>Client: return token with auth_time claim
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~28 minutes

Possibly related PRs

  • tinyauthapp/tinyauth#907: Both PRs modify internal/controller/oidc_controller.go's /authorize error paths by changing how authorizeError is invoked/constructed for authorize failures, so the new prompt=none/login_required handling in the main PR depends on the same refactored error-response logic.
  • tinyauthapp/tinyauth#923: Both PRs change the backend OIDC authorization flow by modifying /authorize handling and the OIDC authorize-request decoding/ticket/parameters in internal/controller/oidc_controller.go and internal/service/oidc_service.go (including request parameter/claim handling), so the main PR's oidc_prompt/prompt enforcement builds directly on the same refactored OIDC authorize machinery.

Suggested reviewers

  • Rycochet
  • scottmckendry

🐇 A session was born with a tick of the clock,
auth_time now rides in every JWT block.
With prompt=login a flag hops along,
oidc_prompt keeps the auth flow from going wrong.
The bunny checks none, rejects with a hop,
Auto-auth tidy — what a fine crop! 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 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 (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately summarizes the main change: adding support for the OIDC prompt parameter across frontend and backend components.
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.

✏️ 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 feat/oidc-prompt

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 and usage tips.

@codecov

codecov Bot commented Jun 19, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 13.33333% with 52 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/controller/oidc_controller.go 17.07% 28 Missing and 6 partials ⚠️
internal/service/oidc_service.go 0.00% 18 Missing ⚠️

📢 Thoughts on this report? Let us know!

Comment thread frontend/src/pages/login-page.tsx

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
internal/service/oidc_service.go (1)

618-628: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Persist auth_time for refresh-issued ID tokens.

GenerateAccessToken creates the OIDC session without saving codeEntry.AuthTime, so RefreshAccessToken has to call generateIDToken(..., 0) and refreshed ID tokens omit the claim. Store AuthTime with the OIDC session and reuse it during refresh so clients don’t lose the auth_time contract after the initial code exchange.

Also applies to: 666-668

🤖 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 `@internal/service/oidc_service.go` around lines 618 - 628, The
CreateOIDCSession call is not persisting the AuthTime from codeEntry, causing
refreshed ID tokens to lose the auth_time claim. Add the AuthTime field to the
CreateOIDCSessionParams struct and pass codeEntry.AuthTime when creating the
OIDC session. Then update RefreshAccessToken to retrieve the stored AuthTime
from the OIDC session and pass it to generateIDToken instead of passing 0,
ensuring the auth_time claim is preserved across token refreshes.
internal/controller/oidc_controller.go (1)

179-219: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Keep authenticated prompt=none requests non-interactive.

After the unauthenticated check, an authenticated prompt=none request still creates a frontend ticket and redirects to /oidc/authorize, which requires user interaction. Silent OIDC checks should either complete server-side and redirect with a code, or return an OIDC error such as interaction_required/consent_required.

🤖 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 `@internal/controller/oidc_controller.go` around lines 179 - 219, After the
initial check for unauthenticated users with `prompt=none`, add additional logic
to handle authenticated users who also have `prompt=none` set. When an
authenticated user requests authorization with `prompt=none`, the request should
not proceed to create an authorize ticket and redirect to the interactive
`/oidc/authorize` screen. Instead, handle it non-interactively by either
completing the authorization server-side and redirecting with an authorization
code, or returning an OIDC error such as `interaction_required` or
`consent_required` via the controller.authorizeError method. Add this check
immediately after the existing `prompt=none` and unauthenticated validation and
before the ticket creation logic.
🤖 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 `@internal/controller/oidc_controller.go`:
- Around line 179-201: The current code uses exact string comparisons for
req.Prompt ("none" and "login"), but the OIDC prompt parameter is
space-delimited and can contain multiple values. Parse req.Prompt using
strings.Fields to extract individual tokens, then validate that if "none" is
present it cannot be combined with other values, and branch on token membership
instead of exact string equality. Update the condition checking req.Prompt ==
"none" to check if "none" exists in the parsed tokens, update the condition
checking req.Prompt == "login" to check if "login" exists in the parsed tokens,
and add validation to reject invalid combinations where "none" appears with
other values.

---

Outside diff comments:
In `@internal/controller/oidc_controller.go`:
- Around line 179-219: After the initial check for unauthenticated users with
`prompt=none`, add additional logic to handle authenticated users who also have
`prompt=none` set. When an authenticated user requests authorization with
`prompt=none`, the request should not proceed to create an authorize ticket and
redirect to the interactive `/oidc/authorize` screen. Instead, handle it
non-interactively by either completing the authorization server-side and
redirecting with an authorization code, or returning an OIDC error such as
`interaction_required` or `consent_required` via the controller.authorizeError
method. Add this check immediately after the existing `prompt=none` and
unauthenticated validation and before the ticket creation logic.

In `@internal/service/oidc_service.go`:
- Around line 618-628: The CreateOIDCSession call is not persisting the AuthTime
from codeEntry, causing refreshed ID tokens to lose the auth_time claim. Add the
AuthTime field to the CreateOIDCSessionParams struct and pass codeEntry.AuthTime
when creating the OIDC session. Then update RefreshAccessToken to retrieve the
stored AuthTime from the OIDC session and pass it to generateIDToken instead of
passing 0, ensuring the auth_time claim is preserved across token refreshes.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 61178aab-f39a-4d47-813d-49d5d0f5193b

📥 Commits

Reviewing files that changed from the base of the PR and between 6ccc894 and 80bb4f1.

📒 Files selected for processing (6)
  • frontend/src/lib/hooks/screen-params.ts
  • frontend/src/pages/authorize-page.tsx
  • frontend/src/pages/login-page.tsx
  • internal/controller/oidc_controller.go
  • internal/model/context.go
  • internal/service/oidc_service.go

Comment thread internal/controller/oidc_controller.go Outdated
@dosubot dosubot Bot added size:L This PR changes 100-499 lines, ignoring generated files. and removed size:M This PR changes 30-99 lines, ignoring generated files. labels Jun 19, 2026

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

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 `@internal/service/oidc_service.go`:
- Around line 949-965: The GetPrompt function does not validate the OIDC Core
spec requirement that prompt=none cannot be combined with other prompt values.
Add validation logic within the GetPrompt function to detect when the input
contains "none" alongside other prompts and reject this invalid combination.
After splitting the prompt string, check if both "none" and other supported
prompts are present in the list, and if so, return an error indicator or
empty/invalid state rather than proceeding to return the first supported prompt.
This ensures requests like "prompt=none login" are properly rejected as
invalid_request instead of being accepted.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 21f44d18-3908-4622-a031-980dc2766de5

📥 Commits

Reviewing files that changed from the base of the PR and between 80bb4f1 and 32e899e.

📒 Files selected for processing (5)
  • frontend/src/lib/hooks/screen-params.ts
  • frontend/src/pages/authorize-page.tsx
  • frontend/src/pages/login-page.tsx
  • internal/controller/oidc_controller.go
  • internal/service/oidc_service.go

Comment thread internal/service/oidc_service.go
Rycochet
Rycochet previously approved these changes Jun 19, 2026
@dosubot dosubot Bot added the lgtm This PR has been approved by a maintainer label Jun 19, 2026
scottmckendry
scottmckendry previously approved these changes Jun 19, 2026

@scottmckendry scottmckendry left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

very small nit that may be more correct for OIDC spec. Otherwise LGTM 🚀

Comment thread internal/service/oidc_service.go Outdated
@steveiliop56 steveiliop56 dismissed stale reviews from scottmckendry and Rycochet via 2f46ff7 June 19, 2026 20:35
@steveiliop56 steveiliop56 merged commit 7f18b45 into main Jun 19, 2026
5 checks passed
@steveiliop56 steveiliop56 deleted the feat/oidc-prompt branch June 19, 2026 21:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lgtm This PR has been approved by a maintainer size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants