SvelteKit and Authentication—server- or client-side?

Struggling to know “the best way” of doing auth in a SvelteKit app. With Supabase, it appears you can run supabaseClient.auth.signIn({ email: form.email, password: form.password }); server- or client-side: 1. Send username and password to a server-side route (/api/login) which then runs supabaseClient.auth.signIn() server-side, gets back a user and session, registers session and returns data to client for Supabase to know who's logged in. (This is how I did my first SvelteKit + Supabase app according to https://www.youtube.com/watch?v=znZE6DEtVNs) 2. Do auth in the client, then send session object back to the server so that SvelteKit's backend can register session and then knows that the user is logged-in (or not), which helps with SSR protected routes (if not logged in, redirect to /login). This appears to be how most of the tutorials now are structured, but it feels kinda weird... Like, I feel the server should be the source of truth, not the web browser. Does this make any sense? Any thoughts or opinions?
Svelte Mastery
YouTube
Supabase & Sveltekit - Auth w/ Cookies 🍪 (Part 3.5)
So now we get into how to store the session with cookies which lets us have a much better redirect experience for users! Timestamps 0:00 - Intro 0:55 - App Overview 2:20 - Signup Code 4:04 - Set Cookie Code 5:58 - Get Cookie Code 7:17 - Redirect Code 8:37 - Logout Code 10:47 - Summary CODE https://github.com/sveltemaster/supasveltekit-cookies...
67 Replies
e0
e04y ago
SvelteKit just removed the session store actually. This is the proposal that lead up to it and it looks really nice imo. https://github.com/sveltejs/kit/discussions/5883 I just migrated my routes stuff yesterday and would like to rewrite the auth stuff today. Will try to post an update here is it turns out nice.
GitHub
Removing session · Discussion #5883 · sveltejs/kit
Update: session was removed in #5946 One of the great joys of designing APIs is the realisation, when you finally hit upon the right design, that previously hard problems become trivial to solve. A...
Waldemar
Waldemar4y ago
Following. I've been hacking around with Supabase Auth and SvelteKit for a few days now. And so far my understanding is: If you want to do auth or any sensitive user permissions related logic on the server side, there is this auth helper package from Supabase team, but I don't like that I have to wrap every call to Supabase into something like `withApi( ...select... ) and in general try to avoid using too many packages. If you can implement all your data security (i.e. RBAC) with RLS policies, you can just use the Auth on client-side. This is what I currently go with (also because I decided to use Astro instead of SvelteKit for our project). And if I can't do something with RLS, well, not sure what I will do.
e0
e04y ago
I have RLS but I still have doing most of my supabase calls server side. Much easier to get good SEO this way. I saw the withApi wrapper in the auth helper docs as well but I'm not using it at all. I'm passing the accessToken directly to the supabase related functions and you can use it directly with await supabaseServerClient(accessToken).from(... without the withApi wrapper. Anyhow.. the auth helper does not work with the latest changes as mentioned above (see https://github.com/supabase/auth-helpers/issues/230 for more details) so I'm currently reverting to not use the auth helper library and incorporating the new changes without session. Interesting that you decided to use Astro! I'm thinking about switching too but I would like to give the new svelte kit changes a more solid try first.
e0
e04y ago
Just saw that Rich posted a solution/workaround to make the auth helper (https://github.com/supabase/auth-helpers/tree/main/packages/sveltekit) work: https://github.com/sveltejs/kit/discussions/5883#discussioncomment-3430427 I already rewrote everything by myself without the auth helper for now but it's not clean atm so I won't share too much about that for now. Interested to see how the auth helper evolves after this flurry of changes for svelte kit.
GitHub
auth-helpers/packages/sveltekit at main · supabase/auth-helpers
A collection of framework specific Auth utilities for working with Supabase. - auth-helpers/packages/sveltekit at main · supabase/auth-helpers
GitHub
Removing session · Discussion #5883 · sveltejs/kit
Update: session was removed in #5946 One of the great joys of designing APIs is the realisation, when you finally hit upon the right design, that previously hard problems become trivial to solve. A...
stukennedy
stukennedy4y ago
Yeah I’m still trying to figure out how he means to use this Do you still use the auth helper code in the hooks.ts? Would be nice to get away from using the Auth Helper altogether and just write the session cookie in an endpoint. Then the load function can provide the user to any page wanting it, no need for the Front End provider at all then
e0
e04y ago
I have personally removed the auth helper for now because I'm impatient. The new changes with +layout.server.ts makes it really straightforward to implement. The bonus super nice thing is that after these changes, I no longer need the hooks.ts and app.d.ts files. The following is the gist of what I did. 1. Add a route at src/routes/api/auth/+server.ts, in which I have a POST function defined. Here I read the accessToken and refreshToken, which are sent from the function in the next step. If the tokens are provided, we set the cookie headers that are then sent back to the client and added to the browser. 2. Whenever the supabase session data changes (eg. after sign-in, sign-out, or refresh etc), I post the access and refresh tokens to the route from step 1. The function looks like the following (the type Session here is from import type { Session } from '@supabase/gotrue-js';).
const setServerSession = async (session: Session | null) => {
const payload: { accessToken?: string; refreshToken?: string } = {};

if (session) {
payload.accessToken = session.access_token;
payload.refreshToken = session.refresh_token;
}

await fetch('/api/auth', {
method: 'POST',
credentials: 'same-origin',
body: JSON.stringify(payload)
});
};
const setServerSession = async (session: Session | null) => {
const payload: { accessToken?: string; refreshToken?: string } = {};

if (session) {
payload.accessToken = session.access_token;
payload.refreshToken = session.refresh_token;
}

await fetch('/api/auth', {
method: 'POST',
credentials: 'same-origin',
body: JSON.stringify(payload)
});
};
Let me know if this doesn't make sense and I would be happy to provide more details.
stukennedy
stukennedy4y ago
Thanks so much for this, just trying to get my head around it all. So if you’ve removed auth-helper stuff, how do you call Supabase with the token from the server side?
stukennedy
stukennedy4y ago
Rich mentions being able to use the handle method to write to the locals variable … is this easier? I’m just not getting how this hangs together. What happens when my magic link is resolved to the redirectTo path? How do I get the session from that and set it in the app so I can access it from the locals variable in all my server side code? https://github.com/sveltejs/kit/discussions/5883#discussioncomment-3393658
GitHub
Removing session · Discussion #5883 · sveltejs/kit
Update: session was removed in #5946 One of the great joys of designing APIs is the realisation, when you finally hit upon the right design, that previously hard problems become trivial to solve. A...
e0
e04y ago
Once the cookies get added to the browser following the previous steps, the cookies will be available on the subsequent requests and I have a helper function like this that I use in +layout.server.ts.
import { parse } from 'cookie';

const getAccessToken = (request: Request) => {
const cookies = parse(request.headers.get('cookie') || '');
return cookies['sb-access-token'] || null;
};
import { parse } from 'cookie';

const getAccessToken = (request: Request) => {
const cookies = parse(request.headers.get('cookie') || '');
return cookies['sb-access-token'] || null;
};
Then in the same layout file you want to include the accessToken along with the user as similar to how Rich described in: https://github.com/sveltejs/kit/discussions/5883#discussion-4302953.
export const load: LayoutServerLoad = async ({ request }) => {
const accessToken = getAccessToken(request);

if (!accessToken) {
return {};
}

const [user, extraUserData] = await Promise.all([
getUserByToken(accessToken),
getExtraUserData(accessToken)
]);

return {
user: {
...user,
...extraUserData
},
accessToken
};
};
export const load: LayoutServerLoad = async ({ request }) => {
const accessToken = getAccessToken(request);

if (!accessToken) {
return {};
}

const [user, extraUserData] = await Promise.all([
getUserByToken(accessToken),
getExtraUserData(accessToken)
]);

return {
user: {
...user,
...extraUserData
},
accessToken
};
};
Now in the +page.server.ts files, you can get the accessToken using: const { accessToken } = await parent();. From here you can use the setAuth function (https://supabase.com/docs/reference/javascript/auth-setauth) from supabase-js with the accessToken. Be careful here because as mentioned in the docs: "The JWT will then be sent in all subsequent network requests.". So you want to make sure that you are creating a new instance using createClient each time.
setAuth() | Supabase
Overrides the JWT on the current client. The JWT will then be sent in all subsequent network requests.
GitHub
Removing session · Discussion #5883 · sveltejs/kit
Update: session was removed in #5946 One of the great joys of designing APIs is the realisation, when you finally hit upon the right design, that previously hard problems become trivial to solve. A...
e0
e04y ago
I have not explored this alternative. I imagine the only difference from the method I described above is that you don't have to do const { accessToken } = await parent();. I prefer being explicit about it though and opt-in for the routes I need instead.
stukennedy
stukennedy4y ago
Thanks so much … I’d actually ended up with the same solution as you (minus the user data) last night, but I can’t figure out how to handle expired tokens and force the refresh. Totally baffled by all of this ... is there a step by step about how this supabase auth works? When you click the link in the magic link email it hits an endpoint in supabase, what does it do next? I'm guessing the redirectTo is where it goes AFTER it's been verified, but how does it do that? Is there a specific endpoint on the client app that it's expecting to hit which then extracts the data from the URL and stores it as cookies. I understand how once we've got cookies to pass them around the app, but how do you get to that stage? Also how do you deal with expired tokens etc. Or are you still using AuthHelpers for some stuff?
garyaustin
garyaustin4y ago
Using magiclink comes back to your app at the redirectTo address. The supabase client code will look at the url for a token and then onAuthStateChanged will be fired with a SIGNED_IN event. It also sets up the session and stores that to localstorage.
stukennedy
stukennedy4y ago
... let me clarify my confusion 🤣 I understand everything you explained about getting the cookies from the req.header and passing them around and using them, I just don't understand how we get those cookies, how we create them. You mentioned that you post them to setServerSession but where do you get session from e.g. in the login function ... and how does the POST function in api/auth/+server.ts set the cookies in browser storage? I think that's all I'm missing. I think the access token comes back as a hash parameter in the URL, but I can't find info on that. Apologies for the stupidity here, just not used to dealing with low-level auth stuff. Hi Gary, sure ... but we're trying to solve this the SSR way ... using the endpoints, not using the JS onAuthStateChanged handler which subscribes to events. We should be able to pull the data out of the URL ourselves, store the cookies and use them in the server endpoints, without needing to use any async stuff.
jensen
jensen4y ago
I haven't found a solution that works with the managed service. The only way I've gotten full server-side auth is with changes to gotrue and self hosting.
garyaustin
garyaustin4y ago
https://discord.com/channels/839993398554656828/1007998446315241617/1008076722299736094 implies you have to have browser code for magic link. But I've not read thru the entire thread here, (don't use server side stuff) so certainly don't have the full context of the thread.
stukennedy
stukennedy4y ago
what's in your api/auth/+server.ts file to save the cookies to the browser? Just cannot figure it out. Spent hours on this now 😬 I've got it getting the tokens, calling the endpoint. I've got it reading the tokens stored in the cookies and using them. I just can't update the cookies with the ones that have just been served. I'm using your setServerSession approach and calling a POST metho in /api/auth/+server.ts ... tried doing
import type { RequestEvent } from './$types';
import { serialize } from 'cookie';

export async function POST({ request }: RequestEvent) {
const { accessToken, refreshToken } = await request.json();
setHeaders({
'set-cookie': serialize('sb-access-token', accessToken)
});
})
import type { RequestEvent } from './$types';
import { serialize } from 'cookie';

export async function POST({ request }: RequestEvent) {
const { accessToken, refreshToken } = await request.json();
setHeaders({
'set-cookie': serialize('sb-access-token', accessToken)
});
})
it sets a new cookie alongside the old one, with the same name sb-access-token but it doesn't get read when I get('cookie') in +layout.server.ts load method
e0
e04y ago
Hi! Just got off work and catching up on this thread. This is what my /routes/api/auth/+server.ts looks like. Sorry it's not very DRY but it's easy for me to read.
export const POST = async ({ request }) => {
const { accessToken, refreshToken } = await request.json();
const headers = new Headers();
if (accessToken) {
headers.append(
'set-cookie',
`sb-access-token=${accessToken}; HttpOnly; Path=/;; Max-Age=${60 * 60 * 24 * 7}`
);
headers.append(
'set-cookie',
`sb-refresh-token=${refreshToken}; HttpOnly; Path=/;; Max-Age=${60 * 60 * 24 * 365}`
);
} else {
headers.append('set-cookie', `sb-access-token=; HttpOnly; Path=/;; Max-Age=-1`);
headers.append('set-cookie', `sb-refresh-token=; HttpOnly; Path=/;; Max-Age=-1`);
}

return new Response(null, { headers });
};
export const POST = async ({ request }) => {
const { accessToken, refreshToken } = await request.json();
const headers = new Headers();
if (accessToken) {
headers.append(
'set-cookie',
`sb-access-token=${accessToken}; HttpOnly; Path=/;; Max-Age=${60 * 60 * 24 * 7}`
);
headers.append(
'set-cookie',
`sb-refresh-token=${refreshToken}; HttpOnly; Path=/;; Max-Age=${60 * 60 * 24 * 365}`
);
} else {
headers.append('set-cookie', `sb-access-token=; HttpOnly; Path=/;; Max-Age=-1`);
headers.append('set-cookie', `sb-refresh-token=; HttpOnly; Path=/;; Max-Age=-1`);
}

return new Response(null, { headers });
};
stukennedy
stukennedy4y ago
Perfect, works a treat. Gonna try and simplify it and write it up. Getting weird type problems with RequestEvent and parent, need to figure that out. I've used the src/hooks.ts file to set the locals variable instead of setting the response on the +layout.server.ts and then having to use const {accessToken} = await parent() in each of the load handlers ... I can just get it from locals.accessToken
// src/hooks.ts
import type { RequestEvent } from '@sveltejs/kit';
import { parse } from 'cookie';

export async function handle({ event, resolve }: RequestEvent) {
const cookies = parse(event.request.headers.get('cookie') || '');
const accessToken = cookies['sb-access-token'];
event.locals.accessToken = accessToken;
return resolve(event);
}
// src/hooks.ts
import type { RequestEvent } from '@sveltejs/kit';
import { parse } from 'cookie';

export async function handle({ event, resolve }: RequestEvent) {
const cookies = parse(event.request.headers.get('cookie') || '');
const accessToken = cookies['sb-access-token'];
event.locals.accessToken = accessToken;
return resolve(event);
}
I'm still getting weird Typescript errors with RequestEvent ... I also tried importing it from './$types' I just get a different TS error
e0
e04y ago
I use TS too but I didn't get any lint warnings about not specifying the types in this file. Try to take it (type imports) out and see what happens? There is a lot of magic type goodies with these new svelte kit changes. Other than that I have not been able to keep up with all the new changes. Maybe it's best to just lay low for a couple of weeks. I'm checking out astro in the mean time because I just don't like the routing change esthetics. Might stick with svelte kit anyways for the type magic though.
stukennedy
stukennedy4y ago
Okay finally got there with all this ... I wrote it up as I went, hopefully someone else can benefit
stukennedy
stukennedy4y ago
Stu's Notion on Notion
Sveltekit + Supabase Magic Link Auth using SSR
Sveltekit encourages a progressive enhancement approach to webapp development by leveraging the power of SSR (Server-side rendering). Supabase is an excellent platform that provides storage, realtime DB, DB, edge functions and Auth out of the box and with minimal integration. Implementing Auth correctly is a non-trivial problem.
e0
e04y ago
Thanks for sharing. I browsed through it a bit. In the code block of the "Making authenticated Supabase calls from endpoints" section, how is it making an authenticated call based on the current user?
Smardrengr
SmardrengrOP4y ago
Same here. SSR is just a nicer user experience, but it isn't easy or obvious (to me). Working on it... Yeah, I don't like their auth helpers either. They seem (sorry to be blunt)... ugly.
stukennedy
stukennedy4y ago
the hooks.ts file handles auth changes and sets the supabase auth context supabase.auth.setAuth(accessToken); ... so any subsequent calls should use that (unless I've misunderstood how this hangs together and I should be getting the accessToken before every API call and calling setAuth? )
e0
e04y ago
Ah I see. Sorry I missed that bit. That sounds like it makes sense. I do vaguely remember the sessions getting leaked during testing at some point for my app though but not sure if it was because of this. Guess you can always test a bit with RLS and different users.
ak4zh
ak4zh3y ago
GitHub
auth-helpers/packages/sveltekit at main · supabase/auth-helpers
A collection of framework specific Auth utilities for working with Supabase. - auth-helpers/packages/sveltekit at main · supabase/auth-helpers
Smardrengr
SmardrengrOP3y ago
No. Because Rich & Co. removed session. I'm trying to figure out how to make my app work again. Grr.
Waldemar
Waldemar3y ago
Another thing regarding the code under "Making authenticated Supabase calls from endpoints": can this block:
} catch {
return {
status: 303,
location: '/login'
};
}
} catch {
return {
status: 303,
location: '/login'
};
}
be abstracted away? Where would you move it? It looks like this is needed every time you call Supabase to select/insert etc....?
Smardrengr
SmardrengrOP3y ago
@Waldemar I don't know. The “simple” thing I want to do is redirect users from /profile to /login if a session is not set. Maybe we should code-pair.
Max52
Max523y ago
Read here for exactly how to modify your auth helper code to work with the latest SK. https://github.com/supabase/auth-helpers/issues/230
GitHub
SvelteKit removed Session store · Issue #230 · supabase/auth-helpers
Bug report Describe the bug The latest version of SvelteKit removes the Session store, breaking the Svelte and SvelteKit auth helpers. See: sveltejs/kit#5883 (comment) Expected behavior Be able to ...
Smardrengr
SmardrengrOP3y ago
Will look another look. I want to do server-side auth for SSR...
MrMendez
MrMendez3y ago
i'm deep stuck on this does it works? I'm trying to follow throw but not working for me
Smardrengr
SmardrengrOP3y ago
I pressed pause on this last week until more of Internet figures things out. What I did was watch https://www.youtube.com/watch?v=LMTfzyVJIXs (excellent) then started a new SvelteKit project and figure out how cookies are persisted in hooks.js.
James Q Quick
YouTube
SvelteKit Breaking Changes 2022 - My Reactions and What You Need to...
SvelteKit just announced some major breaking changes. Here's what you need to know! Migrating Breaking Changes in SvelteKit - https://www.netlify.com/blog/migrating-breaking-changes-in-sveltekit/ What's New in Svelte - https://svelte.dev/blog/whats-new-in-svelte-august-2022 Routing Docs - https://kit.svelte.dev/docs/routing#page-page-js Github ...
MrMendez
MrMendez3y ago
I'm following this guiide from @stukennedy https://stukennedy.notion.site/Sveltekit-Supabase-Magic-Link-Auth-using-SSR-08a94511da3e43c9b49ed6ce1f292e38, i get logged in but not cookies get saved and just get redirected back to the auth page i'm checking supabase logs to check if the login when through, there is no error message
MrMendez
MrMendez3y ago
this code never gets executed
No description
stukennedy
stukennedy3y ago
hey guys sorry been deep in other stuff. Yeah I got it working. Lemme go back to my notion and update it
stukennedy
stukennedy3y ago
Stu's Notion on Notion
Sveltekit + Supabase Magic Link Auth using SSR
Sveltekit encourages a progressive enhancement approach to webapp development by leveraging the power of SSR (Server-side rendering). Supabase is an excellent platform that provides storage, realtime DB, DB, edge functions and Auth out of the box and with minimal integration. Implementing Auth correctly is a non-trivial problem.
stukennedy
stukennedy3y ago
okay try that now if it doesn't work, please let me know I've put it on a webpage
stukennedy
stukennedy3y ago
Stu's Notion on Notion
Sveltekit + Supabase Magic Link Auth using SSR
Sveltekit encourages a progressive enhancement approach to webapp development by leveraging the power of SSR (Server-side rendering). Supabase is an excellent platform that provides storage, realtime DB, DB, edge functions and Auth out of the box and with minimal integration. Implementing Auth correctly is a non-trivial problem.
Smardrengr
SmardrengrOP3y ago
Hi @stukennedy, do you have a variation that is not MagicLink, but regular username + password auth()? I will look at your example, maybe there's enough logic in common. Thanks for sharing!
stukennedy
stukennedy3y ago
that should be a LOT simpler actually maybe not, you may still have to jump through all the hoops to get the cookies set etc
Smardrengr
SmardrengrOP3y ago
Yes, my issue up until now is setting the cookie server-side and redirecting to /login when there is no session. I'll read your code and see what happens.
stukennedy
stukennedy3y ago
I'd imagine you just copy my code then add a password field
Smardrengr
SmardrengrOP3y ago
I'd like to avoid Supabase's auth helpers. The context thing is ugly. Right.
stukennedy
stukennedy3y ago
yeah I think it'll be exactly the same as my code only add a password input to the login page you'd get the password value through the formData the same as I did for email and then just call
const response = await supabase.auth.signIn(
{ email, password },
{ redirectTo: `${url.origin}/logging-in` }
);
const response = await supabase.auth.signIn(
{ email, password },
{ redirectTo: `${url.origin}/logging-in` }
);
that's a guess (not tested) obviously though with password you need the whole signup and forgot password journeys I love magic link
Smardrengr
SmardrengrOP3y ago
Yeah I'm re-thinking password, maybe just MagicLink is better. @stukennedy Read through, looks really good. Excited to try it. Thanks for the post.
stukennedy
stukennedy3y ago
no problem ... do let me know if you get stuck
MrMendez
MrMendez3y ago
i got it working with magic link but nos password, i'll try again, i need passwords because magic link is not feasible for my client/project but thanks a lot for helping out the redirectTo is being ignore by supabase so the its always redirecting to root / never mind, it for some reason its working now 🙃
Smardrengr
SmardrengrOP3y ago
Why is it being ignored?
stukennedy
stukennedy3y ago
RedirectTo only works if you have the same url in the list of Redirect URLs in the Supabase Authentication settings on their dashboard http://localhost:3000/logging-in (I force VITE to make it port 3000 otherwise this messed up)
Smardrengr
SmardrengrOP3y ago
Hmm, I applied @stukennedy Notion article code, but get the following error on /login:
Cannot read properties of undefined (reading 'auth')
TypeError: Cannot read properties of undefined (reading 'auth')
at Object.handle (/Users/rene/Sites/me/side/gameonornot/app/src/hooks.ts:9:10)
at respond (file:///Users/rene/Sites/me/side/gameonornot/app/node_modules/@sveltejs/kit/src/runtime/server/index.js:202:40)
at runMicrotasks (<anonymous>)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async file:///Users/rene/Sites/me/side/gameonornot/app/node_modules/@sveltejs/kit/src/vite/dev/index.js:399:22
{"status":303,"location":"/login"}
Error: {"status":303,"location":"/login"}
at coalesce_to_error (file:///Users/rene/Sites/me/side/gameonornot/app/node_modules/@sveltejs/kit/src/utils/error.js:11:5)
at respond_with_error (file:///Users/rene/Sites/me/side/gameonornot/app/node_modules/@sveltejs/kit/src/runtime/server/page/respond_with_error.js:85:17)
at runMicrotasks (<anonymous>)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async respond (file:///Users/rene/Sites/me/side/gameonornot/app/node_modules/@sveltejs/kit/src/runtime/server/index.js:418:11)
at async file:///Users/rene/Sites/me/side/gameonornot/app/node_modules/@sveltejs/kit/src/vite/dev/index.js:399:22
Cannot read properties of undefined (reading 'auth')
TypeError: Cannot read properties of undefined (reading 'auth')
at Object.handle (/Users/rene/Sites/me/side/gameonornot/app/src/hooks.ts:9:10)
at respond (file:///Users/rene/Sites/me/side/gameonornot/app/node_modules/@sveltejs/kit/src/runtime/server/index.js:202:40)
at runMicrotasks (<anonymous>)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async file:///Users/rene/Sites/me/side/gameonornot/app/node_modules/@sveltejs/kit/src/vite/dev/index.js:399:22
{"status":303,"location":"/login"}
Error: {"status":303,"location":"/login"}
at coalesce_to_error (file:///Users/rene/Sites/me/side/gameonornot/app/node_modules/@sveltejs/kit/src/utils/error.js:11:5)
at respond_with_error (file:///Users/rene/Sites/me/side/gameonornot/app/node_modules/@sveltejs/kit/src/runtime/server/page/respond_with_error.js:85:17)
at runMicrotasks (<anonymous>)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async respond (file:///Users/rene/Sites/me/side/gameonornot/app/node_modules/@sveltejs/kit/src/runtime/server/index.js:418:11)
at async file:///Users/rene/Sites/me/side/gameonornot/app/node_modules/@sveltejs/kit/src/vite/dev/index.js:399:22
hooks.ts looks like
// src/hooks.ts
import { supabase } from '$lib/db';
import { parse } from 'cookie';
import type { Handle } from '@sveltejs/kit';

export const handle: Handle = async ({ event, resolve }) => {
const cookies = parse(event.request.headers.get('cookie') || '');
const accessToken = cookies['sb-access-token'];
supabase.auth.setAuth(accessToken);
const { user } = await supabase.auth.api.getUser(accessToken);
event.locals.user = user;
return resolve(event);
};
// src/hooks.ts
import { supabase } from '$lib/db';
import { parse } from 'cookie';
import type { Handle } from '@sveltejs/kit';

export const handle: Handle = async ({ event, resolve }) => {
const cookies = parse(event.request.headers.get('cookie') || '');
const accessToken = cookies['sb-access-token'];
supabase.auth.setAuth(accessToken);
const { user } = await supabase.auth.api.getUser(accessToken);
event.locals.user = user;
return resolve(event);
};
Seems like if there is no cookie for sb-access-token it fails. Should that not perhaps be wrapped in an if?
stukennedy
stukennedy3y ago
Yes … Possibly a ternary to set the user to null instead of trying to use it
Smardrengr
SmardrengrOP3y ago
e0
e03y ago
It looks like you are not using the password when you are calling the signIn function. https://bitbucket.org/r2-creative/gameonornot/src/04d633724ba4176b1e105bcb13e0ab3783d7a3ed/app/src/routes/login/%2Bpage.server.ts#lines-18:21 FWIW, I do this a bit differently. Once a user is signed in, I make all of the supabase calls server-side. But for the actual signing in/out/up etc, I do that directly on the frontend.
e0
e03y ago
Did you end up testing this more? The problem I'm wondering about is like this: say that you have two users A and B and for each of them you want to make two database calls, for (bad) example you have a server route that fetches a user's tweets, and then fetch a user's photos.
await supabase.from('tweets').select('*')
await supabase.from('photos').select('*')
await supabase.from('tweets').select('*')
await supabase.from('photos').select('*')
If user A makes the call first and then user B makes the same call immediately after, does that make it so that when user A is fetching the photos, supabase is fetching user B's photos instead?
stukennedy
stukennedy3y ago
I did test this, and it seemed to be behaving correctly used 2 browsers and logged in to 2 accounts, and did a select on projects, it only recovered the projects for the user
e0
e03y ago
That use case sounds like it should be safe since the race condition won’t really be reflected. Did you try to use setTimeout on the first user’s projects fetch to make sure that the call happens after the second user’s session got set?
MrMendez
MrMendez3y ago
i have it working as magic link but i cant access or save locals
MrMendez
MrMendez3y ago
No description
MrMendez
MrMendez3y ago
this is my hook
MrMendez
MrMendez3y ago
fixed it doing this
No description
No description
MrMendez
MrMendez3y ago
for the types and passing the events to the page throw the load function
Smardrengr
SmardrengrOP3y ago
Hmm, even with your suggestions (thank you!), I'm still getting a coalesce_to_error error... from most recent commit https://bitbucket.org/r2-creative/gameonornot/src/main/app/src/.
Error: {"status":303,"location":"/login"}
at coalesce_to_error (file:///Users/rene/Sites/me/side/gameonornot/app/node_modules/@sveltejs/kit/src/utils/error.js:11:5)
at respond_with_error (file:///Users/rene/Sites/me/side/gameonornot/app/node_modules/@sveltejs/kit/src/runtime/server/page/respond_with_error.js:85:17)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async render_page (file:///Users/rene/Sites/me/side/gameonornot/app/node_modules/@sveltejs/kit/src/runtime/server/page/index.js:305:10)
at async resolve (file:///Users/rene/Sites/me/side/gameonornot/app/node_modules/@sveltejs/kit/src/runtime/server/index.js:312:11)
at async respond (file:///Users/rene/Sites/me/side/gameonornot/app/node_modules/@sveltejs/kit/src/runtime/server/index.js:202:20)
at async file:///Users/rene/Sites/me/side/gameonornot/app/node_modules/@sveltejs/kit/src/vite/dev/index.js:399:22
Error: {"status":303,"location":"/login"}
at coalesce_to_error (file:///Users/rene/Sites/me/side/gameonornot/app/node_modules/@sveltejs/kit/src/utils/error.js:11:5)
at respond_with_error (file:///Users/rene/Sites/me/side/gameonornot/app/node_modules/@sveltejs/kit/src/runtime/server/page/respond_with_error.js:85:17)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async render_page (file:///Users/rene/Sites/me/side/gameonornot/app/node_modules/@sveltejs/kit/src/runtime/server/page/index.js:305:10)
at async resolve (file:///Users/rene/Sites/me/side/gameonornot/app/node_modules/@sveltejs/kit/src/runtime/server/index.js:312:11)
at async respond (file:///Users/rene/Sites/me/side/gameonornot/app/node_modules/@sveltejs/kit/src/runtime/server/index.js:202:20)
at async file:///Users/rene/Sites/me/side/gameonornot/app/node_modules/@sveltejs/kit/src/vite/dev/index.js:399:22
Smardrengr
SmardrengrOP3y ago
It's got to be something obvious. Wish I could see it! 😆 Btw, once I/we get this working, I intend to make a sort of public template repo for a bare bones “SvelteKit + Supabase basic auth with email, password and/or magic link“ so others can get up and running without the pain.
stukennedy
stukennedy3y ago
just looking at the code again, I think my setting Auth in hooks/handle should work handle gets called every time the sveltekit server receives a request (e.g. all my server methods post/get/put/delete/update) ... and it sets the auth at that point. That's just the same as calling setAuth in the method instance right? (without the boilerplate)
MrMendez
MrMendez3y ago
for some reason my code stop working and can't figure out why 😵‍💫
Smardrengr
SmardrengrOP3y ago
Pushed a commit to my work-in-progress side app that has auth working: https://bitbucket.org/r2-creative/gameonornot/commits/

Did you find this page helpful?