You can’t stop every attacker, but you can make stolen tokens useless. Here’s how to secure your API before someone else does.

Introduction: The Hidden Cost of “It Works”
Most developers never think about token security until something goes wrong.
Your login works, your tokens are issued and verified correctly, and everything seems perfect.
Then one day, you see strange API traffic. Tokens from unfamiliar IPs.
No brute-force attacks, no code injection, just someone quietly using your API like a valid user.
That’s what token theft looks like.
It doesn’t crash your system. It blends in.
If you rely on JWTs, OAuth, or any form of API token, this guide walks through the 7 essential security practices that keep stolen tokens from turning into full-scale breaches.
1. Keep Tokens Short-Lived and Scoped
A token should grant access only for a short time and only to what’s necessary.
But many APIs issue tokens that never expire, effectively giving attackers a permanent key once leaked.
Best Practices
- Access tokens: expire within 5–30 minutes.
- Refresh tokens: valid for days, not months.
- Scopes: limit what each token can do (e.g.,
read:profile,write:comments).
Example:
const token = jwt.sign(
{ sub: user.id, scope: "read:profile" },
process.env.JWT_SECRET,
{ expiresIn: "15m" }
);
Short lifetimes and scoped permissions make stolen tokens far less valuable.
2. Never Store Tokens in LocalStorage or SessionStorage
This one causes more token thefts than anything else.
When you store tokens in localStorage, they’re accessible to any script that runs on your page.
If an attacker injects a malicious <script> even once, they can read and exfiltrate your token.
Why It’s Dangerous
- XSS (Cross-Site Scripting) can expose
localStorage. - Browser extensions can read stored tokens.
- Tokens persist after logout unless explicitly cleared.
The Secure Alternative
- Store access tokens in memory (e.g., React state).
- Store refresh tokens in HTTP-only cookies, which are not accessible to JavaScript.
- Use CSRF tokens to secure refresh flows.
Example (Express):
res.cookie("refreshToken", refreshToken, {
httpOnly: true,
secure: true,
sameSite: "Strict",
});
This setup eliminates JavaScript access and mitigates XSS risks.
3. Rotate and Revoke Tokens Regularly
A long-lived token is a permanent backdoor once leaked.
Even if you use short-lived access tokens, your refresh tokens can still be abused if not rotated.
Rotation Strategy
- Every time a refresh token is used, invalidate the old one.
- Track tokens by
jti(JWT ID) or a database record. - Revoke on logout or password reset.
Example:
if (oldToken.used || oldToken.revoked) {
throw new Error("Token reuse detected");
}
oldToken.used = true;
await save(oldToken);
Rotation ensures that even if a token leaks, it cannot be reused.
Bonus: Log every refresh event. Repeated refresh attempts from different IPs are a red flag.
4. Use HTTPS Everywhere and Enforce HSTS
A shocking number of “secure” APIs still serve parts of their stack over plain HTTP images, scripts, or subdomains.
If a token ever crosses an unencrypted connection, it can be intercepted using a man-in-the-middle (MITM) attack.
Checklist
✅ Force HTTPS on every endpoint (backend, auth, CDN).
✅ Enable HSTS (HTTP Strict Transport Security) to block downgrades.
✅ Use strong TLS (1.2 or 1.3 only).
Example Nginx configuration:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
Encrypt everything, not just the login route.
5. Don’t Expose Tokens in Logs or URLs
Tokens are often leaked internally through debugging logs, not hackers.
Common mistakes include:
console.log("Authorization:", req.headers.authorization);
or
GET /api/user?token=abc123
Once logged, that data may end up in third-party monitoring tools, email alerts, or even error screenshots.
Safer Practices
- Never log raw tokens.
- Redact them before logging (e.g., show first 6 characters only).
- Avoid query parameters for tokens; always use headers.
Example:
console.log("Token:", token.slice(0, 6) + "...redacted");
A simple omission like this has caused real-world breaches in major APIs.
6. Implement IP and Device-Level Anomaly Detection
Not every token misuse can be prevented. But anomalies can be detected before damage grows.
What to Track
- Unusual IPs (e.g., user logged in from the US, token used from Asia minutes later).
- Multiple devices reusing the same token.
- Excessive refresh attempts.
- Sudden traffic bursts from unknown clients.
Implementation
- Log metadata (
ip,userAgent,geo) with every token event. - Set automated alerts or block thresholds for abnormal behavior.
Even simple monitoring (e.g., CloudWatch + API gateway metrics) can catch 80% of unauthorized activity before it becomes a breach.
7. Protect Your CI/CD and Source Code
Developers often forget that CI/CD pipelines and code repositories handle the same secrets as production.
If your token or secret key leaks here, it’s game over.
Best Practices
- Use secret managers like AWS Secrets Manager, HashiCorp Vault, or Doppler.
- Never store keys directly in
.envfiles inside version control. - Use build-time injection of secrets through environment variables.
- Restrict who can view CI logs or job outputs.
- Run secret-scanning tools such as Gitleaks or TruffleHog.
Example (GitHub Actions):
env:
STRIPE_KEY: ${{ secrets.STRIPE_KEY }}
A single overlooked .env file has exposed countless API tokens, some still active years later.
Bonus Tip: Limit What Each Token Can Do
Even perfect storage can’t save you from an overly powerful token.
If every token can “do everything,” then one leak means full compromise.
Use least privilege:
- Assign specific scopes to tokens (
read,write,delete). - Issue separate tokens for frontend and backend.
- Revalidate permissions on sensitive routes.
When tokens are scoped tightly, a leak might cause inconvenience, not a catastrophe.
Recap: The 7 Practices That Actually Work

Conclusion: Token Security Is a Habit, Not a Patch
You can’t make your system invincible, but you can make it resilient.
A stolen token doesn’t have to mean a breach if it expires fast, rotates safely, and is worthless outside its intended context.
Security isn’t about locking everything down. It’s about building systems that fail safely.
The developers who understand this don’t just write APIs; they write APIs that last.
Call to Action
What’s your biggest token security blind spot right now?
Take 10 minutes today to check one of these: token lifetime, HTTPS config, or where you’re storing refresh tokens.
Then share this post with your team. One small fix could prevent your next 3 a.m. security incident.


Leave a Reply