HttpOnly cookie auth strategy
Unanswered
Round sardinella posted this in #help-forum
Round sardinellaOP
I'm dealing with a small API where logging in only requires calling a
Once I call this and receive a cookie to send in subsequent requests (via
The cookie can't be accessed in any way in either client or server code because of the
POST /login
endpoint with a name and email which returns with a Set-Cookie header to create a unique token cookie. This cookie has httpOnly=true; domain=example.com; sameSite=None
.Once I call this and receive a cookie to send in subsequent requests (via
useCredentials
), what's the best way in Next.js to check that the user is authenticated on/before page load?The cookie can't be accessed in any way in either client or server code because of the
domain=example.com
setting and the API doesn't have an endpoint specifically for checking the session.23 Replies
I use an AuthProvider:
https://github.com/adb-software-solutions/debuglife/blob/main/debuglife-frontend/src/context/AuthContext.tsx
And then I wrap my authenticated routes in an Auth Guard:
https://github.com/adb-software-solutions/debuglife/blob/main/debuglife-frontend/src/guards/AuthGuard.tsx
https://github.com/adb-software-solutions/debuglife/blob/main/debuglife-frontend/src/context/AuthContext.tsx
And then I wrap my authenticated routes in an Auth Guard:
https://github.com/adb-software-solutions/debuglife/blob/main/debuglife-frontend/src/guards/AuthGuard.tsx
I'm not 100% sure if this will work with your particular cookie setup, but this is the only auth system i ever build lol.
Round sardinellaOP
So you're just calling an endpoint on mount to login/check if there's a session and then manually tracking it with context?
Yeah so basically, the way it rechecks, is if the api call works and returns data im authenticated as i clearly passed the correct session cookie, or it fails and im not logged in so i end up redirected to login
Round sardinellaOP
That makes sense. Does this method initially show protected pages while the auth check happens though?
Its been bullet proof. And i use the same system in both NextJS and Vite+React (the latter in a production saas app) and we've had no issues.
No, the AuthGuard, that you would place in the dash layout for example, prevents that from happening.
Round sardinellaOP
Oh I see, you're just rendering based on
loading
// src/components/admin/AuthGuard.tsx
"use client";
import {useEffect} from "react";
import {useRouter} from "next/navigation";
import {useAuth} from "@/context/AuthContext";
interface AuthGuardProps {
children: React.ReactNode;
}
const AuthGuard = ({children}: AuthGuardProps) => {
const {user, loading} = useAuth();
const router = useRouter();
useEffect(() => {
if (!loading && !user) {
router.push("/auth/login");
}
}, [user, loading, router]);
if (loading || !user) {
return <div>Loading...</div>;
}
return <>{children}</>;
};
export default AuthGuard;
As you can see, if its loading or user doesn't exist, it will not render.
Round sardinellaOP
Perfect. Thanks for the examples!
Quick note, if you're only returning children, you can just say
return children
instead of wrapping it in a fragmentUnless you're expecting multiple children then nvm
No problem @Round sardinella, when I first tried tackle a proper auth system for my saas app about 9months ago it took me 2 months to get a working system. I tried every library under the sun, switched from nextjs to react 10 times, tried session based auth, jwt based and honetsly i was so close to giving up. I was massively overly complicating my guards. Trying to make one big one and it just would never work.
Where as with this its so simple. In my Saas app, i actually have about 10 guards in total, but each guard only protects against one thing which is the key.
Where as with this its so simple. In my Saas app, i actually have about 10 guards in total, but each guard only protects against one thing which is the key.
@Round sardinella Quick note, if you're only returning children, you can just say `return children` instead of wrapping it in a fragment
Yeah not sure why i did that, maybe i hadn't set props at that point so did it to avoid type issues.
Round sardinellaOP
Looks pretty solid though. Nice work
Cape lion
@adam.birds
I would like to know, why such pattern is good for you. I mean, why everything here is as client component.
Isn't it better to keep that logic on server side and validate path in middleware?
I would like to know, why such pattern is good for you. I mean, why everything here is as client component.
Isn't it better to keep that logic on server side and validate path in middleware?
@Cape lion <@452033040428826644>
I would like to know, why such pattern is good for you. I mean, why everything here is as client component.
Isn't it better to keep that logic on server side and validate path in middleware?
I'm not really after any server side benefits on my logged in pages. I only use server side stuff for the pages i care about seo/speed on. And my backend is in django, not nextjs so its not like im building the rest of my backend in nextjs.
Cape lion
Oh ok, i get it.
Im currently building my own full-stack app with next.js and separated node.js server.
In every tutorial they are always talking about server components etc. so ive just assumed that this is better and the only way of proper next.js apps
Im currently building my own full-stack app with next.js and separated node.js server.
In every tutorial they are always talking about server components etc. so ive just assumed that this is better and the only way of proper next.js apps
Can you tell me more about " any server side benefits on my logged in pages ". Why do you find it better to write your logged in pages as client components?
My experience is mainly in React + Vite as well on a purely client side app, so for the dashboard side im just sticking with that kind of principal. It is data heavy, requires a lot of state for interactivity. There probably is a way of doing it differently, and maybe getting a slight performance benefit from it, but I'm guessing it won't be half as simple. When it comes to do the actual frontend of the blog i'm building at the moment. That will be using all server side stuff for seo and speed benefits.
Both the saas app I've built and the CMS i'm building for my blog system both have a lot of data and tables with builtin filtering, inline editing and other stuff in and i just don't think its worth the effort to try and do server stuff too ha.
Cape lion
Yeah, i think it would be a lot of refactoring
@Cape lion Yeah, i think it would be a lot of refactoring
I've actually just built my table package as a library i've released on npm, its not really usable for anyone else currently as I've built it specific to the way i work on my projects and I haven't done any docs for it yet, but its completely reusable and features, sorting, filtering, inline editing, bulk actions. And it works with either react or nextjs because its been done client side. Feel free to take a look if interested, but as i said probably won't work for anyone else yet, as it expects the api to be set up in a specific way - https://www.npmjs.com/package/tablewind