Skip to content

feat(core): add OAuth2 consent flow support#584

Open
Jorgagu wants to merge 4 commits intoory:mainfrom
Jorgagu:feat/oauth2-consent-flow
Open

feat(core): add OAuth2 consent flow support#584
Jorgagu wants to merge 4 commits intoory:mainfrom
Jorgagu:feat/oauth2-consent-flow

Conversation

@Jorgagu
Copy link
Contributor

@Jorgagu Jorgagu commented Jan 5, 2026

Add complete OAuth2 consent flow support to @ory/nextjs and @ory/elements-react packages, enabling applications to handle OAuth2 authorization consent screens with Ory Hydra.

Related Issue or Design Document

Fixex #327

Add complete OAuth2 consent flow support to @ory/nextjs and @ory/elements-react packages, enabling applications to handle OAuth2 authorization consent screens with Ory Hydra.

Features

  • Consent Flow Utilities (@ory/nextjs)

    • getConsentFlow - Fetch consent challenge from Ory Hydra
    • acceptConsentRequest - Accept consent with selected scopes
    • rejectConsentRequest - Reject consent request
  • OAuth2 Client Logo Display

    • Display OAuth2 client logo on login, registration, and consent cards
    • Shared getConfigWithOAuth2Logo utility for consistent behavior
  • Example Implementations

    • App Router: consent page + API route
    • Pages Router: consent page + API route
    • Custom Components: ConsentFooter, custom scope checkbox with toggle switches
  • Exported Utilities

    • getConsentNodeKey, isFooterNode from card-consent
    • isUiNodeInput, UiNodeInput type helpers

Improvements

  • Optimize rewriteUrls to single-pass regex replacement
  • Add OAuth2 path exclusion in URL rewriting
  • Add null/undefined handling in rewriteJsonResponse

Tests

  • Unit tests for consent utilities and rewrite functions

Checklist

  • I have read the contributing guidelines and signed the CLA.
  • I have referenced an issue containing the design document if my change introduces a new feature.
  • I have read the security policy.
  • I confirm that this pull request does not address a security vulnerability.
    If this pull request addresses a security vulnerability,
    I confirm that I got approval (please contact security@ory.sh) from the maintainers to push the changes.
  • I have added tests that prove my fix is effective or that my feature works.
  • I have added the necessary documentation within the code base (if appropriate).

Further comments

This implementation follows the pattern established in kratos-selfservice-ui-node for handling OAuth2 flows. The OAuth2 client logo is displayed by overriding the project configuration's logo_light_url when an OAuth2 client logo is available, keeping the existing DefaultCardLogo component unchanged.

@changeset-bot
Copy link

changeset-bot bot commented Jan 5, 2026

⚠️ No Changeset found

Latest commit: 73020fc

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@vercel
Copy link

vercel bot commented Jan 5, 2026

@Jorgagu is attempting to deploy a commit to the ory Team on Vercel.

A member of the Team first needs to authorize it.

@codecov
Copy link

codecov bot commented Jan 5, 2026

Codecov Report

❌ Patch coverage is 47.10744% with 64 lines in your changes missing coverage. Please review.
✅ Project coverage is 55.68%. Comparing base (f3fad4d) to head (73020fc).
⚠️ Report is 288 commits behind head on main.

Additional details and impacted files
@@             Coverage Diff             @@
##             main     #584       +/-   ##
===========================================
+ Coverage   42.43%   55.68%   +13.25%     
===========================================
  Files         136      178       +42     
  Lines        2008     3369     +1361     
  Branches      288      494      +206     
===========================================
+ Hits          852     1876     +1024     
- Misses       1149     1416      +267     
- Partials        7       77       +70     
Components Coverage Δ
@ory/elements-react 55.10% <ø> (+18.31%) ⬆️
@ory/nextjs 58.60% <ø> (-7.38%) ⬇️
🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@Jorgagu Jorgagu changed the title feat(oauth2): add OAuth2 consent flow support feat(core): add OAuth2 consent flow support Jan 5, 2026
@Jorgagu
Copy link
Contributor Author

Jorgagu commented Jan 7, 2026

@vinckr @jonas-jonas @aeneasr Happy New Year ! 🎉 Could you please review this one ?

@jonas-jonas
Copy link
Member

hi @Jorgagu, thank you very much for this contribution, and happy new year!

We'll take a look at this in the coming weeks. We do have some code for this already; it just wasn't ready to be published, so we might need to do some merging with that.

And just a heads-up, we're quite busy ramping up after the holidays again, so it might take a couple days longer for us to get to this.

- Add getConsentFlow, acceptConsentRequest, rejectConsentRequest in @ory/nextjs
- Add consent page and API routes for app-router, pages-router, custom-components
- Display OAuth2 client logo and subtitle on login/registration cards
- Add ConsentFooter and custom scope checkbox for custom-components example
- Export getConsentNodeKey, isFooterNode, isUiNodeInput, UiNodeInput utilities
- Optimize rewriteUrls to single-pass replacement with OAuth2 path exclusion
- Add null/undefined handling in rewriteJsonResponse
- Add unit tests for consent utilities, card-consent functions, and rewrite
…consent flows

