You’ve just built a React login page. The user signs in, everything’s working fine… until they hit refresh. Boom they’re logged out. Again. And again.
If you’ve run into this, you’re not alone. It’s one of those sneaky “React gotchas” that trips up even experienced developers. But the fix? It’s actually simpler than you think.
What’s Actually Going On?
Let’s keep this real and beginner-friendly. When someone logs in and your app sets their “logged-in” status using React state or context, you’re only storing it in memory.
Here’s the catch:
React state is ephemeral(lasting for a very short time, “I had to google this one out guys”). It exists only while the page is alive.
So the moment the user refreshes the page?
The entire React app reboots from scratch and boom, your isAuthenticated
or user
state disappears into the void.
That’s why they get logged out, the state that said “this user is logged in” was wiped.
So… How Do You Keep Users Logged In?
You need a way to persist authentication across page reloads, And that means storing the token (usually a JWT) outside of memory.
Method 1: Use localStorage
After the user logs in and your API returns a token, save that token in localStorage
:
localStorage.setItem("token", yourToken);
Now, even if the user refreshes the page, you can fetch that token again:
const token = localStorage.getItem("token");
if (token) {
// Verify token and re-authenticate
}
Pros:
- Simple to implement
- Persistent across tabs and refreshes
Cons:
- Accessible via JavaScript, which means if your site is vulnerable to XSS, an attacker could steal the token check out OWASP article for more indepth .
Method 2: Use HTTP-Only Cookies
This is a slightly more secure option. Instead of storing the JWT in localStorage
, you store it in a cookie that’s marked HTTP-only.
Here’s the difference:
- HTTP-only cookies can’t be accessed by JavaScript at all.
- This makes them immune to XSS attacks.
Server-side logic sets the cookie:
Set-Cookie: token=abc123; HttpOnly; Secure; SameSite=Strict
And on the client, the browser handles it automatically with every request no manual token handling in JavaScript. Full breakdown on MDN Web Docs
Which One Should You Use?
For personal projects or quick MVPs localStorage
is fine.
For production apps where security matters go with HTTP-only cookies.
If you’re building with something like Next.js or integrating with platforms like Auth0, you’ll often get HTTP-only cookie-based auth out of the box. See best practices for JWT storage on Auth0’s Blog
Real World Analogy
Think of your login state like writing your name on a whiteboard in a meeting room.
- If you only write it on the whiteboard (React state), the moment the room is reset (page refresh), your name is gone.
- But if you also file your name in the office records (localStorage or cookies), even after the room resets, people can look it up and know you belong.
My Take
Man, this is one of those deceptively simple React problems that can turn into a rabbit hole if you don’t know what’s going on behind the scenes. When I first hit this issue, I was storing login state in a context and wondering why every refresh nuked it. It’s wild how a tiny detail like “memory vs. persistence” can make or break the UX.
Personally, I lean towards using HTTP-only cookies on projects where security matters especially anything user-facing. But when I’m prototyping or building dashboards? localStorage
does the job.
This is the kind of stuff every dev should bump into early. It teaches you that not everything lives forever in React sometimes, you gotta make your memory… persistent.
Still stuck with your login state? Implement the fix and ping me let’s debug it together.