'How to handle sessions securely in SvelteKit

I'm fairly new to SvelteKit and I'm wondering how to properly handle sessions. From what I understand a unique session ID is typically stored in the browser as a cookie and this is linked to the currently signed in user backend. I'm used to PHP where all this is taken care of for you but that doesn't seem to be the case with SvelteKit.

This is what I've got so far:

/src/hooks.ts:

import cookie from 'cookie';
import { v4 as uuid } from '@lukeed/uuid';
import type { Handle } from '@sveltejs/kit';
import { getOrCreateSession } from '$lib/Authentication';

export const handle: Handle = async ({ event, resolve }) => {
    const cookies = cookie.parse(event.request.headers.get('cookie') || '');
    event.locals.userid = cookies.userid || uuid();

    const response = await resolve(event);

    if (!cookies.userid) {
        // if this is the first time the user has visited this app,
        // set a cookie so that we recognise them when they return
        response.headers.set(
            'set-cookie',
            cookie.serialize('userid', event.locals.userid, {
                path: '/',
                httpOnly: true
            })
        );
    }

    return response;
};

export async function getSession(event) : Promise<App.Session> {
    return getOrCreateSession(event.locals.userid);
}

/src/app.d.ts:

/// <reference types="@sveltejs/kit" />

// See https://kit.svelte.dev/docs/types#the-app-namespace
// for information about these interfaces
declare namespace App {
    interface Locals {
        userid: string;
    }

    // interface Platform {}

    interface Session {
        id: string;
        userId?: number;
    }

    // interface Stuff {}
}

/src/lib/Authentication.ts:

export let sessions: App.Session[] = [];

export async function getOrCreateSession(id: string) {
    let session = sessions.find(x => x.id === id);
    if(!session) {
        session = {
            id: id,
        };
        sessions.push(session);
    }
    return session;
}

/src/routes/setSession.svelte:

<script lang="ts" context="module">
    export async function load({ session }) {
        session.userId = 1;
        return {}
    }
</script>

/src/routes/getSession.svelte:

<script lang="ts" context="module">
    export async function load({ fetch, session }) {
        return {
            props: {
                session: session,
            }
        }
    }
</script>
<script lang="ts">
    export let session: App.Session;
</script>
{JSON.stringify(session)}

Visiting /setSession will set userId and it'll be retrieved when visiting /getSession.

  1. Is this the proper way to do this?
  2. Other than sessions not persisting on server restart, is there any other drawback storing the sessions in a variable instead of a database?
  3. Over time sessions will become quite large. To have an expiry date that's extended on each request would probably be a good idea but where would be a good place to put the code that remove all expired sessions?


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source