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)
Sylwia Laskowska
Sylwia Laskowska

Posted on

Auth Explained (Part 1): ID vs Access vs Refresh tokens โ€” ๐Ÿค”what they ACTUALLY do (and why localStorage is a trap)

A while ago in a technical interview I got asked:

โ€œCan you walk me through how authentication and authorization actually work under the hood?โ€

And like many devs I knew just enough to plug in Auth0/NextAuth etcโ€ฆ but not enough to explain the โ€œwhyโ€ behind the flow.

This series is the version I wish I had back then โ€” plain English, no magic โœจ, just a mental model that sticks.


Why does the frontend need AuthN? ๐Ÿคทโ€โ™€๏ธ

Because the frontend knows nothing about you.

To your browser, youโ€™re just:

  • a tab with JavaScript,
  • a userโ€ฆ or a hacker,
  • or possibly a fridge ๐ŸงŠ with Chrome ๐Ÿ˜…

It needs someone trusted to say โ€œyes, thatโ€™s really Sylwia.โ€ โ†’ that โ€œsomeoneโ€ is the IdP.


AuthN vs AuthZ ๐Ÿ†š

Name Fancy Human
AuthN Authentication โ€œWho are you?โ€ ๐Ÿ‘ค
AuthZ Authorization โ€œWhat are you allowed to do?โ€ โœ…

๐Ÿ‘‰ The frontend does NOT authenticate you โ€” it just starts the process and carries tokens.
๐Ÿ‘‰ The API is the thing that actually says โ€œyes/noโ€ to an action.


Who does what? ๐Ÿงฉ

Actor Job
IdP Knows the user + issues tokens
Frontend Asks for tokens & stores the right ones
API Validates access token & allows/blocks actions

Analogy ๐Ÿ›‚

Real World In Auth
Passport office IdP
Border control API
Traveler sweating at customs ๐Ÿ˜… Frontend

The three token types ๐ŸŽŸ๏ธ

Token What it is Analogy
ID Token who you are passport / ID
Access Token permission visa / entry stamp
Refresh Token ability to renew VIP wristband ๐ŸŽค

โš ๏ธ The ID token is for the frontend only.
The API doesnโ€™t care about your life story โ€” it cares about the access token โœ…


Where do tokens live (and why not localStorage)? ๐Ÿ 

โŒ localStorage = โ€œplease rob meโ€ ๐Ÿดโ€โ˜ ๏ธ

Super convenientโ€ฆ also super easy to steal:

localStorage.getItem("access_token")
๐Ÿ”ด Live TV: sylwia lask/auth explained part id vs access vs refresh tokens what they actually do and why l - Pertandingan Hari Ini ๐Ÿ”ด Live TV: sylwia lask/auth explained part id vs access vs refresh tokens what they actually do and why l - Pertandingan Hari Ini

One tiny XSS โ†’ ๐Ÿ’ธ token gone.


And what about sessionStorage? ๐Ÿค”

A common question is: โ€œIf localStorage is risky, is sessionStorage safer?โ€

Answer: No โ€” same problem.

Storage Can JS steal it? XSS resistance
localStorage โœ… yes โŒ weak
sessionStorage โœ… yes โŒ weak
HttpOnly cookie โŒ no โœ… strong

sessionStorage only dies when the tab closes โ€” it doesnโ€™t protect against theft during the session.
So it doesnโ€™t make tokens safer, just shorter-lived loot.


โœ… Access Token โ†’ in memory ๐Ÿง 

What it is: โ€œpermissionโ€ โ€“ proof you can call the API
Where it lives: in memory (JS variable, not storage)
Lifetime: short: ~5โ€“15 min (sometimes up to 30)
Why short?: if stolen โ†’ damage window stays tiny

What it actually does:

You attach it to every API request so the API knows who is calling.

