---
title: "19 — Authentication — A Spectrum of Where Proof Lives and Who You Trust"
uid: authentication-strategies
tags: ["sso", "auth", "security", "sessions", "jwt", "roadmap:frontend", "oauth"]
excerpt: "Basic, Session, Token, JWT, OAuth, SSO: not a menu — a spectrum, placed by where the proof lives and who you trust to vouch for you."
date: 2026-08-12T18:35:09+0000
source: https://www.aveshina.my.id/en/blog/authentication-strategies
---

Six names I used to treat as a menu to memorize — Basic, Session, Token, JWT, OAuth, SSO. Writing them down collapsed them into one model: **they're a spectrum, not a menu, and the two axes that place any strategy on it are *where the proof lives* and *who you trust to vouch for you*.** [1]

Every auth flow answers one question — *who are you?* — and the strategies differ only in how they answer it. At one end you re-prove who you are on every single request. At the other you never prove anything to the app at all; a third party you both trust does it for you. Everything in between is a trade-off between statelessness (the server remembers nothing, so it scales) and revocability (the server remembers, so it can kick you out). That trade-off is the whole spine:

```figure
<svg viewBox="0 0 740 320" xmlns="http://www.w3.org/2000/svg" class="my-6 w-full max-w-3xl" role="img" aria-label="Authentication strategies laid out as a spectrum. A horizontal arrow runs left to right from 'you prove it every request' to 'you delegate trust to a third party.' Four stages sit on the arrow: Basic Auth (proof sent every request, least trust delegation), Session (server remembers you in a vault), Token/JWT (you carry a signed card, stateless), OAuth/SSO (a third party you both trust vouches for you). A second axis runs vertically labelled stateless at top and revocable at bottom. A dashed curve shows the trade-off: as you move right you gain scalability and trust delegation but lose instant revocation.">
  <defs>
    <marker id="aarrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto">
      <path d="M0,0 L10,5 L0,10 z" fill="#64748b"/>
    </marker>
  </defs>
  <g font-family="ui-sans-serif, system-ui, sans-serif" text-rendering="geometricPrecision">

    <!-- horizontal spectrum arrow -->
    <line x1="60" y1="180" x2="680" y2="180" stroke="#64748b" stroke-width="2" marker-end="url(#aarrow)"/>
    <text x="60" y="206" font-size="10" fill="#64748b">you prove it every request</text>
    <text x="678" y="206" font-size="10" fill="#64748b" text-anchor="end">you delegate trust to a third party</text>

    <!-- strategy nodes -->
    <g>
      <rect x="55" y="95" width="120" height="56" rx="8" fill="#e0e7ff" stroke="#6366f1" stroke-width="1.5"/>
      <text x="115" y="120" font-size="13" font-weight="700" fill="#1e1b4b" text-anchor="middle">Basic</text>
      <text x="115" y="138" font-size="10" fill="#475569" text-anchor="middle">proof every request</text>
    </g>
    <g>
      <rect x="225" y="95" width="120" height="56" rx="8" fill="#fef9c3" stroke="#ca8a04" stroke-width="1.5"/>
      <text x="285" y="120" font-size="13" font-weight="700" fill="#422006" text-anchor="middle">Session</text>
      <text x="285" y="138" font-size="10" fill="#475569" text-anchor="middle">server remembers you</text>
    </g>
    <g>
      <rect x="395" y="95" width="120" height="56" rx="8" fill="#fce7f3" stroke="#db2777" stroke-width="1.5"/>
      <text x="455" y="120" font-size="13" font-weight="700" fill="#500724" text-anchor="middle">Token / JWT</text>
      <text x="455" y="138" font-size="10" fill="#475569" text-anchor="middle">you carry a signed card</text>
    </g>
    <g>
      <rect x="565" y="95" width="120" height="56" rx="8" fill="#dcfce7" stroke="#16a34a" stroke-width="1.5"/>
      <text x="625" y="120" font-size="13" font-weight="700" fill="#052e16" text-anchor="middle">OAuth / SSO</text>
      <text x="625" y="138" font-size="10" fill="#475569" text-anchor="middle">third party vouches</text>
    </g>

    <!-- vertical trade-off axis -->
    <line x1="370" y1="245" x2="370" y2="285" stroke="#94a3b8" stroke-width="1.5" stroke-dasharray="3 3"/>
    <text x="365" y="262" font-size="10" fill="#16a34a" text-anchor="end" font-weight="700">stateless · scalable</text>
    <text x="375" y="262" font-size="10" fill="#db2777" font-weight="700">revocable · controllable</text>
    <text x="370" y="300" font-size="10" font-style="italic" fill="#64748b" text-anchor="middle">the central trade-off — you rarely get both</text>
  </g>
</svg>
```

