Conceptual questions on an auth setup with sveltekit and a separate api sever

Hey guys, I'm currently trying to build a techstack for a small SaaS around sveltekit as a frontend and graphql-yoga as a backend. Now I am stuck on how to do auth properly. Unfortunately most example repos I could find use the backend from the meta frameworks and not a separate API Server, so I couldn't find examples on how I could implement this. At the moment I planned on installing the better auth server side stuff into the yoga server and obviously put the client side better auth stuff into sveltekit. Here are my questions around this setup: -How can I access the session on the sveltekit serverside even if the better auth server stuff is installed on my separate api server? This is needed for route protection, redirects and SSR of protected routes. - Is there anything to keep in mind installing better auth on a graphql-yoga server or should this be as easy as any other node backend?
18 Replies
shubhattin
shubhattin•4w ago
I also recently ran into a similar problem recently https://github.com/shubhattin/tsc-users
GitHub
GitHub - shubhattin/tsc-users
Contribute to shubhattin/tsc-users development by creating an account on GitHub.
shubhattin
shubhattin•4w ago
Let me share with what I understood about this. - To be able to access or send cookie on the frontend you need to be on the same domain. like app.xyz.com and app2.xyz.com - On the server side you can receive the cookie and the make a request to your auth server to get the session information.
shubhattin
shubhattin•4w ago
For cross sub domain cookie sharing you need to configure things properly for proper CORS handling Let me share some code snippets from recent work https://github.com/shubhattin/tsc-users/blob/main/src/lib/auth.ts https://github.com/shubhattin/tsc-users/blob/main/src/hooks.server.ts
GitHub
tsc-users/src/lib/auth.ts at main · shubhattin/tsc-users
Contribute to shubhattin/tsc-users development by creating an account on GitHub.
GitHub
tsc-users/src/hooks.server.ts at main · shubhattin/tsc-users
Contribute to shubhattin/tsc-users development by creating an account on GitHub.
shubhattin
shubhattin•4w ago
If you want to share info accross domains then you should use JWT cookies can be only passed across same subdomains only. - While Making the request from backend server to auth server you need to pass the Cookie Header incomming from your app. - For frontend you need to set set { credentials : "include" } for fetch, ky and axios will have their own options for this. You can look that up. This step is necessary as can't access a secure httpOnly cookie from javascript I Hope I was able to help you.
King Louie
King LouieOP•4w ago
Hey @shubhattin thank you for your input on this! The repo you linked uses the sveltekit backend as an auth server, you linked this to illustrate the cross subdomain cookie sharing, right? With JWT Cookie you mean the jwt + bearer plugin from here https://www.better-auth.com/docs/plugins/jwt ? If I get the flow right, it would work like this? 1. sveltekit FE uses better auth client login method to call my api server with betterauth and gets session cookie in response 2. sveltekit FE fetches /token on my api server to obtain jwt and save it to localstorage Now when requesting a protected route on sveltekit I need to: 1. always pass the jwt token to sveltekit 2. check the token in the sveltekit BE against the /jwks endpoint of my api server 3. do stuff bases on the token contents Did I get this right?
JWT | Better Auth
Authenticate users with JWT tokens in services that can't use the session
King Louie
King LouieOP•4w ago
Do I also need the JWT token stuff for my client side rendering after the initial Sveltekit SSR or can I use the default session cookie in this instance?
shubhattin
shubhattin•4w ago
Luckily in my case my apps were on the same subdomain so no need for jwts were there as they could share directly, which is a more safer way.
King Louie
King LouieOP•4w ago
for me it would be example.tld for sveltekit and api.example.tld for the api server with better auth server
shubhattin
shubhattin•4w ago
Then you can use the approach I use Actually previously I was using JWT based auth (self implemented), But then I recently moved to session based auth using better auth. Not sure about this, It should be needed I think (based on the examples from the docs). I have not implemented jwt based auth so I don't think I can help much here. You have implement and play around with it.
King Louie
King LouieOP•4w ago
So for every SSR request to sveltekit, the sveltekit backend needs to call my api server to get the session, then if the session is valid, calls my api server with the same session and the api server checks the session again to return the protected api info?
shubhattin
shubhattin•4w ago
Yes on required routes if you need to pass the session info as props to component or for redirecting purpose you have to do that Something like this
import { auth } from '~/lib/auth';
import type { LayoutServerLoad } from './$types'; // Adjust the path based on your project structure

export const load: LayoutServerLoad = async ({ locals, request }) => {
const session = await auth.api.getSession({
headers: request.headers
});
return {
user_info: session?.user // This can be undefined if the user is not authenticated
};
};
import { auth } from '~/lib/auth';
import type { LayoutServerLoad } from './$types'; // Adjust the path based on your project structure

