diff --git a/README.md b/README.md index bb291ee..1728e83 100644 --- a/README.md +++ b/README.md @@ -156,6 +156,44 @@ In the above example the `/admin` page will require a user to be signed in, wher `unauthenticatedPaths` uses the same glob logic as the [Next.js matcher](https://nextjs.org/docs/pages/building-your-application/routing/middleware#matcher). +### Middleware auth and server actions + +Using [server actions](https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations) with middleware auth mode can result in unexpected CORS errors if you don't wrap your server action call in a `try/catch` block. This is because a call to a server action without an existing session will be intercepted by the middleware and a redirect to AuthKit will be attempted, triggering a CORS error. + +Wrapping your server action call in a `try/catch` block will allow you to either display an error or redirect the user: + +```jsx +'use client'; + +import { serverFunction } from '../../server-function'; +import { useRouter } from 'next/navigation'; + +export default function TestPage() { + const router = useRouter(); + + const handleClick = async () => { + try { + const data = await serverFunction(); + + // Do something with data + } catch (e) { + // In the case of a CORS error, redirect user to login page + router.push('/login'); + } + }; + + return ( + <> + + + ); +} +``` + +For handling errors from the server action itself, refer to the [Next.js documentation](https://nextjs.org/docs/app/building-your-application/routing/error-handling). + ### Signing out Use the `signOut` method to sign out the current logged in user and redirect to your app's homepage. The homepage redirect is set in your WorkOS dashboard settings under "Redirect". diff --git a/package-lock.json b/package-lock.json index 29967f9..cc3521f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,7 +21,7 @@ "eslint": "^8.29.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-require-extensions": "^0.1.3", - "next": "^14.1.3", + "next": "^14.2.5", "typescript": "5.4.2", "typescript-eslint": "^7.2.0" }, @@ -174,15 +174,15 @@ "dev": true }, "node_modules/@next/env": { - "version": "14.2.2", - "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.2.tgz", - "integrity": "sha512-sk72qRfM1Q90XZWYRoJKu/UWlTgihrASiYw/scb15u+tyzcze3bOuJ/UV6TBOQEeUaxOkRqGeuGUdiiuxc5oqw==", + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.5.tgz", + "integrity": "sha512-/zZGkrTOsraVfYjGP8uM0p6r0BDT6xWpkjdVbcz66PJVSpwXX3yNiRycxAuDfBKGWBrZBXRuK/YVlkNgxHGwmA==", "dev": true }, "node_modules/@next/swc-darwin-arm64": { - "version": "14.2.2", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.2.tgz", - "integrity": "sha512-3iPgMhzbalizGwHNFUcGnDhFPSgVBHQ8aqSTAMxB5BvJG0oYrDf1WOJZlbXBgunOEj/8KMVbejEur/FpvFsgFQ==", + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.5.tgz", + "integrity": "sha512-/9zVxJ+K9lrzSGli1///ujyRfon/ZneeZ+v4ptpiPoOU+GKZnm8Wj8ELWU1Pm7GHltYRBklmXMTUqM/DqQ99FQ==", "cpu": [ "arm64" ], @@ -195,6 +195,134 @@ "node": ">= 10" } }, + "node_modules/@next/swc-darwin-x64": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.5.tgz", + "integrity": "sha512-vXHOPCwfDe9qLDuq7U1OYM2wUY+KQ4Ex6ozwsKxp26BlJ6XXbHleOUldenM67JRyBfVjv371oneEvYd3H2gNSA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.5.tgz", + "integrity": "sha512-vlhB8wI+lj8q1ExFW8lbWutA4M2ZazQNvMWuEDqZcuJJc78iUnLdPPunBPX8rC4IgT6lIx/adB+Cwrl99MzNaA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.5.tgz", + "integrity": "sha512-NpDB9NUR2t0hXzJJwQSGu1IAOYybsfeB+LxpGsXrRIb7QOrYmidJz3shzY8cM6+rO4Aojuef0N/PEaX18pi9OA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.5.tgz", + "integrity": "sha512-8XFikMSxWleYNryWIjiCX+gU201YS+erTUidKdyOVYi5qUQo/gRxv/3N1oZFCgqpesN6FPeqGM72Zve+nReVXQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.5.tgz", + "integrity": "sha512-6QLwi7RaYiQDcRDSU/os40r5o06b5ue7Jsk5JgdRBGGp8l37RZEh9JsLSM8QF0YDsgcosSeHjglgqi25+m04IQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.5.tgz", + "integrity": "sha512-1GpG2VhbspO+aYoMOQPQiqc/tG3LzmsdBH0LhnDS3JrtDx2QmzXe0B6mSZZiN3Bq7IOMXxv1nlsjzoS1+9mzZw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-ia32-msvc": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.5.tgz", + "integrity": "sha512-Igh9ZlxwvCDsu6438FXlQTHlRno4gFpJzqPjSIBZooD22tKeI4fE/YMRoHVJHmrQ2P5YL1DoZ0qaOKkbeFWeMg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.5.tgz", + "integrity": "sha512-tEQ7oinq1/CjSG9uSTerca3v4AZ+dFa+4Yu6ihaG8Ud8ddqLQgFGcnwYls13H5X5CPDPZJdYxyeMui6muOLd4g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1498,12 +1626,12 @@ "dev": true }, "node_modules/next": { - "version": "14.2.2", - "resolved": "https://registry.npmjs.org/next/-/next-14.2.2.tgz", - "integrity": "sha512-oGwUaa2bCs47FbuxWMpOoXtBMPYpvTPgdZr3UAo+pu7Ns00z9otmYpoeV1HEiYL06AlRQQIA/ypK526KjJfaxg==", + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/next/-/next-14.2.5.tgz", + "integrity": "sha512-0f8aRfBVL+mpzfBjYfQuLWh2WyAwtJXCRfkPF4UJ5qd2YwrHczsrSzXU4tRMV0OAxR8ZJZWPFn6uhSC56UTsLA==", "dev": true, "dependencies": { - "@next/env": "14.2.2", + "@next/env": "14.2.5", "@swc/helpers": "0.5.5", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001579", @@ -1518,15 +1646,15 @@ "node": ">=18.17.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "14.2.2", - "@next/swc-darwin-x64": "14.2.2", - "@next/swc-linux-arm64-gnu": "14.2.2", - "@next/swc-linux-arm64-musl": "14.2.2", - "@next/swc-linux-x64-gnu": "14.2.2", - "@next/swc-linux-x64-musl": "14.2.2", - "@next/swc-win32-arm64-msvc": "14.2.2", - "@next/swc-win32-ia32-msvc": "14.2.2", - "@next/swc-win32-x64-msvc": "14.2.2" + "@next/swc-darwin-arm64": "14.2.5", + "@next/swc-darwin-x64": "14.2.5", + "@next/swc-linux-arm64-gnu": "14.2.5", + "@next/swc-linux-arm64-musl": "14.2.5", + "@next/swc-linux-x64-gnu": "14.2.5", + "@next/swc-linux-x64-musl": "14.2.5", + "@next/swc-win32-arm64-msvc": "14.2.5", + "@next/swc-win32-ia32-msvc": "14.2.5", + "@next/swc-win32-x64-msvc": "14.2.5" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", diff --git a/package.json b/package.json index f436e59..8261933 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "eslint": "^8.29.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-require-extensions": "^0.1.3", - "next": "^14.1.3", + "next": "^14.2.5", "typescript": "5.4.2", "typescript-eslint": "^7.2.0" }, diff --git a/src/session.ts b/src/session.ts index c3e0c36..9d562d0 100644 --- a/src/session.ts +++ b/src/session.ts @@ -61,6 +61,18 @@ async function updateSession(request: NextRequest, debug: boolean, middlewareAut if (middlewareAuth.enabled && matchedPaths.length === 0 && !session) { if (debug) console.log('Unauthenticated user on protected route, redirecting to AuthKit'); + const serverAction = request.headers.get('next-action'); + + // If the request is a server action, then we're likely to run afoul of CORS protections + // as the request might have come from the client as a server function. + // In that case we warn the user and continue, which will likely result in a CORS error. + if (serverAction !== null) { + if (debug) + console.warn( + `🚫 Server action detected without a valid session in middleware auth mode. Make sure you catch the CORS error and either redirect or handle the error gracefully. See the authkit-nextjs readme for more information: https://github.com/workos/authkit-nextjs`, + ); + } + return NextResponse.redirect(await getAuthorizationUrl({ returnPathname: getReturnPathname(request.url) })); }