Profile    Mohammed Shiroz Status   Loading  
Logo
Share This
Back to blog
Filter by:
Tags
//Article title

JWT vs Sessions vs API Keys: Which One to Use, and When

About Post

Ask three developers how their API handles authentication and you'll often get three answers that are really the same answer: "We use JWT." For the web app. And the mobile app. And the partner integration. And the cron job on another server.

JWT is a fine tool. But sessions, JWTs and API keys solve different problems, and picking one for everything is how you end up with a logout button that doesn't actually log anyone out, or a partner whose "token" expires every hour and breaks their nightly import.

The quickest way I know to tell them apart is three everyday objects.

Three objects, three ideas

Sessions: the coat check ticket

You hand over your coat and get a numbered ticket. The ticket itself is worthless; it's just a reference. The cloakroom keeps the real thing.

That's a session. After login, the server stores your state (user ID, maybe a few more details) and gives the browser a random session ID in a cookie. On each request, the server looks that ID up. Logging out means throwing away the record, and the ticket instantly means nothing.

JWT: the stamped festival wristband

At a festival, the gate staff don't phone the ticket office for every person. They look at the wristband: right colour, right stamp, today's date. The wristband carries the information and proves itself.

A JWT works the same way. The token contains claims (who you are, when it expires) plus a signature. Any server holding the key can verify it without a database lookup. The catch is the same as with wristbands: once it's on your wrist, it's hard to take back before it expires.

API keys: the access card for the delivery van

The delivery company doesn't log in with a username and password each morning. Its van has an access card that opens one loading bay, issued to the company rather than to a person, valid until someone cancels it.

An API key is a long-lived secret that identifies an application or service, not a person sitting in front of a screen.

Side by side

SessionJWTAPI key
IdentifiesA user in a browserA user or service, per tokenAn application or integration
State livesOn the serverInside the tokenOn the server (key record)
LifetimeMinutes to hours, slidingShort (minutes), refreshedLong, until rotated or revoked
Instant revokeEasy: delete the sessionHard without extra stateEasy: mark revoked
Main riskCSRF (cookies are sent automatically)Theft plus no easy revokeLeaked in code, logs or repos
Natural fitYour own web appDistributed services, SSO, OAuthServer-to-server integrations

The question that decides it: who is calling?

Most confusion disappears when you ask whether the caller is a person or a program.

A person in a browser, on your own domain? Use sessions with secure, HttpOnly, SameSite cookies. It's boring and battle-tested, logout really works, and JavaScript can't read the cookie if an XSS bug slips through. In Laravel, Sanctum's SPA authentication is exactly this: normal session cookies, plus CSRF protection, for a JavaScript frontend.

A person in a mobile app? Cookies are awkward there, so a token is the usual answer. It doesn't have to be a JWT. Sanctum's personal access tokens are opaque random strings stored hashed in the database, which means you can revoke one from a "log out this device" screen immediately. Store the token in the platform's secure storage (Keychain, Keystore), not in plain app storage.

Many services that need to trust the same identity? This is where JWT shines. An identity provider signs a short-lived token, and each service verifies it locally without calling back. That's why OAuth and OpenID Connect use JWTs so widely. Keep them short-lived and use refresh tokens, because a stolen JWT is valid until it expires.

A program calling your API: a partner's system, an internal cron job, a webhook sender? Use API keys (or OAuth client credentials if you need standards and scopes). Nobody is there to log in, so a token that expires every 15 minutes just creates failures at 3 am.

Rule of thumb: users get sessions or short-lived tokens; services get keys or client credentials. If you're issuing a user's token to a server, or a long-lived key to a browser, stop and rethink.

Doing API keys properly

API keys look like the simplest option, and that's why they're often done carelessly. A few habits make a big difference:

$plain = 'sk_live_' . Str::random(40);

ApiKey::create([
    'client_id' => $client->id,
    'prefix'    => substr($plain, 0, 12),   // shown in the UI to identify the key
    'key_hash'  => hash('sha256', $plain),  // never store the key itself
    'scopes'    => ['invoices:read'],
]);

return $plain; // shown once, then gone
  • Store a hash, show the key once. If your database leaks, the keys don't. A fast hash like SHA-256 is fine here (unlike passwords) because the key is long and random, so there's nothing to guess.
  • Add a recognisable prefix. It helps people tell keys apart, and secret scanners in tools like GitHub can spot leaked keys with known patterns.
  • Scope them. A reporting integration doesn't need write access. Smaller keys mean smaller accidents.
  • Support rotation. Allow two active keys per client, so they can switch over without downtime, then revoke the old one.
  • Never put them in frontend code. Anything shipped to a browser or app bundle is public. A key in JavaScript is a key for everyone.

The JWT gotchas worth knowing

  • A JWT is signed, not encrypted. Anyone can decode the payload. Don't put anything private in it.
  • Logout is a lie unless you add state. Deleting the token on the client doesn't stop a stolen copy. Short expiry plus revocable refresh tokens is the usual compromise.
  • Pin the algorithm when verifying. Libraries let you specify which algorithms you accept. Do it, and don't let the token's own header decide.
  • Don't keep it in localStorage for a browser app if you can avoid it. Any XSS can read it. For your own web app, a session cookie is usually the better answer anyway.

The short version

  • Your own web app: sessions in secure cookies.
  • Mobile app: revocable tokens in secure storage.
  • Many services trusting one identity provider: short-lived JWTs.
  • Machines and partners: hashed, scoped, rotatable API keys.

Plenty of real systems use all three at once, and that's fine, as long as each one is doing the job it's good at. Which one do you see misused most often in the codebases you've worked on?

Comments (0)
Leave your review

Thanks for your valuable comments. Your comments has been updated and appreciate your getting in touch...

01. About Shiroz

Mohammed Shiroz

Hi, I'm Mohammed Shiroz, a software engineer and AI enthusiast from Sri Lanka who turns ideas into intelligent, real-world solutions. With over 9 years of hands-on experience, I currently lead real estate ERP development at Kate Group, a...

03.My Projects

04. Categories

Ready To order Your Project ?

Get in Touch
Close