pocketbase / js-sdk

PocketBase JavaScript SDK

Home Page:https://www.npmjs.com/package/pocketbase

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

SvelteKit SSR issues

SenneVanderAuwera opened this issue · comments

I can't seem to get SvelteKit SSR authentication to work. I've used the code provided in the documentation but the exportToCookie method does not work, even with secure and httpOnly set to false.

// src/hooks.server.js
import PocketBase from 'pocketbase';
import { PUBLIC_POCKETBASE } from '$env/static/public';

/** @type {import('@sveltejs/kit').Handle} */
export async function handle({ event, resolve }) {
    event.locals.pb = new PocketBase(PUBLIC_POCKETBASE);

    // load the store data from the request cookie string
    event.locals.pb.authStore.loadFromCookie(event.request.headers.get('cookie') || '');

    try {
        // get an up-to-date auth store state by verifying and refreshing the loaded auth model (if any)
        event.locals.pb.authStore.isValid && await event.locals.pb.collection('users').authRefresh();
    } catch (_) {
        // clear the auth store on failed refresh
        event.locals.pb.authStore.clear();
    }

    const response = await resolve(event);

    // send back the default 'pb_auth' cookie to the client with the latest store state
    response.headers.append('set-cookie', event.locals.pb.authStore.exportToCookie());

    return response;
}

What do you mean by "exportToCookie method does not work"?

If you ware testing on localhost, note that some browsers (eg. Safari) may require disabling the default secure cookie flag, aka.:

response.headers.append('set-cookie', event.locals.pb.authStore.exportToCookie({
    secure: false, // enable on prod
}));

Edit: On second read I see that you've mentioned that disabling the secure flags didn't work for you. In that case, please elaborate or create a minimal reproducible repo and I'll give it a try, otherwise I'm not sure how to reproduce it.

If i console log the result from the .exportToCookie() method the expire date is set to 01-01-1970, i think chrome automatically removes this cookie. What would be the expected outcome of the .exportToCookie() method?

Could you provide a more complete code sample?

How and where do you authenticate in the first place?

Ofcourse. I have tried some other things but still can't seem to get it to work. Here is the code i'm using:

hooks.server.ts:

// src/hooks.server.js
import PocketBase from 'pocketbase';

export const handle: Handle = async ({ event, resolve }) => {
	event.locals.pb = new PocketBase('http://localhost:8090');

	// load the store data from the request cookie string
	event.locals.pb.authStore.loadFromCookie(event.request.headers.get('cookie') || '');

	try {
		// get an up-to-date auth store state by verifying and refreshing the loaded auth model (if any)
		event.locals.pb.authStore.isValid && (await event.locals.pb.collection('users').authRefresh());
	} catch (_) {
		// clear the auth store on failed refresh
		event.locals.pb.authStore.clear();
	}

	const response = await resolve(event);

	// send back the default 'pb_auth' cookie to the client with the latest store state
	response.headers.append('set-cookie', event.locals.pb.authStore.exportToCookie());

	return response;
};

routes/login/+page.svelte:

<script lang="ts">
</script>

<div class="w-full flex min-h-full justify-center items-center">
	<form method="POST" class="flex flex-col">
		<input class="rounded border-2 border-primary" type="text" name="username" placeholder="Gebruikersnaam" />
		<input class="rounded border-2 border-primary" type="password" name="password" placeholder="Wachtwoord" />
		<button class="bg-primary text-white" type="submit">Log in</button>
	</form>
</div>

routes/login/+page.server.ts:

import type { Actions } from '@sveltejs/kit';

export const actions: Actions = {
	default: async ({ locals, request }) => {
		const formData = await request.formData();
		const username = formData.get('username') as string;
		const password = formData.get('password') as string;

		locals.pb
			.collection('users')
			.authWithPassword(username, password)
			.then((res) => {
				console.log(res);
			})
			.catch((err) => {
				console.log(err);
			});
	},
};

You are missing a return in the action (you need to return the Promise or await it before the hook.server.js is resolved), aka. try with:

import type { Actions } from '@sveltejs/kit';

export const actions: Actions = {
	default: async ({ locals, request }) => {
		const formData = await request.formData();
		const username = formData.get('username') as string;
		const password = formData.get('password') as string;

		return locals.pb
			.collection('users')
			.authWithPassword(username, password)
			.then((res) => {
				console.log(res);
			})
			.catch((err) => {
				console.log(err);
			});
	},
};

If that doesn't resolve your issue, feel free to let me know I'll try to setup a local Svelte project to test it.