DEV Community

Cover image for Auth Explained (Part 1): ID vs Access vs Refresh tokens — 🤔what they ACTUALLY do (and why localStorage is a trap)

Auth Explained (Part 1): ID vs Access vs Refresh tokens — 🤔what they ACTUALLY do (and why localStorage is a trap)

Sylwia Laskowska on October 22, 2025

A while ago in a technical interview I got asked: “Can you walk me through how authentication and authorization actually work under the hood?” ...
Collapse
 
cyber8080 profile image
Cyber Safety Zone

Great article, thanks Sylwia Laskowska! 🙌
Your breakdown of ID tokens vs Access tokens vs Refresh tokens is super clear and actionable:

  • ID token = who the user is, for the UI. (DEV Community)
  • Access token = permission to call APIs, short-lived, keep in memory. (DEV Community)
  • Refresh token = hidden, long-lived cookie, used to renew access. (DEV Community) Also totally agree that storing tokens in localStorage or sessionStorage is a risky move—XSS wins too easily. (DEV Community)

One question though: when you say the Access token lives just in memory, how do you manage safe page refreshes or tab closes in single-page apps without hurting UX? Would love a few mini patterns if you plan a part 2.

Looking forward to part 2 and digging into PKCE + BFF flows!

Collapse
 
hashbyt profile image
Hashbyt

Managing access tokens purely in memory definitely introduces UX challenges with page refreshes and tab closes in SPAs. As Sylwia hinted, common patterns to handle this include implementing silent refresh mechanisms where a hidden iframe or background request fetches a new access token using the refresh token stored securely in an HttpOnly cookie. Another solid approach is the Backend-for-Frontend (BFF) pattern, where tokens never hit the browser but sessions are managed server-side, effectively eliminating client-side token storage risks while maintaining seamless UX.

Collapse
 
sylwia-lask profile image
Sylwia Laskowska

That's an excellent and spot-on summary!

You've perfectly captured the two most robust and widely adopted strategies for solving the in-memory token storage dilemma in SPAs.

Silent Refresh (using an HttpOnly Refresh Token cookie) provides the balance of security and seamless UX.

The BFF Pattern offers the highest security baseline by eliminating client-side token exposure entirely.

Thanks for enriching the discussion!

Collapse
 
rcls profile image
OssiDev • Edited

If sessions are managed server side you don't need tokens at all. You're just stateful at that point

Thread Thread
 
sylwia-lask profile image
Sylwia Laskowska

Absolutely — 100% agreed 👍
Once you move to a BFF or any server-side session model, you’re no longer doing “token-based auth” in the browser — the session is the auth, and the browser just carries a session cookie.

The moment you go stateful, the whole “where do I store the access token” problem disappears entirely.

I’m planning to touch on this contrast in Part 2 as well — because a lot of SPA devs don’t realise “no tokens on the client” is actually a valid (and often superior) option. 🚀

Collapse
 
sylwia-lask profile image
Sylwia Laskowska

Thanks so much 🙌 really glad the breakdown clicked!

Re: access token + page refresh — that’s exactly the topic I start with in Part 2, because that’s where the “in-memory” strategy meets real UX 🙂
Different ways to survive a reload (silent refresh / BFF etc.) will be covered there.

Part 2 is coming next 🚀

Collapse
 
shemith_mohanan_6361bb8a2 profile image
shemith mohanan

This is such a clear and fun read, Sylwia! The passport/visa analogy nailed it 😂

Totally agree on avoiding localStorage — I’ve seen so many early-stage apps trip on that one.
Excited for Part 2 and the PKCE section 👏

Collapse
 
hashbyt profile image
Hashbyt

Authentication is like showing your passport to prove who you are, while authorization is like the visa that grants you permission to enter certain places. In tech terms, the ID token verifies your identity for the frontend, and the access token grants your app permission to call APIs. This mental model helps build secure and clear authentication flows that align perfectly with the blog’s explanation.

Collapse
 
sylwia-lask profile image
Sylwia Laskowska

Ahh thank you! 😄
So glad the border/passport analogy landed — it’s my favorite way to make sense of all the token chaos 😂
And yes, localStorage is like leaving your passport at the café — looks fine until it’s not.

