Skip to content
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

SvelteKit Auth + refresh token rotation not working as expected #6447

Open
nicklascarnegie opened this issue Jan 20, 2023 · 11 comments
Open
Labels
triage Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime.

Comments

@nicklascarnegie
Copy link

nicklascarnegie commented Jan 20, 2023

Environment

System:
    OS: macOS 13.1
    CPU: (10) arm64 Apple M1 Pro
    Memory: 121.16 MB / 32.00 GB
    Shell: 5.8.1 - /bin/zsh
  Binaries:
    Node: 18.9.0 - ~/.nvm/versions/node/v18.9.0/bin/node
    Yarn: 1.22.19 - /opt/homebrew/bin/yarn
    npm: 8.19.1 - ~/.nvm/versions/node/v18.9.0/bin/npm
  Browsers:
    Chrome: 109.0.5414.87
    Safari: 16.2

Reproduction URL

https://github.com/nicklasbondesson/sveltekitauth-token-rotation-demo

Describe the issue

I'm trying to implement refresh token rotation (JWT) based on the guide over here https://authjs.dev/guides/basics/refresh-token-rotation using the recently released SvelteKit Auth.

Once the access token has expired and is refreshed it seems that it is not remembered anymore, as shown below.

Here's the entry point to the demo code where it can be reproduced.

sveltekitauth-token-rotation-demo

How to reproduce

Follow the README in here https://github.com/nicklasbondesson/sveltekitauth-token-rotation-demo

Expected behavior

I think the expected behaviour would be that the refreshed token(s) would be remembered, just as it was on the initial login. If not, I would very much welcome some clarity around the matter.

@nicklascarnegie nicklascarnegie added the triage Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime. label Jan 20, 2023
@kai-ahmadov
Copy link

kai-ahmadov commented Jan 20, 2023

I've tried to follow the refresh token guideline as well, and I couldn't get the refreshed access_token to be persisted, which basically means that you have to refresh on every single request.
As far as I understand from the docs, on the server-side, the session is not persisted according to this.

DANGER
The session object is not persisted server side, even when using database sessions - only data such as the session token, the user, and the expiry time is stored in the session table.
If you need to persist session data server side, you can use the accessToken returned for the session as a key - and connect to the database in the session() callback to access it. Session accessToken values do not rotate and are valid as long as the session is valid.
If using JSON Web Tokens instead of database sessions, you should use the User ID or a unique key stored in the token (you will need to generate a key for this yourself on sign in, as access tokens for sessions are not generated when using JSON Web Tokens).

On the client side, it's persisted in a session cookie, but only once , on your initial login. Since you're refreshing from hooks.server.ts, I think you'd need to persist the session in a db

@nicklascarnegie nicklascarnegie changed the title SvelteKitAuth + refresh token rotation not working as expected SvelteKit Auth + refresh token rotation not working as expected Jan 21, 2023
@half2me
Copy link
Contributor

half2me commented Jan 24, 2023

I'm having the same issue. When you use the getSession() function, it doesn't persist any new jwt cookie that it receives.
My workaround is to not use the getSession() and instead just use something like this in my layout.server.ts

export const load: LayoutServerLoad = async ({ fetch }) => {
	const r = await fetch('/auth/session');
	const res = await r.json();
	console.log(res);
	return {
		session: res
	};
};

This actually persists the new jwt, so you don't keep refreshing the token on every request.
Also there is the case that your token can expire between page loads, and you might be relying on an access token to make an api call in the browser, but that token expires before you make a new call to your server to get a new jwt with the refreshed token.

So I like to also save the expiration time of the token, and schedule a function to run to invalidate it forcing a call to the server to refresh:

setTimeout(() => {
  // invalidate session, force fetch for new token
  invalidate('/auth/session');
}, expiration);

@bfbay315
Copy link

@half2me Just curious where you added the timer to refresh the token?

@half2me
Copy link
Contributor

half2me commented Dec 16, 2023

@half2me Just curious where you added the timer to refresh the token?

Just in my layout's onLoad()

I use Houdini to access a GraphQL API that needs this token to work. I also added an exception handler to the houdini client to detect 401 errors and retry the request with a new token, just in case the timer doesn't trigger. (When the device sleeps etc, it can happen)

@rbozan
Copy link

rbozan commented Feb 1, 2024

I'm having the same issue. When you use the getSession() function, it doesn't persist any new jwt cookie that it receives. My workaround is to not use the getSession() and instead just use something like this in my layout.server.ts

export const load: LayoutServerLoad = async ({ fetch }) => {
	const r = await fetch('/auth/session');
	const res = await r.json();
	console.log(res);
	return {
		session: res
	};
};

This actually persists the new jwt, so you don't keep refreshing the token on every request. Also there is the case that your token can expire between page loads, and you might be relying on an access token to make an api call in the browser, but that token expires before you make a new call to your server to get a new jwt with the refreshed token.

So I like to also save the expiration time of the token, and schedule a function to run to invalidate it forcing a call to the server to refresh:

setTimeout(() => {
  // invalidate session, force fetch for new token
  invalidate('/auth/session');
}, expiration);

Sorry but does this work? It seems like a dirty hack

@half2me
Copy link
Contributor

half2me commented Feb 1, 2024

@rbozan works fine for me 🤷 . If there is any better way to do it, I'm all ears.

@bfbay315
Copy link

bfbay315 commented Feb 1, 2024

I'm doing something similar. I'm not happy with it, but it's working.

In +layout.server.ts

export const load: LayoutServerLoad = async (event) => {
    return {
        session: await event.locals.getSession(),
    };
};

In layout.svelte

let timer: any = null;
let tokenExpirationMilliseconds = 0;

$: $page.data.session, refreshSession();

function refreshSession() {
	if (browser) {
		tokenExpirationMilliseconds = $page.data.session?.expires_in * 1000;
		if ($page.data.session?.error === "RefreshAccessTokenError") {
			logout()
		}else{
			if(!timer) {
				timer = setTimeout(() => {
					invalidateAll()
					timer = null;
				}, tokenExpirationMilliseconds)
			}
		}
	}
}

@half2me
Copy link
Contributor

half2me commented Feb 2, 2024

@bfbay315 yeah, in my case I only invalidate the auth endpoint instead of everything, but otherwise same idea. It works 🤷

@aakash14goplani
Copy link

aakash14goplani commented Feb 2, 2024

I think this was recently addressed - refer. You must be on or above v0.10.0 of @auth/sveltekit + you have to change event.locals.getSession() to event.locals.auth(). This new method updates cookies which helps resolving this issue. Unfortunately documentation is yet to be updated!

@kinglouie
Copy link

currently testing out authjs and the new event.locals.auth() function successfully updates the session jwt token when reloading the page. I am current facing the issue that I don't know what would be the best way to update the client side session for token rotation purposes?
The callbacks.session callback from SvelteKitAuth only runs serverside, it would nice if there was a authjs function to achieve something similar clientside.

@aakash14goplani
Copy link

Finally, I found solution for this issue: https://blog.aakashgoplani.in/how-to-implement-refresh-token-rotation-in-sveltekitauth

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
triage Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime.
Projects
None yet
Development

No branches or pull requests

7 participants