S
SolidJS7mo ago
hannus

Proper Usage of load() for Authentication and Redirection in Solid-Start

Scenario: When a user tries to access a route that requires authentication, they should be redirected to the login route. After logging in, the user should be redirected back to the originally requested route. To achieve this, I created a function getUserWithQueryPara. This function checks if a session token is saved. If a token exists, it fetches the user information based on the token; if not, it redirects to the login component. To ensure the user is redirected back to the originally requested route after authentication, a query parameter is added to the login route. Here is the getUserWithQueryPara function:
export const getUserWithQueryPara = cache(async (query?: string) => {
"use server";
const session = await getSession();
const token = session.data.token;
if (token === undefined) throw redirect(`/login?from=${query}`);
const userinfo = await fetchUserPublicWeb(token);
return userinfo;
}, "userinfo");
export const getUserWithQueryPara = cache(async (query?: string) => {
"use server";
const session = await getSession();
const token = session.data.token;
if (token === undefined) throw redirect(`/login?from=${query}`);
const userinfo = await fetchUserPublicWeb(token);
return userinfo;
}, "userinfo");
In the route that requires authentication, to improve performance, I attempted to use load() to pre-load getUserWithQueryPara. In the component, I use createAsync to obtain the result of getUserWithQueryPara. Considering that the getUserWithQueryPara function needs the pathname parameter to handle redirection for unauthenticated users, I added const pathname = useLocation().pathname in both the load() function and before creating createAsync in the component. This is to ensure consistency between pre-loading and in-component loading. Is my approach correct? Any suggestions or improvements would be appreciated. Thank you. Below is the code snippet for the component:
export const route = {
load() {
const pathname = useLocation().pathname;
void getUserWithQueryPara(pathname);
},
} satisfies RouteDefinition;
export default function Create() {
const pathname = useLocation().pathname;
const userinfo = createAsync(() => getUserWithQueryPara(pathname), {
deferStream: true,
});
return (...)
export const route = {
load() {
const pathname = useLocation().pathname;
void getUserWithQueryPara(pathname);
},
} satisfies RouteDefinition;
export default function Create() {
const pathname = useLocation().pathname;
const userinfo = createAsync(() => getUserWithQueryPara(pathname), {
deferStream: true,
});
return (...)
11 Replies
Brendonovich
Brendonovich7mo ago
Yeah this looks good, we do something similar for our app
hannus
hannusOP7mo ago
Does const pathname = useLocation().pathname; make sense? Pathname variable has not been wrapped in the Cache.
Brendonovich
Brendonovich7mo ago
It’s fine that it hasn’t been wrapped in cache But you might want to do the .pathname inside the createAsync Though realistically it’s not gonna change much since you don’t need the redirect to be reactive Since it’ll just redirect to the first pathname
hannus
hannusOP7mo ago
get it. I appreciate
Spooky Dooky
Spooky Dooky7mo ago
I've been trying similar things today, but didn't understand how to create a session. My situation is like this: - User logs in with superbase using for example email login. The JWT is stored in localStorage. - The user wants to make a purchase - for this I am using load() or simply any "use server" function. - But ... how do I get the session transferred from the frontend to the backend in the first place, since the session is not managed by solid-start in this case. What I've ended up doing is simply copying the jwt into a cookie and then I can access the cookie from getCookie on the server, but was wondering if there is any advantage to using useSession and if so, how to use it in my setup. Thanks
Brendonovich
Brendonovich7mo ago
useSession is just a fancy cookie that has a nicer API and provides encryption by default. Does supabase put the jwt in localstorage or do you?
Spooky Dooky
Spooky Dooky7mo ago
wow quick answer! Yes, supabase places the jwt into localstorage:
No description
Brendonovich
Brendonovich7mo ago
ah ic, yeah a cookie is a fine approach for that are you just putting access_token in there?
Spooky Dooky
Spooky Dooky7mo ago
yes, then on the server I use:
import { getCookie } from "vinxi/http";
...


const access_token = getCookie("access_token");
await getAdminClient().auth.getUser(access_token)
import { getCookie } from "vinxi/http";
...


const access_token = getCookie("access_token");
await getAdminClient().auth.getUser(access_token)
;` to validate the token
Brendonovich
Brendonovich7mo ago
yeah nice useSession can be handy over regular cookies since you can trust that any data in it was set by your server same as signing a jwt
Spooky Dooky
Spooky Dooky7mo ago
handy over regular cookies since you can trust that any data in it was set by your server
Thats the key info I didn't know 😄 But since the JWT is created by supabase, using a normal cookie is I guess the correct thing, since its not "my server". Thanks for the explanation 🙌
Want results from more Discord servers?
Add your server