export const load: LayoutServerLoad = async ({ locals, request }) => {
const session = await auth.api.getSession({
headers: request.headers
});
return {
user_info: session?.user // This can be undefined if the user is not authenticated
};
};
and then you can access this in child +server and +page files like for /login page
import { redirect } from '@sveltejs/kit';
import type { PageServerLoad } from './$types';

export const load: PageServerLoad = async ({ parent }) => {
const { user_info } = await parent();
if (user_info) redirect(307, '/');
};
import { redirect } from '@sveltejs/kit';
import type { PageServerLoad } from './$types';

export const load: PageServerLoad = async ({ parent }) => {
const { user_info } = await parent();
if (user_info) redirect(307, '/');
};
shubhattin
shubhattin•4w ago
You can refer the codebase I linked https://github.com/shubhattin/tsc-users
GitHub
GitHub - shubhattin/tsc-users
Contribute to shubhattin/tsc-users development by creating an account on GitHub.
shubhattin
shubhattin•4w ago
I have a example from another codebase which depends upon the auth server here.
import { PUBLIC_BETTER_AUTH_URL } from '$env/static/public';
import ky from 'ky';

export type user_verfied_info_type = {
langugaes: {
lang_id: number;
lang_name: string;
}[];
};

export const AUTH_INFO_URL = `${PUBLIC_BETTER_AUTH_URL}/api/ext`;
export const PROJECT_ID = 1; // as defined in tsc_user database

export const get_user_project_info = async (user_id: string, cookie?: string | null) => {
const data = await ky
.get<user_verfied_info_type>(`${AUTH_INFO_URL}/user_info_project`, {
searchParams: {
user_id: user_id,
project_id: PROJECT_ID
},
...(!cookie
? {
credentials: 'include'
}
: {
headers: {
Cookie: cookie
}
})
})
.json();
return data;
};
import { PUBLIC_BETTER_AUTH_URL } from '$env/static/public';
import ky from 'ky';

export type user_verfied_info_type = {
langugaes: {
lang_id: number;
lang_name: string;
}[];
};

export const AUTH_INFO_URL = `${PUBLIC_BETTER_AUTH_URL}/api/ext`;
export const PROJECT_ID = 1; // as defined in tsc_user database

export const get_user_project_info = async (user_id: string, cookie?: string | null) => {
const data = await ky
.get<user_verfied_info_type>(`${AUTH_INFO_URL}/user_info_project`, {
searchParams: {
user_id: user_id,
project_id: PROJECT_ID
},
...(!cookie
? {
credentials: 'include'
}
: {
headers: {
Cookie: cookie
}
})
})
.json();
return data;
};
King Louie
King LouieOP•4w ago
in order to use the auth.api.getSession function I would need to install the server side better auth stuff into sveltekit and the api function does a DB call. Since I planned on installing the better auth server stuff on my api server and keep things separate sveltekit should not be able to access the user db directly
shubhattin
shubhattin•4w ago
If you want to use better auth in another sveltekit frontend you still will need to setup auth-client there.
King Louie
King LouieOP•4w ago
yeah client sure, but auth.api.getSession is a backend function right?
shubhattin
shubhattin•4w ago
this part does not needs setup (server part of another app). Only the client configuration needs to match (I mean the plugins) Like
import { createAuthClient } from 'better-auth/svelte';
import { PUBLIC_BETTER_AUTH_URL } from '$env/static/public';
import { adminClient } from 'better-auth/client/plugins';

export const authClient = createAuthClient({
baseURL: PUBLIC_BETTER_AUTH_URL ?? import.meta.env.VITE_SITE_URL ?? 'http://localhost:5173',
plugins: [
adminClient(),
]
});

export const { useSession, signIn, signOut, signUp } = authClient;
import { createAuthClient } from 'better-auth/svelte';
import { PUBLIC_BETTER_AUTH_URL } from '$env/static/public';
import { adminClient } from 'better-auth/client/plugins';

export const authClient = createAuthClient({
baseURL: PUBLIC_BETTER_AUTH_URL ?? import.meta.env.VITE_SITE_URL ?? 'http://localhost:5173',
plugins: [
adminClient(),
]
});

export const { useSession, signIn, signOut, signUp } = authClient;
In the above example
...(!cookie
? {
credentials: 'include'
}
: {
headers: {
Cookie: cookie
}
})
...(!cookie
? {
credentials: 'include'
}
: {
headers: {
Cookie: cookie
}
})
actually the !cookie is for the client as js cannot access the cookie, but on server cookie needs to be explicitly sent. The modification is to make it work on sever and client.
King Louie
King LouieOP•4w ago
I think I understand now how I need to approach this, thanks very much! I will have to fiddle around a little bit and see if I get this to work 🙂

Did you find this page helpful?