-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Are token cookies updated when getting the session in @auth/sveltekit
?
#8034
Comments
@auth/sveltekit
?
This comment was marked as off-topic.
This comment was marked as off-topic.
@balazsorban44 @ThangHuuVu - would you mind confirming if my understanding is correct here? AFAICT, it does not seem like cookies are handled in next-auth/packages/frameworks-sveltekit/src/lib/index.ts Lines 212 to 230 in d0dd2ab
@auth/core will return the cookies in response but then they aren't handled as only the status and body (.json() ) are read from that response?
I took a look at the NextJS implementation and it looks like there is more explicit cookie handling in next-auth/packages/next-auth/src/next/index.ts Lines 166 to 234 in d0dd2ab
I'd really appreciate if you have suggestions on workarounds (Cognito has max 1 day access token expiry so it's pretty much unusable without refreshes). One thought was to flag in the session when the token is refreshed and then try to manually overwrite the ( |
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
So I ran into this issue @torablien your analysis in your comment above is correct, when @kubieduber @torablien I was able to create a workaround by creating another function Here are details on my workaround: It uses a change to // src/routes/+layout.server.ts
import type { LayoutServerLoad } from "./$types"
export const load: LayoutServerLoad = async (event) => {
const sessionWithCookies = await event.locals.getSessionWithSetCookies();
for(const cookieName in sessionWithCookies?.cookies) {
const { value, options } = sessionWithCookies.cookies[cookieName]
event.cookies.set(cookieName, value, options)
}
return {
session: sessionWithCookies?.session
}
} And a patch to # patches/@auth+sveltekit+0.3.16.patch
diff --git a/node_modules/@auth/sveltekit/index.d.ts b/node_modules/@auth/sveltekit/index.d.ts
index 80a6b97..b223a79 100644
--- a/node_modules/@auth/sveltekit/index.d.ts
+++ b/node_modules/@auth/sveltekit/index.d.ts
@@ -223,6 +223,7 @@ declare global {
namespace App {
interface Locals {
getSession(): Promise<Session | null>;
+ getSessionWithSetCookies(): Promise<{ session: Session, cookies: Record<string, Record<string, string>>} | null>;
}
interface PageData {
session?: Session | null;
diff --git a/node_modules/@auth/sveltekit/index.js b/node_modules/@auth/sveltekit/index.js
index b383260..eeebaf3 100644
--- a/node_modules/@auth/sveltekit/index.js
+++ b/node_modules/@auth/sveltekit/index.js
@@ -203,7 +203,22 @@ import { dev } from "$app/environment";
import { base } from "$app/paths";
import { env } from "$env/dynamic/private";
import { Auth } from "@auth/core";
-export async function getSession(req, config) {
+
+const parseCookies = (cookies) => cookies.reduce((accumulator, cookie) => {
+ const headerValue = cookie.pop()
+
+ if(!headerValue) return;
+ const cookieParameters = headerValue.split(';')
+ const [name, value] = cookieParameters.shift()?.split('=') ?? [];
+ const options = cookieParameters.reduce((accumulator, parameter) => {
+ const [name, value] = parameter.split('=')
+ return {[name]: value ?? true, ...accumulator}
+ }, {});
+
+ return {[name]: {value, options}, ...accumulator}
+}, {})
+
+export async function getSessionWithSetCookies(req, config) {
config.secret ??= env.AUTH_SECRET;
config.trustHost ??= true;
const prefix = config.prefix ?? `${base}/auth`;
@@ -214,10 +229,19 @@ export async function getSession(req, config) {
const data = await response.json();
if (!data || !Object.keys(data).length)
return null;
- if (status === 200)
- return data;
+ if (status === 200) return {
+ session: data,
+ cookies: parseCookies(Array.from(response.headers).filter(([headerName]) => headerName === 'set-cookie'))
+ }
throw new Error(data.message);
}
+
+export async function getSession(req, config) {
+ const data = await getSessionWithSetCookies(req, config)
+
+ return data.session
+}
+
const actions = [
"providers",
"session",
@@ -236,6 +260,7 @@ function AuthHandle(svelteKitAuthOptions) {
const { prefix = `${base}/auth` } = authOptions;
const { url, request } = event;
event.locals.getSession ??= () => getSession(request, authOptions);
+ event.locals.getSessionWithSetCookies ??= () => getSessionWithSetCookies(request, authOptions);
const action = url.pathname
.slice(prefix.length + 1)
.split("/")[0]; |
@benjaminknox would love a pr of this! |
@benjaminknox I made a draft PR of your changes, but I'm having trouble with the |
I was able to successfully replicate @benjaminknox 's workaround with a few changes. if (status === 200) return {
session: data,
- cookies: parseCookies(Array.from(response.headers).filter(([headerName]) => headerName === 'set-cookie'))
+ cookies: parseCookies(response.headers.getSetCookie())
} I modified the interface SetCookie { value: string; options: CookieSerializeOptions & { path: string }; }
function camelize(str: string) {
return str.replace(/(?:^\w|[A-Z]|\b\w)/g, (word, index) => {
return index === 0 ? word.toLowerCase() : word.toUpperCase();
}).replace(/\s+/g, '');
}
const parseCookies = (cookies: string[]) => cookies.reduce((accumulator, headerValue) => {
if (!headerValue) {
return accumulator;
}
const cookieParameters = headerValue.split(';')
const [name, value] = cookieParameters.shift()?.split('=') ?? [];
const options = cookieParameters.reduce((accumulator2, parameter) => {
const [name, value] = parameter.split('=');
const camelCaseName = camelize(name.trim());
if (camelCaseName === 'expires') {
const expires = new Date(value);
return { ...accumulator2, expires };
}
return { ...accumulator2, [camelCaseName]: value ?? true };
}, { path: '/' });
return { [name]: { value, options }, ...accumulator }
}, {} as Record<string, SetCookie>); I also had to add a special case for Instead of setting the cookies in export function SvelteKitAuth2(
options: SvelteKitAuthConfig
): Handle {
const auth = SvelteKitAuth(options);
return async function ({ event, resolve }) {
let r: ReturnType<typeof getSessionWithSetCookies> | null = null;
event.locals.getSession = async () => {
if (!r) {
r = getSessionWithSetCookies(event.request, options).then(result => {
if (result?.cookies) {
for (const cookieName in result.cookies) {
const { value, options } = result.cookies[cookieName]
event.cookies.set(cookieName, value, options)
}
}
return result;
});
}
return r.then(result => result?.session ?? null);
};
const response = await auth({ event, resolve });
return response;
};
} |
Question 💬
I noticed that when my token expires, every subsequent request refreshes the token, seemingly because that refreshed token doesn't persist.
I found #7025 (comment) which states that
getServerSession
in theapp/
directory in NextJS only provides read access to cookies. Does the same apply to Sveltekit? Are there any workarounds so that we can support token refresh?How to reproduce ☕️
I've setup auth with Cognito with
@auth/sveltekit
per https://authjs.dev/guides/basics/refresh-token-rotation. When the token expires, observe the token be continually refreshed every time it is grabbed viagetSession()
with the expiry time of the original token, not the most recent refreshed token expiry time.Contributing 🙌🏽
Yes, I am willing to help answer this question in a PR
The text was updated successfully, but these errors were encountered: