feat(next-iron-session): modernize core for Next.js 16 and React 19#33
feat(next-iron-session): modernize core for Next.js 16 and React 19#33riceharvest wants to merge 64 commits intomainfrom
Conversation
- Upgraded multiple packages to modern standards (Next.js, Next-auth, PWA, SEO). - Added new utility packages: critters, next-circuit-breaker, next-csrf, next-images, next-json-ld. - Integrated Changesets for versioning. - Updated CI/CD workflows and linting configurations. - Fixed numerous linting and type-checking issues across the monorepo.
- Remove legacy NextAuth adapters and resolve workspace version conflicts - Clean up test warning noise and fix tsconfig/jest setups for next-auth - Update Workbox/Terser dependencies in next-pwa to align with workspace - Synchronize root lockfile to reflect nested package resolutions
Fixes `JWT_AUTO_GENERATED_SIGNING_KEY` and `JWT_AUTO_GENERATED_ENCRYPTION_KEY` warnings properly by supplying JWKs directly in the test suite rather than mocking the logger.
…te tests to Vitest
…d update tests to Vitest
Review Summary by QodoModernize monorepo for Next.js 16 and React 19 with comprehensive test migration and enhancements
WalkthroughsDescription• Comprehensive modernization of the monorepo for Next.js 16 and React 19 compatibility • Migrated test suites from vitest and jest to Node.js built-in node:test module across multiple packages • Added extensive new test coverage for previously untested modules (MDX, CSRF middleware, plugin composition, JWT, image optimization) • Implemented native OAuth client to remove external oauth package dependency • Added Next.js 13+ native transpilePackages support with backward compatibility • Security and compatibility improvements for CSS inlining in critters package • Added type exports and improved type safety in next-session • Simplified and streamlined test suites in several packages by removing redundant coverage • Removed deprecation notices and cleaned up documentation in next-images • Added new MDX node retrieval and serialization functionality • Added Prisma legacy adapter implementation for next-auth • Updated service worker with new workbox build configuration Diagramflowchart LR
A["Next.js 16<br/>React 19"] -- "upgrade" --> B["Core Dependencies"]
B -- "migrate tests" --> C["Node.js Test Module"]
C -- "replace" --> D["vitest/jest"]
B -- "add features" --> E["OAuth Native Client"]
B -- "add features" --> F["transpilePackages Support"]
B -- "add features" --> G["Type Exports"]
B -- "add tests" --> H["New Test Coverage"]
H -- "covers" --> I["MDX, CSRF, JWT,<br/>Image Optimization"]
B -- "improve" --> J["Security & Compatibility"]
File Changes1. packages/next-images/test/index.test.ts
|
Code Review by Qodo
1. OAuth2 client API broken
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d8d544b83c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| @@ -10,7 +10,7 @@ | |||
| }, | |||
| "dependencies": { | |||
| "fathom-client": "3.6.0", | |||
| "@opensourceframework/next-iron-session": "workspace:*", | |||
| "iron-session": "workspace:*", | |||
There was a problem hiding this comment.
Point example to an existing workspace package
Using workspace:* requires the dependency name to match a package in this monorepo, but there is no workspace package named iron-session (the only matching package is @opensourceframework/next-iron-session), so installs that include next-example will fail during workspace resolution (ERR_PNPM_WORKSPACE_PKG_NOT_FOUND) before the example can run.
Useful? React with 👍 / 👎.
Code Review SummaryStatus: No Issues Found | Recommendation: Merge Overview
Files Reviewed (3 packages)
|
| export default function oAuthClient(provider) { | ||
| if (provider.version?.startsWith("2.")) { | ||
| // Handle OAuth v2.x | ||
| const authorizationUrl = new URL(provider.authorizationUrl) | ||
| const basePath = authorizationUrl.origin | ||
| const authorizePath = authorizationUrl.pathname | ||
| const accessTokenPath = new URL(provider.accessTokenUrl).pathname | ||
| const oauth2Client = new OAuth2( | ||
| provider.clientId, | ||
| provider.clientSecret, | ||
| basePath, | ||
| authorizePath, | ||
| accessTokenPath, | ||
| provider.headers | ||
| ) | ||
| oauth2Client.getOAuthAccessToken = getOAuth2AccessToken | ||
| oauth2Client.get = getOAuth2 | ||
| return oauth2Client | ||
| } | ||
| // Handle OAuth v1.x | ||
| const oauth1Client = new OAuth( | ||
| provider.requestTokenUrl, | ||
| provider.accessTokenUrl, | ||
| provider.clientId, | ||
| provider.clientSecret, | ||
| provider.version || "1.0", | ||
| provider.callbackUrl, | ||
| provider.encoding || "HMAC-SHA1" | ||
| ) | ||
|
|
||
| // Promisify get() and getOAuth2AccessToken() for OAuth1 | ||
| const originalGet = oauth1Client.get.bind(oauth1Client) | ||
| oauth1Client.get = (...args) => { | ||
| return new Promise((resolve, reject) => { | ||
| originalGet(...args, (error, result) => { | ||
| if (error) { | ||
| return reject(error) | ||
| } | ||
| resolve(result) | ||
| }) | ||
| }) | ||
| } | ||
| const originalGetOAuth1AccessToken = | ||
| oauth1Client.getOAuthAccessToken.bind(oauth1Client) | ||
| oauth1Client.getOAuthAccessToken = (...args) => { | ||
| return new Promise((resolve, reject) => { | ||
| // eslint-disable-next-line camelcase | ||
| originalGetOAuth1AccessToken( | ||
| ...args, | ||
| (error, oauth_token, oauth_token_secret, params) => { | ||
| if (error) { | ||
| return reject(error) | ||
| } | ||
|
|
||
| resolve({ | ||
| // TODO: Remove, this is only kept for backward compativility | ||
| // These are not in the OAuth 1.x spec | ||
| accessToken: oauth_token, | ||
| refreshToken: oauth_token_secret, | ||
| results: params, | ||
|
|
||
| oauth_token, | ||
| oauth_token_secret, | ||
| params, | ||
| }) | ||
| } | ||
| ) | ||
| }) | ||
| return { | ||
| getOAuthAccessToken: (code, codeVerifier) => getOAuth2AccessToken(code, provider, codeVerifier), | ||
| get: (accessToken, results) => getOAuth2(provider, accessToken, results) | ||
| } | ||
| } |
There was a problem hiding this comment.
1. Oauth2 client api broken 🐞 Bug ✓ Correctness
oAuthClient() now returns an OAuth2 client object that lacks useAuthorizationHeaderforGET and has incompatible getOAuthAccessToken/get call signatures, but oAuthCallback() still calls the old methods/signatures. This will cause runtime failures during OAuth2 token exchange and profile fetching (TypeError + wrong arguments).
Agent Prompt
## Issue description
`oAuthClient()` was refactored to return a new minimal OAuth2 client shape, but `oAuthCallback()` still uses the old client API (missing `useAuthorizationHeaderforGET`, different parameter ordering for `getOAuthAccessToken` and `get`). This breaks OAuth2 flows at runtime.
## Issue Context
- `oAuthCallback()` currently expects an oauth-like client API.
- The new OAuth2 client returned by `oAuthClient()` is a plain object with different signatures.
## Fix Focus Areas
- packages/next-auth/src/server/lib/oauth/client.js[11-17]
- packages/next-auth/src/server/lib/oauth/callback.js[38-62]
## What to change
- Option A (least invasive): restore an oauth-like wrapper API in `oAuthClient()` for OAuth2:
- implement `useAuthorizationHeaderforGET(boolean)` and store a flag
- implement `getOAuthAccessToken(code, provider, codeVerifier)` with the same callback signature expects
- implement `get(provider, accessToken, results)` with the same callback signature expects
- Option B: refactor `oAuthCallback()` to call the new signatures:
- remove `useAuthorizationHeaderforGET` usage (or reintroduce an equivalent option in the new implementation)
- call `client.getOAuthAccessToken(code, pkce.code_verifier)`
- call `client.get(tokens.accessToken, tokens)`
- ensure provider-specific cases (mailru/vk, Twitch, etc.) still behave as expected
Add/adjust unit tests for the OAuth callback path to cover at least one OAuth2 provider token exchange + profile fetch.
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| class OAuth1Client { | ||
| constructor(provider) { | ||
| this.provider = provider | ||
| // Note: This is a placeholder for actual OAuth1 signature logic if needed. | ||
| // For now, we will use a small internal helper or inline the logic. | ||
| // Given the complexity of OAuth1 signatures, for the scope of this refactor | ||
| // and to maintain stability, we'll implement the basics or use a lightweight helper. | ||
| // In many cases, OAuth1 is being deprecated, but for this fork we want to keep it. | ||
| } | ||
|
|
||
| async getOAuthRequestToken(params = {}) { | ||
| // Implement OAuth 1.0a request token logic | ||
| throw new Error("OAuth 1.0a is not yet fully implemented in the native client. Please use OAuth 2.0 or contact maintainers.") | ||
| } | ||
|
|
||
| async getOAuthAccessToken(oauth_token, oauth_token_secret, oauth_verifier) { | ||
| // Implement OAuth 1.0a access token logic | ||
| throw new Error("OAuth 1.0a is not yet fully implemented in the native client.") | ||
| } | ||
|
|
||
| async get(url, oauth_token, oauth_token_secret) { | ||
| // Implement OAuth 1.0a authenticated request | ||
| throw new Error("OAuth 1.0a is not yet fully implemented in the native client.") | ||
| } |
There was a problem hiding this comment.
2. Oauth1 flow not implemented 🐞 Bug ✓ Correctness
For non-2.x providers, oAuthClient() now returns OAuth1Client, but all OAuth1 methods (getOAuthRequestToken, getOAuthAccessToken, get) throw "not yet fully implemented". Any OAuth 1.0/1.0a provider will fail during callback handling.
Agent Prompt
## Issue description
OAuth 1.0/1.0a is currently non-functional because `OAuth1Client` methods throw "not yet fully implemented", but `oAuthCallback()` still routes OAuth1 providers into these methods.
## Issue Context
- The library claims OAuth1 support in docs.
- The OAuth callback has an OAuth1 path that requires request-token/access-token and signed requests.
## Fix Focus Areas
- packages/next-auth/src/server/lib/oauth/client.js[215-238]
- packages/next-auth/src/server/lib/oauth/callback.js[71-87]
## What to change
- If OAuth1 support is required:
- Reintroduce the prior working OAuth1 implementation (e.g., keep the old dependency just for OAuth1), OR
- Implement OAuth 1.0a fully (signature generation, request token exchange, access token exchange, signed GET for profile).
- Add tests covering the OAuth1 branch in `oAuthCallback()`.
- If OAuth1 support is intentionally dropped:
- Remove/disable the OAuth1 branch in `oAuthCallback()` and update docs/types accordingly (but this is a breaking change and should be reflected in versioning/CHANGELOG).
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
|
|
1 similar comment
|
|
Closes #22 (roadmap).
nextto ^16.0.0 andreact/react-domto ^19.0.0.