Open Enngage opened 2 weeks ago
Next.js is now officially live: https://nextjs.org/blog/next-15. It'd be great to have a fix for this as it's now breaking my authentication flow.
Fix please. Can't upgrade to nextjs 15 before fix
I see that this issue is already in-view, then I wasted my toime posting on Vercel's github about the issue.
Just for reference: here's what I get in the console:
Error: In route /api/auth/[auth0] a param property was accessed directly with
params.auth0.
paramsshould be awaited before accessing its properties. Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis
Hi all π We're working on adding support for the dynamic APIs in the upcoming v4 release of the SDK.
Hi all π We're working on adding support for the dynamic APIs in the upcoming v4 release of the SDK.
That's great to hear @guabu :) Do you by any chance have an estimation of when beta/release will be available?
That's great to hear @guabu :) Do you by any chance have an estimation of when beta/release will be available?
We're working to release the alpha version today and expect to release the beta shortly after (a few days or a couple of weeks at most).
Next 15 introduced some new breaking! updates, i fixed authentication easily, hint: use await
Hi all π We're working on adding support for the dynamic APIs in the upcoming v4 release of the SDK.
That's great to hear @guabu :) Do you by any chance have an estimation of when beta/release will be available?
I understand that we want to release something with SDK v4, but in the meantime, can we get something for people who don't want to migrate to latest Auth0/NextJS but just the latest NextJS?
Hi all π We've just released the v4 alpha which you could try out here.
I understand that we want to release something with SDK v4, but in the meantime, can we get something for people who don't want to migrate to latest Auth0/NextJS but just the latest NextJS?
We definitely plan to address some of the issues in v3 as we understand that not everyone can migrate right away. We did try to keep breaking changes to a minimum but there are certainly differences and we'll be providing a migration guide soon.
However, Next 15 support will most likely not land in v3 as it will require breaking changes.
However, Next 15 support will most likely not land in v3 as it will require breaking changes.
I would like to navigate this together! Based on my understanding (and I could be missing something), the only changes that would apply to Auth0/NextJS would be changing cookies()
and headers()
etc to have an await in front of them.
Based on my understanding of Javascript, await
-ing a non-Promise value is a no-op. So it's pretty safe to add that await and say, run Next.js v14 or v13 etc. So those changes would make v3 compatible across the board here.
Thoughts?
While the auth0 team works on an official solution, I was able to get a fork working with Next 15. Anyone who needs a drop-in solution today is welcome to use it.
bun add github:johncarmack1984/nextjs-auth0#bada487ceaace86195af774a5d361465cb3688d3
Here's a patch I created while we wait. Works for me on the dev server (am yet to push this to production) on @auth0/nextjs-auth 3.5.0 and nextjs 15.0.2-canary.5. Check out how to apply this patch here. Hope this helps someone.
diff --git a/node_modules/@auth0/nextjs-auth0/dist/auth0-session/session/stateful-session.js b/node_modules/@auth0/nextjs-auth0/dist/auth0-session/session/stateful-session.js
index 452c9bc..c05ca52 100644
--- a/node_modules/@auth0/nextjs-auth0/dist/auth0-session/session/stateful-session.js
+++ b/node_modules/@auth0/nextjs-auth0/dist/auth0-session/session/stateful-session.js
@@ -25,7 +25,7 @@ class StatefulSession extends abstract_session_1.AbstractSession {
async getSession(req) {
const config = await this.getConfig(req);
const { name: sessionName } = config.session;
- const cookies = req.getCookies();
+ const cookies = await req.getCookies();
const keys = await this.getKeys(config);
const sessionId = await (0, signed_cookies_1.getCookieValue)(sessionName, cookies[sessionName], keys);
if (sessionId) {
@@ -39,7 +39,7 @@ class StatefulSession extends abstract_session_1.AbstractSession {
const config = await this.getConfig(req);
const store = await this.getStore(config);
const { name: sessionName, genId } = config.session;
- const cookies = req.getCookies();
+ const cookies = await req.getCookies();
const keys = await this.getKeys(config);
let sessionId = await (0, signed_cookies_1.getCookieValue)(sessionName, cookies[sessionName], keys);
// If this is a new session created by a new login we need to remove the old session
@@ -64,7 +64,7 @@ class StatefulSession extends abstract_session_1.AbstractSession {
async deleteSession(req, res, cookieOptions) {
const config = await this.getConfig(req);
const { name: sessionName } = config.session;
- const cookies = req.getCookies();
+ const cookies = await req.getCookies();
const keys = await this.getKeys(config);
const sessionId = await (0, signed_cookies_1.getCookieValue)(sessionName, cookies[sessionName], keys);
if (sessionId) {
diff --git a/node_modules/@auth0/nextjs-auth0/dist/auth0-session/session/stateless-session.js b/node_modules/@auth0/nextjs-auth0/dist/auth0-session/session/stateless-session.js
index dac0705..3727a8f 100644
--- a/node_modules/@auth0/nextjs-auth0/dist/auth0-session/session/stateless-session.js
+++ b/node_modules/@auth0/nextjs-auth0/dist/auth0-session/session/stateless-session.js
@@ -55,7 +55,7 @@ class StatelessSession extends abstract_session_1.AbstractSession {
async getSession(req) {
const config = await this.getConfig(req);
const { name: sessionName } = config.session;
- const cookies = req.getCookies();
+ const cookies = await req.getCookies();
let existingSessionValue;
if (sessionName in cookies) {
// get JWE from un-chunked session cookie
@@ -96,7 +96,7 @@ class StatelessSession extends abstract_session_1.AbstractSession {
async setSession(req, res, session, uat, iat, exp, cookieOptions) {
const config = await this.getConfig(req);
const { name: sessionName } = config.session;
- const cookies = req.getCookies();
+ const cookies = await req.getCookies();
debug('found session, creating signed session cookie(s) with name %o(.i)', sessionName);
const [key] = await this.getKeys(config);
const value = await this.encrypt(session, { iat, uat, exp }, key);
@@ -123,7 +123,7 @@ class StatelessSession extends abstract_session_1.AbstractSession {
async deleteSession(req, res, cookieOptions) {
const config = await this.getConfig(req);
const { name: sessionName } = config.session;
- const cookies = req.getCookies();
+ const cookies = await req.getCookies();
for (const cookieName of Object.keys(cookies)) {
if (cookieName.match(`^${sessionName}(?:\\.\\d)?$`)) {
res.clearCookie(cookieName, cookieOptions);
diff --git a/node_modules/@auth0/nextjs-auth0/dist/auth0-session/transient-store.js b/node_modules/@auth0/nextjs-auth0/dist/auth0-session/transient-store.js
index 0cfd094..0931ae7 100644
--- a/node_modules/@auth0/nextjs-auth0/dist/auth0-session/transient-store.js
+++ b/node_modules/@auth0/nextjs-auth0/dist/auth0-session/transient-store.js
@@ -59,7 +59,7 @@ class TransientStore {
* @return {String|undefined} Cookie value or undefined if cookie was not found.
*/
async read(key, req, res) {
- const cookies = req.getCookies();
+ const cookies = await req.getCookies();
const cookie = cookies[key];
const config = await this.getConfig(req);
const cookieConfig = config.transactionCookie;
diff --git a/node_modules/@auth0/nextjs-auth0/dist/handlers/auth.js b/node_modules/@auth0/nextjs-auth0/dist/handlers/auth.js
index 28fa778..8b6e547 100644
--- a/node_modules/@auth0/nextjs-auth0/dist/handlers/auth.js
+++ b/node_modules/@auth0/nextjs-auth0/dist/handlers/auth.js
@@ -38,7 +38,7 @@ exports.default = handlerFactory;
*/
const appRouteHandlerFactory = (customHandlers, onError) => async (req, ctx) => {
const { params } = ctx;
- let route = params.auth0;
+ let route = (await params).auth0;
if (Array.isArray(route)) {
let otherRoutes;
[route, ...otherRoutes] = route;
diff --git a/node_modules/@auth0/nextjs-auth0/dist/http/auth0-next-request-cookies.js b/node_modules/@auth0/nextjs-auth0/dist/http/auth0-next-request-cookies.js
index 3f948e5..9eb445c 100644
--- a/node_modules/@auth0/nextjs-auth0/dist/http/auth0-next-request-cookies.js
+++ b/node_modules/@auth0/nextjs-auth0/dist/http/auth0-next-request-cookies.js
@@ -8,8 +8,11 @@ class Auth0NextRequestCookies extends http_1.Auth0RequestCookies {
getCookies() {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { cookies } = require('next/headers');
- const cookieStore = cookies();
- return cookieStore.getAll().reduce((memo, { name, value }) => (Object.assign(Object.assign({}, memo), { [name]: value })), {});
+ return cookies().then((cookieStore) => {
+ return cookieStore
+ .getAll()
+ .reduce((memo, { name, value }) => (Object.assign(Object.assign({}, memo), { [name]: value })), {});
+ });
}
}
exports.default = Auth0NextRequestCookies;
diff --git a/node_modules/@auth0/nextjs-auth0/dist/http/auth0-next-response-cookies.js b/node_modules/@auth0/nextjs-auth0/dist/http/auth0-next-response-cookies.js
index ea7e5e4..0df54c5 100644
--- a/node_modules/@auth0/nextjs-auth0/dist/http/auth0-next-response-cookies.js
+++ b/node_modules/@auth0/nextjs-auth0/dist/http/auth0-next-response-cookies.js
@@ -17,24 +17,30 @@ class Auth0NextResponseCookies extends http_1.Auth0ResponseCookies {
setCookie(name, value, options) {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { cookies } = require('next/headers');
- const cookieSetter = cookies();
- try {
- cookieSetter.set(Object.assign(Object.assign({}, options), { name, value }));
- }
- catch (_) {
- warn();
- }
+ cookies().then((cookieSetter) => {
+ try {
+ cookieSetter.set(
+ Object.assign(Object.assign({}, options), {
+ name,
+ value,
+ })
+ );
+ } catch (_) {
+ warn();
+ }
+ })
}
clearCookie(name, options) {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { cookies } = require('next/headers');
- const cookieSetter = cookies();
- try {
- cookieSetter.set(Object.assign(Object.assign({}, options), { name, value: '', expires: new Date(0) }));
- }
- catch (_) {
- warn();
- }
+ cookies().then((cookieSetter) => {
+ try {
+ cookieSetter.set(Object.assign(Object.assign({}, options), { name, value: '', expires: new Date(0) }));
+ }
+ catch (_) {
+ warn();
+ }
+ })
}
}
exports.default = Auth0NextResponseCookies;
diff --git a/node_modules/@auth0/nextjs-auth0/src/http/auth0-next-request-cookies.ts b/node_modules/@auth0/nextjs-auth0/src/http/auth0-next-request-cookies.ts
index dd93945..d06856d 100644
--- a/node_modules/@auth0/nextjs-auth0/src/http/auth0-next-request-cookies.ts
+++ b/node_modules/@auth0/nextjs-auth0/src/http/auth0-next-request-cookies.ts
@@ -8,13 +8,15 @@ export default class Auth0NextRequestCookies extends Auth0RequestCookies {
public getCookies(): Record<string, string> {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { cookies } = require('next/headers');
- const cookieStore = cookies();
- return cookieStore.getAll().reduce(
- (memo: Record<string, string>, { name, value }: { name: string; value: string }) => ({
+ return cookies().then((cookieStore) => {
+ console.log('cookieStore', cookieStore);
+ return cookieStore.getAll().reduce(
+ (memo: Record<string, string>, { name, value }: { name: string; value: string }) => ({
...memo,
[name]: value
}),
- {}
- );
+ {}
+ );
+ });
}
}
diff --git a/node_modules/@auth0/nextjs-auth0/src/http/auth0-next-response-cookies.ts b/node_modules/@auth0/nextjs-auth0/src/http/auth0-next-response-cookies.ts
index c690479..a511603 100644
--- a/node_modules/@auth0/nextjs-auth0/src/http/auth0-next-response-cookies.ts
+++ b/node_modules/@auth0/nextjs-auth0/src/http/auth0-next-response-cookies.ts
@@ -22,22 +22,25 @@ export default class Auth0NextResponseCookies extends Auth0ResponseCookies {
public setCookie(name: string, value: string, options?: CookieSerializeOptions) {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { cookies } = require('next/headers');
- const cookieSetter = cookies();
- try {
- cookieSetter.set({ ...options, name, value });
- } catch (_) {
- warn();
- }
+ cookies().then((cookieSetter) => {
+ try {
+ cookieSetter.set({ ...options, name, value });
+ } catch (_) {
+ warn();
+ }
+ });
}
public clearCookie(name: string, options?: CookieSerializeOptions) {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { cookies } = require('next/headers');
- const cookieSetter = cookies();
- try {
- cookieSetter.set({ ...options, name, value: '', expires: new Date(0) });
- } catch (_) {
- warn();
- }
+ cookies().then((cookieSetter) => {
+ try {
+ cookieSetter.set({ ...options, name, value: '', expires: new Date(0) });
+ } catch (_) {
+ warn();
+ }
+ })
+
}
}
Thanks @iansbrash
Here's a yarn patch for anyone using yarn >2 who also wants support now and doesn't want to use the v4 alpha
any updates / expected dates for when this issue will be resolved? quite significant blocker for us.
Hey all π We're currently discussing this and will share an update on whether we'll be adding support for Next 15 in v3 of the SDK or recommending the upgrade to v4.
We should have a more concrete answer this week!
Checklist
Describe the problem you'd like to have solved
Accessing cookies / headers is now
async
and the app fails if you access it synchronously in latest canary versions of next 15. More about the change is available within their docs - https://nextjs.org/docs/messages/sync-dynamic-apisDescribe the ideal solution
Implement async handling of cookies - https://nextjs.org/docs/messages/sync-dynamic-apis
Alternatives and current workarounds
There are no workarounds right now, other then staying on older versions of Next 15. Yeah, it's still a Canary version, but we expect to release it soon.
Additional context
No response