Is this a good way to handle user session information?
Answered
Almond stone wasp posted this in #help-forum
Almond stone waspOP
I managed to do authentication and save the session token on a cookie, and moved on to storing session information (user's name, account handle, etc)
I made it work, but feels a bit hacky:
In the root layout, it will check if the
Since
And finally, in the sign in page, I do authentication using a server actions
I made it work, but feels a bit hacky:
export default async function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
const authToken = cookies().get("auth_token");
let session = null;
if (authToken) {
session = await getUserSession(authToken.value);
}
return (
<html lang="en">
<body className={inter.className}>
<div className="h-screen flex">
<main className="flex grow bg-zinc-100">
<Main sessionProp={session}>{children}</Main>
</main>
</div>
</body>
</html>
);
}In the root layout, it will check if the
auth_token cookie is set; if so, get session information and move pass it on to the <Main> component (which is a client component)Since
<Main> is a client component, I can create a global context to spread the session information across the other components (like navbar, which will contain the user avatar, side panel, which has user name and handle, etc)export default function Main({ sessionProp, children }: { sessionProp: Session; children: React.ReactNode }) {
const [session, setSession] = useState<Session | null>(sessionProp);
return (
<SessionContext.Provider value={{ session, setSession }}>
...
</SessionContext.Provider>
);
}And finally, in the sign in page, I do authentication using a server actions
export default function SignIn() {
const [state, formAction] = useFormState(attemptSignIn, { session: null, errorMsg: "" });
const { session, setSession } = useContext(SessionContext) as SessionContextProps;
const router = useRouter();
useEffect(() => {
if (!state.session)
return;
setSession(state.session);
}, [state]);
useEffect(() => {
if (!session)
return;
router.push("/");
}, [session]);
}Answered by Serbian Hound
cus <Main> can technically render a server component if you're just making it render children im sure
21 Replies
Almond stone waspOP
If the server action for sign in succeeds, the form state will update and redirect to
/export async function attemptSignIn(_prevState: any, data: FormData) {
const formUsername = data.get("username");
const formPassword = data.get("password");
const db = await openDb();
// authenticate...
cookies().set("auth_token", authToken);
return { session: await getUserSession(authToken), errorMsg: "" };
}It feels a little hacky, and this approach causes basically the whole app to become client-sided (since I need
useContext to update the user session information)Serbian Hound
why do you feel this is hacky?
I personally wouldn't do it like this (the client context) - are you saying its hacky because you wanna potentially have a server component as a child in client component in the future
Serbian Hound
cus <Main> can technically render a server component if you're just making it render children im sure
Answer
@Serbian Hound why do you feel this is hacky?
Almond stone waspOP
I don't know, it just feels overcomplicated.
For example, when I was working on a server-first web app, I would just:
- Create a middleware to get session information (if there is a session cookie)
- Any route that requires the session information will redirect to
E.g:
This route requires
I guess it's just a different mind model when working client-first
For example, when I was working on a server-first web app, I would just:
- Create a middleware to get session information (if there is a session cookie)
- Any route that requires the session information will redirect to
/login if the user is unauthenticatedE.g:
pub async fn pricing(
ConnectInfo(connect_info): ConnectInfo<SocketAddr>,
UserLanguage(lang): UserLanguage,
uri: Uri,
session_data: SessionData,
) -> Result<Response, RouteError> {
// ...
}This route requires
SessionData, and if it's unavailable (the middleware didn't retrieve it), it will just go to /loginI guess it's just a different mind model when working client-first
@Serbian Hound I personally wouldn't do it like this (the client context) - are you saying its hacky because you wanna potentially have a server component as a child in client component in the future
Almond stone waspOP
Ohh that's interesting, I thought that every child component would also be client-sided because
<Main> isSerbian Hound
I think similar to you, if I was doing it I would've had JWT tokens with middleware and kept it very server side thinking
middleware is responsible for the routing - not react components imo
@Serbian Hound middleware is responsible for the routing - not react components imo
Almond stone waspOP
I didn't mess with the Next middleware yet, on this other project I wasn't using React also, instead I was using template engine
Serbian Hound
yeah nextjs is somewhat new to me, only built very small apps with it that were just static sites really
but I'd suggest to use middleware from what I know for this 😄
Almond stone waspOP
I think I should implement the middleware for doing the redirects anyway, in case the user is not authenticated
Serbian Hound
yup then your main app (which atm is responsible for re-routing) isnt a client component
from what I understand, it's best to have child components at the leaf of the tree, rather than root
Almond stone waspOP
For now I think I will keep this mostly the same, since it's just a test project
A bit overwhelming though
Thanks for the feedback @Serbian Hound
Serbian Hound
np i am also new ish to nextjs so its just my 2 cents