Collapse
 
lico profile image
SeongKuk Han

Great article, thank you!
I have a question.

Where should I store access token and refresh token in react based server or any html, without backend?

If I store access token and refresh token in sessionStorage, it will be blown away, but I want to keep them, so when user reopens it, the login status is still remained.

Collapse
 
sylwia-lask profile image
Sylwia Laskowska

Thanks! 🙌

Access token should live in memory, and the refresh token should be stored as an HttpOnly cookie set by the IdP, not in local/sessionStorage.
On page load, the app just does a silent refresh using that cookie to get a new access token — that’s how login survives a reopen without storing tokens in JS storage.

I’ll cover this step-by-step in the next article (Part 2) 🚀

Collapse
 
lico profile image
SeongKuk Han

I look forward to it.

Just a couple of questions are wandering in my mind.

So in this case, http cookie should be set by the server. But if the backend server has a different domain, how can I set the cookie for client?

Client domain A.com, server domain B.com. And client is html files served by web server such as nginx.

Second and last,

If we store accessToken in http cookie, is there any reason we use refreshToken?

Thread Thread
 
sylwia-lask profile image
Sylwia Laskowska

Thanks! Great questions — super common in real apps.

Different domains (A.com app, B.com IdP/API):

A server on B.com can’t set cookies for A.com.

Use one of these:

Same-site setup: serve IdP on a subdomain (e.g. auth.a.com) so it can set a first-party HttpOnly cookie (SameSite=Lax/Strict).

Top-level redirect: briefly navigate the browser to b.com so it’s first-party there; B.com sets the cookie, then redirects back.

BFF pattern: tiny backend under a.com holds tokens; browser only has a session cookie.

Access token in an HttpOnly cookie — do we still need a refresh token?

For SPAs, don’t put the access token in a cookie (CSRF + it’s sent automatically everywhere). Keep access in memory and use Authorization: Bearer.

You still want a refresh token (in HttpOnly cookie) to renew short-lived access tokens without re-login (and to enable rotation/reuse-detection).

If you move to BFF + server session, then you typically don’t use access tokens in the browser at all (so no refresh token in the browser either).

I’ll cover these options (same-site vs redirect, PKCE, BFF, CSRF gotchas) in Part 2. 🚀

Collapse
 
jediswebdev_07a684996b15e profile image
JedisWebDev

This was a nice article. I think I understand the concepts better now.
Thanks a lot 🙏

Collapse
 
hashbyt profile image
Hashbyt

I am definitely going to share this with our team @jediswebdev_07a684996b15e

Collapse
 
sylwia-lask profile image
Sylwia Laskowska

Thanks a lot 🙌
Really happy it helped make the concepts click — that’s exactly why I’m writing the series 🙂
Part 2 coming soon 🚀

Collapse
 
priteshkiri profile image
Pritesh Kiri

The explanation was crisp and clear!!

Thanks for sharing this blog @sylwia-lask

Collapse
 
sylwia-lask profile image
Sylwia Laskowska

Thank you so much! 🙌
Really happy to hear it was clear — that’s exactly what I was aiming for 🙂
Part 2 coming very soon! 🚀

Collapse
 
hashbyt profile image
Hashbyt

I completely agree with you @priteshkiri

Collapse
 
hashbyt profile image
Hashbyt

Great breakdown! To put it simply: authentication is about verifying who you are like showing your ID at the border. Once verified, authorization is about what you’re allowed to do like having the right visa or permissions to enter certain areas. In the tech world, the ID token confirms your identity, while the access token determines what actions or resources you can access. Understanding this helps clarify how secure systems manage user access efficiently!

Collapse
 
n3nad profile image
Nenad Mitrovic

We can never have too many mental models for auth. Each one offers its own unique perspective and gives us a chance to learn something new.

Thanks for your effort on this one!

Collapse
 
sylwia-lask profile image
Sylwia Laskowska

Thanks so much 🙌
Totally agree — auth really clicks only once you’ve seen it from a few angles.
Glad this model added another lens to the toolkit 🙂

Collapse
 
syahla_nahda_0ca4b37b609b profile image
syahla nahda

Cuan banget main di Jo777.