Add shared utility getConfigWithOAuth2Logo to override project logo with
OAuth2 client logo when available. Apply to Login, Registration, and Consent
flows to display the OAuth2 client's logo during OAuth2-initiated flows.
@Jorgagu Jorgagu force-pushed the feat/oauth2-consent-flow branch 2 times, most recently from 75d637e to 70b3e84 Compare February 3, 2026 12:34
Add security validation to prevent consent hijacking attacks where an
attacker could use a stolen consent_challenge to grant or reject consent
on behalf of a different user.

Changes:
- Pages Router: verify session cookie and compare identity with subject
- App Router: add identityId parameter to accept/reject functions
- Return 401 for missing session, 403 for identity mismatch
@Jorgagu Jorgagu force-pushed the feat/oauth2-consent-flow branch from 70b3e84 to 73020fc Compare February 3, 2026 12:43
@alamchrstn
Copy link

hi thanks for this contrib @Jorgagu ! this really helps our team to understand more context on the Ory FE stack here
wondering if we're looking to have this into main anytime soon @jonas-jonas ?

Copy link
Member

@jonas-jonas jonas-jonas left a comment

Choose a reason for hiding this comment

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

Thank you for this contribution! Overall it looks solid. I do have one note about the missing CSRF protection. Happy to discuss this in more detail, if needed!

consentChallenge={consentRequest}
session={session}
config={config}
csrfToken=""
Copy link
Member

Choose a reason for hiding this comment

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

The endpoints used in this component are susceptible to CSRF attacks. This is also the reason the consent screen is not yet part of the elements examples.

Since the <Consent /> component does not yet support server actions, the CSRF protection must be done through middleware. This is kind of awkward to implement, and there aren't many libraries out there that support this.

Ideally, we'd move the Consent screen to a server actions-based form submission because they're CSRF protected by default, but that would make support for the pages router impossible.

https://www.npmjs.com/package/@edge-csrf/nextjs?activeTab=readme is the best library for this (even though it is unmaintained, and vulnerable to subdomain attacks). Could you integrate that into this change?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hey @jonas-jonas, thanks for the review!

A few things worth noting about the current state:

  • The consent form submits via fetch() with Content-Type: application/json (line 161 of useOryFormSubmit.ts), so cross-origin CSRF is blocked by CORS preflight.
  • I've added server-side session identity validation on both routers so the server checks session.identity.id matches
    consentRequest.subject before processing.
  • The csrfToken="" is not validated anywhere server-side though, which is a gap if the submission mechanism ever changes.

Regarding @edge-csrf/nextjs, it uses the Naive Double-Submit Cookie Pattern (vulnerable to subdomain attacks) and the maintainer is looking to hand off the project (last stable release: October 2024).

Here are the options I see:

Approach Trade-offs
@edge-csrf/nextjs Subdomain vulnerability, uncertain maintenance
Signed Double Submit Cookie (custom) No dependency, works with both routers, no subdomain vulnerability (OWASP recommended)
Custom request header Simplest with fetch(), breaks if we ever switch to HTML form POST
Server Actions CSRF-protected by default, but kills Pages Router support

I'd lean toward the Signed Double Submit Cookie. What's your preference?

Copy link
Member

Choose a reason for hiding this comment

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

Thanks for the investigation.

Signed double submit seems like the best solution. However, we generally try not to reinvent the wheel (unless necessary!), and CSRF seems like a well-solved issue, so ideally we use a library to solve this. "Don't roll your own security" applies here.

However, when I last looked into this, there were few libraries that actually solved this for Next.js specifically. Do you know of any?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I looked into Next.js CSRF libraries that implement the Signed Double Submit Cookie pattern. Here's what I found:

Package Pattern Version Latest Release Monthly Downloads App Router Pages Router Status
@edge-csrf/nextjs Naive Double Submit v2.5.3 Nov 2024 117,278 Yes Yes Maintainer stepping down, subdomain vulnerability
next-csrf Synchronizer Token (stateful) v0.2.1 Apr 2022 23,608 No Yes Abandoned
@csrf-armor/nextjs Signed Double Submit (HMAC) v1.4.1 Feb 2026 694 Yes Yes Active
@simple-csrf/next Signed Double Submit v0.1.1 Apr 2025 176 Yes No Requires React 19

@csrf-armor/nextjs is the only library that checks all the boxes: Signed Double Submit (HMAC), both routers, Edge
Runtime compatible, zero dependencies, TypeScript, and CodeQL analysis. The adoption is low, but the code is auditable
and the core package (@csrf-armor/core) is framework-agnostic, which
could allow building a Nuxt adapter on top of it for the Vue/Nuxt side of ory-elements in the future.

What do you think about going with @csrf-armor/nextjs?

Copy link
Member

Choose a reason for hiding this comment

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

Thanks for the compilation. I think that's right; let's use @csrf-armor/nextjs here. Would you mind adjusting the examples to use the package?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

Comments