Skip to content

Upgrade example app to Next.js 16, React 19, and AuthKit v4 (AUTH-6473) - #75

Open
Rmole57 wants to merge 3 commits into
mainfrom
rick-upgrade-to-next-16
Open

Upgrade example app to Next.js 16, React 19, and AuthKit v4 (AUTH-6473)#75
Rmole57 wants to merge 3 commits into
mainfrom
rick-upgrade-to-next-16

Conversation

@Rmole57

@Rmole57 Rmole57 commented Jul 29, 2026

Copy link
Copy Markdown

Summary

Upgrades the example app from Next.js 14.1.4 to 16.2.12, which pulls React 19 and
majors of both WorkOS SDKs along with it. All required migrations are applied here.

Dependencies

Package From To
next 14.1.4 16.2.12
react / react-dom ^18 ^19.2.0
@workos-inc/authkit-nextjs 0.4.2 ^4.3.0
@workos-inc/node ^6.7.0 ^10.8.0
eslint ^8 ^9
eslint-config-next 14.1.4 16.2.12
@types/react / @types/react-dom ^18 ^19

Breaking changes handled

Next.js 16

  • src/middleware.tssrc/proxy.ts, authkitMiddlewareauthkitProxy. Next 16 errors (E900) if both files exist.
  • Async request APIs are no longer available synchronously: searchParams is now Promise<…> in 7 pages, and cookies() is awaited in with-session/auth.ts. reset-password/page.tsx is a Client Component, so it unwraps via use(searchParams).
  • next lint was removed: .eslintrc.jsoneslint.config.mjs (flat config), lint script is now plain eslint.
  • tsconfig: target es5ES2017; Next's build also requires jsx: react-jsx and adds .next/dev/types.

React 19

  • useFormState (react-dom) → useActionState (react) across 8 components.

authkit-nextjs v4

  • getUser()withAuth(); added the now-required AuthKitProvider to the root layout.
  • Renamed WORKOS_REDIRECT_URINEXT_PUBLIC_WORKOS_REDIRECT_URI in .env.local.example and in using-hosted-authkit/README.md. v4 reads only the prefixed name.
  • getSignInUrl() writes a PKCE cookie, so Next 16 forbids calling it during render. The with-nextjs example now signs in via a POST Server Action instead of an <a href>.

@workos-inc/node v10

  • workos.mfaworkos.multiFactorAuth; userManagement.enrollAuthFactormultiFactorAuth.createUserAuthFactor; sendMagicAuthCodecreateMagicAuth.

Behavior change worth a look

sendPasswordResetEmail is gone. Its replacement, createPasswordReset, dropped the passwordResetUrl input and no longer sends an email — it mints the token and returns it, so delivery is now the application's responsibility. The example renders a labelled link to keep the flow clickable, and comments on why a real app must email the token instead. This is the one place where the example demonstrates something different than before, so it may warrant a product call rather than just a mechanical migration.

Also in this PR

  • Switched to npm as the single package manager: yarn.lock removed, package-lock.json added, README install step updated. The committed yarn.lock was in Yarn Berry format while Yarn 1 is what most environments resolve, so installs had been rewriting it inconsistently.
  • Added JWT_SECRET_KEY to .env.local.example — the with-session example already required it but it was undocumented.

Upgrading an existing local checkout

Only one step isn't covered by this PR, because the file is gitignored: rename WORKOS_REDIRECT_URI to NEXT_PUBLIC_WORKOS_REDIRECT_URI in your own .env.local (the value is unchanged). The old name is silently ignored, so auth fails with no clear error.

Testing

  • tsc --noEmit clean
  • eslint clean
  • next build green — 29/29 routes, proxy.ts detected
  • Dev smoke test: routes return 200; the reset-password flow renders correctly with and without a token

Closes AUTH-6473

@Rmole57 Rmole57 self-assigned this Jul 29, 2026
@Rmole57
Rmole57 marked this pull request as ready for review July 31, 2026 13:43
@Rmole57
Rmole57 requested a review from gjtorikian July 31, 2026 13:44
@Rmole57 Rmole57 changed the title Upgrade example app to Next.js 16, React 19, and AuthKit v4 Upgrade example app to Next.js 16, React 19, and AuthKit v4 (AUTH-6473) Jul 31, 2026
@linear-code

linear-code Bot commented Jul 31, 2026

Copy link
Copy Markdown

AUTH-6473

AUTH-6743

@greptile-apps

greptile-apps Bot commented Jul 31, 2026

Copy link
Copy Markdown

Greptile Summary

This PR upgrades the example application to Next.js 16, React 19, and current WorkOS SDK APIs.

  • Migrates middleware, asynchronous request APIs, React form actions, lint configuration, and package-manager metadata.
  • Adds AuthKit provider and proxy integration required by AuthKit v4.
  • Reworks the password-reset example around createPasswordReset and server-side token handling.