With that spine in place, the six names stop being a list to memorize and start being points on a line.

## Basic Auth — you prove it, every time

At the left end is the simplest possible answer: send your username and password with *every* request [2]. The browser base64-encodes the pair — base64 is just a reversible way to wrap the text into a safe string of characters, *not* encryption — and stuffs it into an Authorization header on each call:

```
Authorization: Basic YXZlOnNlY3JldA==
```

That's it. There's no session, no token, no state — the server checks the credentials afresh each time. I now reach for it only for one-off internal tools or simple API gateways, because the cost is obvious: the password travels on every request, and there's no clean way to revoke one without changing the password. It's the trustless baseline everything else improves on.

## Session-based — the server remembers you

The first improvement: stop sending the password. On login the server validates credentials once, then stores a record that says "this user is logged in" and hands back a **session ID** — an opaque string it keeps in a lookup table [3]. The browser carries that ID in a cookie; on each request the server looks it up and knows who you are.

The mental shift for me was seeing what the server-side store buys you: **revocation is trivial.** Delete the row, and the session is dead instantly — no waiting for a token to expire, no blacklist to maintain. The cost is the mirror image: every server (or a shared store like Redis) has to *consult* that table on every request, so horizontal scaling gets harder. It's the classic stateful pattern — easy to control, harder to scale.

## Token-based — you carry the proof

Move one step right and the proof changes hands. On login the server issues a **token** — an unguessable string — that *is* the proof of who you are [4]. The browser stores it and sends it on each request, but the server doesn't look anything up: if the token is valid, you're in. That's the stateless win — any server, anywhere, can validate you with no shared session store.

The trade-off written plainly: because there's no server-side record, **revoking a token before it expires is hard.** You either wait it out or maintain a blacklist (which is just sessions with extra steps). Tokens also need safe storage — they're bearer instruments; whoever holds one is you.

## JWT — a token that carries its own meaning

JWT (JSON Web Token) is the dominant token shape, and the part I had to get straight is that a JWT is *not* encrypted secrecy — it's a signed claim [5]. It's three base64 chunks — header, payload, signature — joined by dots:

```
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhdmUifQ.sFlKxwRJSMeKKF2QT4f...
        header              payload              signature
```

The signature is a value the server computes over the first two parts with a secret key — called an HMAC, or a key-pair signature with RSA/ECDSA. Anyone can *read* the payload — base64-decode it and the claims (sub, exp, iat, custom ones) are right there. What they can't do is *change* it: alter a byte and the signature stops matching. That's what "signed, not encrypted" means. The payoff is that the token carries its own metadata, so any service sharing the signing key can trust the claims without a database lookup — microservices love it. The footgun is the same: until exp fires, a JWT is valid, and the payload is public, so it never goes near sensitive data [6].

## OAuth — you delegate the trust

The right end of the spectrum answers a different question entirely. Up to here, *your* server checked the password. OAuth flips it: **you stop collecting passwords at all** and let a provider you both trust — Google, GitHub, the company IdP (identity provider) — vouch for the user [7]. The flow is a redirected handshake: your app sends the user to the provider, the user logs in *there*, the provider sends back an authorization grant, and your app exchanges it for an access token. You never see the password.

The thing that clicked: OAuth isn't really "logging in with Google" — it's **authorization delegation**. The access token represents permission your app was granted to *act on the user's behalf* against the provider's API. That's why there are scopes, consent screens, and refresh tokens — the machinery is about *what your app is allowed to do*, not just *who the user is*. Using it purely as login is a common simplification, but conflating the two muddies the model.

## SSO — one login, many apps