fetch("https://api.example.com/profile", {
  headers: {
    "Authorization": `Bearer ${accessToken}`
  }
});
๐Ÿ”ด Live TV: sylwia lask/auth explained part id vs access vs refresh tokens what they actually do and why l - Pertandingan Hari Ini ๐Ÿ”ด Live TV: sylwia lask/auth explained part id vs access vs refresh tokens what they actually do and why l - Pertandingan Hari Ini

The API verifies:
โœ”๏ธ signature
โœ”๏ธ issuer
โœ”๏ธ audience
โœ”๏ธ expiry
โœ”๏ธ scopes (permissions)


โœ… ID Token โ†’ in memory ๐Ÿง โœจ

What it is: identity snapshot โ€” โ€œwho the user isโ€
Where: in memory
Lifetime: short (~5โ€“15 min)
Used for: UI (display name, avatar, etc.), not for calling APIs

You decode it just to show profile data โ€” not to grant access.


BONUS โ€” Reading the ID Token ๐Ÿ”

const idToken = "...your.jwt.here...";
const payload = JSON.parse(atob(idToken.split('.')[1]));
console.log(payload);

// object will look something like:
{
  name: "Sylwia",
  email: "sylwia@example.com",
  picture: "https://example.com/avatar.png",
  sub: "user-123"
}
๐Ÿ”ด Live TV: sylwia lask/auth explained part id vs access vs refresh tokens what they actually do and why l - Pertandingan Hari Ini ๐Ÿ”ด Live TV: sylwia lask/auth explained part id vs access vs refresh tokens what they actually do and why l - Pertandingan Hari Ini

โš ๏ธ decode โ‰  verify


โœ… Refresh Token โ†’ HttpOnly cookie ๐Ÿช๐Ÿ”’

What it is: the thing that gives you new access tokens
Where: HttpOnly Secure SameSite cookie
Lifetime: long: days/weeks/months
Why: frontend should never read it

What it actually does:

Its only job is to refresh an expired access token.

await fetch("/token/refresh", {
  method: "POST",
  credentials: "include" // <-- RT cookie auto-sent
});
๐Ÿ”ด Live TV: sylwia lask/auth explained part id vs access vs refresh tokens what they actually do and why l - Pertandingan Hari Ini ๐Ÿ”ด Live TV: sylwia lask/auth explained part id vs access vs refresh tokens what they actually do and why l - Pertandingan Hari Ini

The frontend doesnโ€™t โ€œseeโ€ it โ€” it just benefits from it.


Mental model ๐Ÿง ๐Ÿ“

Token Where Why
Access in memory short-lived, API calls
ID in memory UI only
Refresh HttpOnly cookie unreadable, long-lived

โœ… Mental model diagram

[User] 
   |
   v
[Frontend]  -- "I don't know who this is" -->  
   |
   v
[IdP]  -- "Okay, here's who they are" --> (ID Token + Access Token + Refresh Token)
   |
   v
[Frontend]  -- stores ID+Access (memory), RT in cookie
   |
   v
[API]  -- "Do you have a valid Access Token?"
๐Ÿ”ด Live TV: sylwia lask/auth explained part id vs access vs refresh tokens what they actually do and why l - Pertandingan Hari Ini ๐Ÿ”ด Live TV: sylwia lask/auth explained part id vs access vs refresh tokens what they actually do and why l - Pertandingan Hari Ini

Up next โ€” Part 2 ๐Ÿš€

In Part 2 weโ€™ll:
โœ… walk the full redirect โ€œdanceโ€ ๐Ÿ’ƒ
โœ… explain PKCE (secure code exchange) ๐Ÿ”
โœ… show how the refresh cookie appears ๐Ÿช
โœ… cover refresh token rotation โ™ป๏ธ
โœ… mention BFF (extra-safe pattern) ๐Ÿ›ก๏ธ

Top comments (22)

๐Ÿ”ด Live TV: sylwia lask/auth explained part id vs access vs refresh tokens what they actually do and why l - Pertandingan Hari Ini
 
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!

๐Ÿ”ด Live TV: sylwia lask/auth explained part id vs access vs refresh tokens what they actually do and why l - Pertandingan Hari Ini
 
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.

