API Authentication with JWTs, Explained
Once your app has users, your API needs to know who is making each request. The most common answer today is the JSON Web Token (JWT). It's everywhere, and it's often used slightly wrong. This post explains what a JWT actually is, how the authentication flow works, and the security details that separate a safe implementation from a risky one.
The problem: HTTP forgets
HTTP is stateless — each request stands alone, and the server doesn't inherently remember that you logged in a moment ago. So after a user signs in, every subsequent request needs to prove who they are. A JWT is a compact, verifiable way to carry that proof.
What a JWT actually is
A JWT is a string with three parts separated by dots: a header, a payload, and a signature.
- The payload holds "claims" — small facts like the user's ID and when the token expires.
- The signature is the important part. The server creates it using a secret key. Anyone can read the token, but only the server (which holds the secret) can produce a valid signature — so nobody can forge or tamper with one without being detected.
A critical point that trips people up: a JWT is signed, not encrypted. The payload is only encoded, not hidden — anyone with the token can read its contents. So never put sensitive data (passwords, secrets) in a JWT payload.
The authentication flow
- Login. The user sends credentials. The server verifies them and creates a signed JWT containing their ID and an expiry.
- Store. The app keeps the token (in secure storage on mobile).
- Send. On each request to a protected endpoint, the app includes the token, usually in an
Authorization: Bearer <token>header. - Verify. The server checks the signature and expiry. If valid, it trusts the claims and knows who's calling — without a database lookup.
That last point is the appeal: the server can authenticate a request just by verifying the token's signature, no session store required.
Access tokens and refresh tokens
Here's the tension: short-lived tokens are safer (a stolen one expires quickly), but forcing users to log in constantly is miserable. The standard resolution is two tokens:
- A short-lived access token (minutes to an hour) sent with every request.
- A longer-lived refresh token used only to obtain a new access token when the old one expires.
The app quietly refreshes the access token in the background, so the user stays logged in and any leaked access token is only briefly useful. Refresh tokens are more sensitive, so store them carefully and make them revocable.
The security details that matter
JWTs are safe only if you handle them properly:
- Always use HTTPS. A token sent over plain HTTP can be intercepted and reused. Non-negotiable.
- Keep expiry short. Because a standard JWT can't easily be "un-issued," a long expiry means a stolen token stays valid a long time. Short access tokens limit the damage.
- Store tokens securely on the device. Use the platform's secure storage, not plain local storage where other code might read them.
- Protect your signing secret. If the secret leaks, anyone can mint valid tokens for any user. Keep it in environment variables, rotate it if exposed.
- Never trust an "unsigned" token. Always verify the signature server-side and reject tokens using a "none" algorithm — a classic attack.
- Plan for revocation. Pure JWTs are hard to revoke before expiry. For "log out everywhere" or banning a user immediately, keep a server-side list of revoked tokens or short-lived sessions.
Don't over-reach
JWTs are for authentication — proving identity. Resist the urge to stuff them full of data or use them as a general-purpose cache. Keep the payload minimal: an ID, an expiry, maybe a role. Look up the rest from your database when you need it.
Summary
A JWT is a signed, tamper-evident token that lets your API verify who's making a request without a session lookup. The user logs in, receives a token, and sends it on every request; the server verifies the signature and trusts the claims. Use short-lived access tokens with refresh tokens for good UX, always run over HTTPS, store tokens securely, guard your signing secret, and keep the payload small and non-sensitive. Handled with those details in mind, JWTs are a clean, scalable foundation for authenticating your app's users.