Single Sign-On is the organizational expression of the same idea: one trusted identity provider, many relying applications [8]. The user authenticates once with the provider; each app trusts the provider's assertion (often via SAML or OIDC — two standard handshake protocols built on OAuth ideas) and logs them in without ever seeing a password. The difference from generic OAuth is mostly framing — SSO is the *goal* (one login for the whole suite), and protocols like SAML and OIDC are how it's delivered inside enterprises.

For a small portfolio site like this one, SSO is overkill; "Login with Google" via plain OAuth is the right-sized version of the same trust-delegation idea. The spectrum still tells me *why* — I'm picking the delegation end because I'd rather trust Google's security team than store my own passwords.

## How I use this

The spectrum is now my first cut at any auth decision. I ask two questions: *do I need to revoke sessions instantly?* (lean left, to session-based) and *do I want to avoid storing passwords at all?* (jump right, to OAuth). JWT fits when I have multiple services sharing a key and can tolerate eventual expiry. Basic stays in the toolbox for trivial internal gates. Naming the axis — where proof lives, who you trust — turned a six-item menu into a single line I can actually reason along.

## References

[1] roadmap.sh, "Authentication Strategies," 2024. [Online]. Available: [https://roadmap.sh/frontend/auth-strategies](https://roadmap.sh/frontend/auth-strategies)

[2] roadmap.sh, "Basic Authentication," 2024. [Online]. Available: [https://roadmap.sh/guides/basic-authentication](https://roadmap.sh/guides/basic-authentication)

[3] roadmap.sh, "Session Based Authentication — Visually Explained," 2024. [Online]. Available: [https://roadmap.sh/guides/session-based-authentication-visually-explained](https://roadmap.sh/guides/session-based-authentication-visually-explained)

[4] roadmap.sh, "Token Based Authentication," 2024. [Online]. Available: [https://roadmap.sh/guides/token-authentication](https://roadmap.sh/guides/token-authentication)

[5] Auth0, "Introduction to JSON Web Tokens," jwt.io. [Online]. Available: [https://jwt.io/introduction](https://jwt.io/introduction)

[6] Auth0, "JSON Web Token (JWT) signing algorithms overview," jwt.io. [Online]. Available: [https://jwt.io](https://jwt.io)

[7] OAuth.net, "OAuth 2.0 — OAuth," 2024. [Online]. Available: [https://www.oauth.com/](https://www.oauth.com/)

[8] roadmap.sh, "SSO — Single Sign On," 2024. [Online]. Available: [https://roadmap.sh/guides/sso](https://roadmap.sh/guides/sso)

```quiz
Q: The six auth strategies differ along two axes. Which pair is the spine of the spectrum?
- Speed vs. security
- Where the proof lives, and who you trust to vouch for you
correct: 1
explain: Every strategy answers "who are you?" — the difference is where the proof is stored (every request, server-side, or a token you carry) and whose word you take (your own server, or a third party).

Q: A JWT's payload is base64-encoded. That means…
- it's encrypted and unreadable without the key
- it's signed (tamper-evident) but readable by anyone — don't put secrets in it
correct: 1
explain: JWT is signed, not encrypted. Anyone can decode the payload; the signature only stops them from altering it. Sensitive data must never go in the payload.

Q: You need to be able to kill a user's access instantly after a password reset. Which strategy fits best?
- Session-based (server stores the session)
- Stateless JWT with a long expiry
correct: 0
explain: Sessions are trivial to revoke — delete the row and the session is dead. A JWT stays valid until it expires unless you maintain a blacklist, which is sessions with extra steps.

Q: "Login with Google" on a small site is really an application of…
- Basic Auth, because the provider checks the password
- OAuth — you delegate trust to a provider and never store the password yourself
correct: 1
explain: OAuth lets a third party vouch for the user. Your app receives an access token, never the password. SSO is the same trust-delegation idea at organizational scale.

Q: Why is Basic Auth (sending credentials on every request) only used for trivial internal gates?
- It can't be made to work over HTTPS
- The password travels on every request and there's no clean revocation path
correct: 1
explain: Basic Auth works fine over HTTPS, but re-sending the password per request and lacking an easy kill switch makes it a poor fit for anything beyond simple internal tooling.
```