๐Ÿ”ด Live TV: sylwia lask/auth explained part id vs access vs refresh tokens what they actually do and why l - Pertandingan Hari Ini
 
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!

๐Ÿ”ด Live TV: sylwia lask/auth explained part id vs access vs refresh tokens what they actually do and why l - Pertandingan Hari Ini
 
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

๐Ÿ”ด Live TV: sylwia lask/auth explained part id vs access vs refresh tokens what they actually do and why l - Pertandingan Hari Ini 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. ๐Ÿš€

๐Ÿ”ด Live TV: sylwia lask/auth explained part id vs access vs refresh tokens what they actually do and why l - Pertandingan Hari Ini
 
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 ๐Ÿš€

๐Ÿ”ด Live TV: sylwia lask/auth explained part id vs access vs refresh tokens what they actually do and why l - Pertandingan Hari Ini
 
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 ๐Ÿ‘

๐Ÿ”ด Live TV: sylwia lask/auth explained part id vs access vs refresh tokens what they actually do and why l - Pertandingan Hari Ini
 
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.

๐Ÿ”ด Live TV: sylwia lask/auth explained part id vs access vs refresh tokens what they actually do and why l - Pertandingan Hari Ini
 
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.

๐Ÿ”ด Live TV: sylwia lask/auth explained part id vs access vs refresh tokens what they actually do and why l - Pertandingan Hari Ini
 
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.

๐Ÿ”ด Live TV: sylwia lask/auth explained part id vs access vs refresh tokens what they actually do and why l - Pertandingan Hari Ini
 
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) ๐Ÿš€

๐Ÿ”ด Live TV: sylwia lask/auth explained part id vs access vs refresh tokens what they actually do and why l - Pertandingan Hari Ini
 
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?

๐Ÿ”ด Live TV: sylwia lask/auth explained part id vs access vs refresh tokens what they actually do and why l - Pertandingan Hari Ini 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. ๐Ÿš€

๐Ÿ”ด Live TV: sylwia lask/auth explained part id vs access vs refresh tokens what they actually do and why l - Pertandingan Hari Ini
 
jediswebdev_07a684996b15e profile image
JedisWebDev

This was a nice article. I think I understand the concepts better now.
Thanks a lot ๐Ÿ™

๐Ÿ”ด Live TV: sylwia lask/auth explained part id vs access vs refresh tokens what they actually do and why l - Pertandingan Hari Ini
 
hashbyt profile image
Hashbyt

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

๐Ÿ”ด Live TV: sylwia lask/auth explained part id vs access vs refresh tokens what they actually do and why l - Pertandingan Hari Ini
 
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 ๐Ÿš€

๐Ÿ”ด Live TV: sylwia lask/auth explained part id vs access vs refresh tokens what they actually do and why l - Pertandingan Hari Ini
 
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!

๐Ÿ”ด Live TV: sylwia lask/auth explained part id vs access vs refresh tokens what they actually do and why l - Pertandingan Hari Ini
 
priteshkiri profile image
Pritesh Kiri

The explanation was crisp and clear!!

Thanks for sharing this blog @sylwia-lask

๐Ÿ”ด Live TV: sylwia lask/auth explained part id vs access vs refresh tokens what they actually do and why l - Pertandingan Hari Ini
 
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! ๐Ÿš€

๐Ÿ”ด Live TV: sylwia lask/auth explained part id vs access vs refresh tokens what they actually do and why l - Pertandingan Hari Ini
 
hashbyt profile image
Hashbyt

I completely agree with you @priteshkiri

๐Ÿ”ด Live TV: sylwia lask/auth explained part id vs access vs refresh tokens what they actually do and why l - Pertandingan Hari Ini
 
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!

๐Ÿ”ด Live TV: sylwia lask/auth explained part id vs access vs refresh tokens what they actually do and why l - Pertandingan Hari Ini
 
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 ๐Ÿ™‚

Some comments may only be visible to logged-in visitors. Sign in to view all comments.