⚒️ Encrypted "stateless" cookie sessions for SvelteKit
This SvelteKit backend utility allows you to create a session to be stored in the browser cookies via a encrypted seal. This provides strong client/"stateless" sessions.
The seal stored on the client contains the session data, not your server, making it a "stateless" session from the server point of view. This is a different take than express-session
where the cookie contains a session ID to then be used to map data on the server-side.
By default the cookie has an ⏰ expiration time of 7 days, set via [expires
] which should be a number
in days
.
Install into dependencies
npm i svelte-kit-cookie-session
yarn add svelte-kit-cookie-session
⚠️ Because of some vite issues #14 #15: you should add the following to yoursvelte.config
!
const config = {
kit: {
vite: {
optimizeDeps: {
exclude: ['svelte-kit-cookie-session'],
},
},
},
};
You can find an example implementation here Example.
The secret is a private key or list of private keys you must pass at runtime, it should be at least 32 characters
long. Use Password Generator to generate strong secrets.
src/hooks.ts || src/hooks/index.ts
import { handleSession } from "svelte-kit-cookie-session";
/** @type {import('@sveltejs/kit').GetSession} */
export async function getSession({ locals }) {
return locals.session.data;
}
// You can do it like this, without passing a own handle function
export const handle = handleSession({
secret: "SOME_COMPLEX_SECRET_AT_LEAST_32_CHARS",
});
// Or pass your handle function as second argument to handleSession
export const handle = handleSession(
{
secret: "SOME_COMPLEX_SECRET_AT_LEAST_32_CHARS",
},
({ request, resolve }) => {
// request.locals is populated with the session `request.locals.session`
// Do anything you want here
return resolve(request);
}
);
♻️ Secret rotation is supported. It allows you to change the secret used to sign and encrypt sessions while still being able to decrypt sessions that were created with a previous secret.
This is useful if you want to:
- rotate secrets for better security every two (or more, or less) weeks
- change the secret you previously used because it leaked somewhere (😱)
Then you can use multiple secrets:
Week 1:
export const handle = handleSession({
secret:
"SOME_COMPLEX_SECRET_AT_LEAST_32_CHARS",
});
Week 2:
export const handle = handleSession({
secret: [
{
id: 2,
secret: "SOME_OTHER_COMPLEX_SECRET_AT_LEAST_32_CHARS",
},
{
id: 1,
secret: "SOME_COMPLEX_SECRET_AT_LEAST_32_CHARS",
},
],
});
Notes:
id
is required so that we do not have to try every secret in the list when decrypting (theid
is part of the cookies value).- The secret used to encrypt session data is always the first one in the array, so when rotating to put a new secret, it must be first in the array list
- Even if you do not provide an array at first, you can always move to array based secret afterwards, knowing that your first password (
string
) was given{id:1}
automatically.
If the session already exists, the data get's updated but the expiration time stays the same
src/routes/login.ts
/** @type {import('@sveltejs/kit').RequestHandler} */
export async function post({ locals, body }) {
locals.session.data = body;
return {
body: locals.session.data,
};
}
src/routes/logout.ts
/** @type {import('@sveltejs/kit').RequestHandler} */
export async function del({ locals }) {
locals.session.destroy();
return {
body: {
ok: true,
},
};
}
src/routes/refresh.ts
/** @type {import('@sveltejs/kit').RequestHandler} */
export async function put({ locals, body }) {
locals.session.refresh(/** Optional new expiration time in days */);
return {
body: locals.session.data,
};
}
Note this currently only fires if a session is already existing
handleSession({
rolling: true,
});