Confidence Score: 4/5

The PR is not yet safe to merge because password-reset bearer tokens are written to application logs and can be used to take over accounts.

The prior client-side token disclosure has been removed, but sendReset now logs the complete reset URL containing the token that resetPassword accepts with a caller-selected password.

Files Needing Attention: src/app/using-your-own-ui/reset-password/reset-password.ts

Security Review

The browser-visible reset-token exposure was removed, but the replacement writes the bearer token and complete reset URL to application logs. Anyone with access to those logs can reset the associated account. How this was verified: The token returned by createPasswordReset is interpolated into console.log and the same token is accepted by resetPassword with a caller-selected password.

Important Files Changed

Filename Overview
src/app/using-your-own-ui/reset-password/reset-password.ts Replaces browser disclosure with server logging of the password-reset bearer token, leaving account takeover possible for log readers.
src/app/using-your-own-ui/reset-password/page.tsx Stops rendering reset tokens or distinguishable account-existence responses in the client.
package.json Upgrades Next.js, React, WorkOS SDKs, ESLint, and associated type packages.
src/proxy.ts Migrates the AuthKit middleware convention to the Next.js 16 proxy API.

Sequence Diagram

sequenceDiagram
    participant U as Requester
    participant A as sendReset
    participant W as WorkOS
    participant L as Application logs
    participant R as resetPassword
    U->>A: Submit account email
    A->>W: createPasswordReset(email)
    W-->>A: passwordResetToken
    A->>L: Log complete reset URL and token
    L-->>U: Token visible to a log reader
    U->>R: Submit token and chosen password
    R->>W: resetPassword(token, newPassword)
Loading
Prompt To Fix All With AI
### Issue 1
src/app/using-your-own-ui/reset-password/reset-password.ts:33-38
**Reset token leaks through logs**

When a reset is created for an existing account, this code writes the bearer token and complete reset URL to application logs, allowing anyone with log access to submit the token with a chosen password and take over the account.

**How this was verified:** The token returned by `createPasswordReset` is interpolated into `console.log`, and `resetPassword` accepts that token with a caller-selected password.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (2): Last reviewed commit: "Stop returning the password reset token ..." | Re-trigger Greptile

Comment thread src/app/using-your-own-ui/reset-password/page.tsx Outdated
@Rmole57

Rmole57 commented Jul 31, 2026

Copy link
Copy Markdown
Author

@greptileai update

Comment on lines +33 to +38
console.log(
`[example] Password reset for ${reset.email} — in a real app, email this link:\n` +
` http://localhost:3000/using-your-own-ui/reset-password` +
`?token=${encodeURIComponent(reset.passwordResetToken)}` +
`&email=${encodeURIComponent(reset.email)}`
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 security Reset token leaks through logs

When a reset is created for an existing account, this code writes the bearer token and complete reset URL to application logs, allowing anyone with log access to submit the token with a chosen password and take over the account.

How this was verified: The token returned by createPasswordReset is interpolated into console.log, and resetPassword accepts that token with a caller-selected password.

Rule Used: Do not log sensitive fields like access_token, ref... (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/app/using-your-own-ui/reset-password/reset-password.ts
Line: 33-38

Comment:
**Reset token leaks through logs**

When a reset is created for an existing account, this code writes the bearer token and complete reset URL to application logs, allowing anyone with log access to submit the token with a chosen password and take over the account.

**How this was verified:** The token returned by `createPasswordReset` is interpolated into `console.log`, and `resetPassword` accepts that token with a caller-selected password.

**Rule Used:** Do not log sensitive fields like access_token, ref... ([source](https://app.greptile.com/workos/-/custom-context?memory=395edb09-f95b-4759-834f-94cb847721f5))

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

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.

yeah can you add a

if (process.env.NODE_ENV == 'development') { console.log(...) }

gate here, just in case?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Good call. Here's the suggestion:

Suggested change
console.log(
`[example] Password reset for ${reset.email} — in a real app, email this link:\n` +
` http://localhost:3000/using-your-own-ui/reset-password` +
`?token=${encodeURIComponent(reset.passwordResetToken)}` +
`&email=${encodeURIComponent(reset.email)}`
);
if (process.env.NODE_ENV === 'development') {
console.log(
`[example] Password reset for ${reset.email} — in a real app, email this link:\n` +
` http://localhost:3000/using-your-own-ui/reset-password` +
`?token=${encodeURIComponent(reset.passwordResetToken)}` +
`&email=${encodeURIComponent(reset.email)}`
);
}

This keeps the convenience for local dev while ensuring the token is never logged in staging or production environments where log access is less controlled.

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

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants