JavaScript API Security: How to Make Fetch and Axios Calls Securely

We train developers every day to spot the weak points in their JavaScript API calls, especially when using fetch or axios. We’ve seen how easy it is for mistakes to creep in—tokens exposed, bad input slipping through, or sensitive data leaking out. 

Our approach is all about practical, real-world steps: strong authentication, encrypting traffic, validating every bit of input, and handling errors without giving away clues. We believe secure development isn’t about adding layers of confusion—it’s about building habits that keep our apps and users safe, right from the first line of code.

Key Takeaway

  • Use strong authentication methods like OAuth 2.0 and JWT with short-lived tokens.
  • Always enforce HTTPS and secure token storage to protect data in transit and at rest.
  • Validate inputs, handle errors carefully, and monitor API usage to prevent attacks.

The Importance of API Security in JavaScript

We’ve built things fast—sometimes too fast. It’s easy to forget how open our JavaScript code really is. Every fetch or axios call we make is a small invitation. And not everyone who shows up is a guest. Some come to steal.

We’ve seen APIs that pass tokens in URLs, others that send passwords unencrypted. Mistakes like that—small ones—open big doors. When JavaScript runs on the client side, it hands out clues: how we connect, where our data lives, and sometimes, how to break in.

The web doesn’t forgive shortcuts. We can’t afford to treat API security like a feature—it’s the foundation. Our browser is the house, and APIs are the pipes. If the pipes leak, water’s not our only problem.

Core Principles of Secure JavaScript API Usage

Use Strong Authentication and Authorization

We don’t just want to know who’s asking—we want to know what they’re allowed to do. Authentication says who you are. Authorization says what you can touch.

We use OAuth 2.0 and JWTs because they give us both structure and flexibility. Short-lived tokens are better than long-lived ones. We rotate them often and use refresh tokens to keep users logged in without giving attackers time to use a stolen key.

We also design our APIs with roles in mind. It’s not just “user” or “admin”. It’s about what actions belong to each. If a token has a role claim, our backend checks it every time.

When it’s a high-risk API—think finance or personal data—we might even use mTLS. Both sides must prove who they are, which raises the bar for any attacker. (1)

Always Use HTTPS and TLS Encryption

We don’t guess if traffic is safe. If it’s not HTTPS, it’s not secure. Every call made with fetch or axios goes over TLS—always.

The browser helps. It blocks mixed content and warns about insecure requests. But the responsibility is still ours. We audit URLs, strip out HTTP, and configure servers to force redirects and reject plain requests.

TLS 1.3 isn’t optional in our setup. It’s faster, safer, and supported almost everywhere now. When something talks over the wire, it should do so in code, not plain speech.

Validate and Sanitize Inputs Relentlessly

We learned the hard way—never trust input. It doesn’t matter if it’s a string, an ID, or a whole JSON body. If it’s coming from outside, it’s suspect.

So we use libraries like Zod or Yup. We define schemas before we send data to the server or accept it. If someone sends “DROP TABLE users” instead of a name, it stops at the front gate.

Here’s a trick we do: we validate everything, even optional fields. A missing field is one thing. A wrong format is another. We check types, lengths, and allowed values.

Sanitizing helps too. We strip out HTML tags, script blocks, and sneaky Unicode characters. We keep logs to see what bad input looks like—so we’re ready next time.

Implement Rate Limiting and Throttling

We don’t leave our APIs open 24/7 for just anyone to hammer. Rate limits are part of our shield.

Our setup includes thresholds by IP, user ID, and API key. If someone sends 100 login attempts in a minute, we block them. If a scraper tries to pull every product listing, they get a timeout.

We use rate-limiting middleware or gateways. It’s not just a good idea—it saves us from getting flooded.

And when something breaks that pattern—hundreds of requests at 3 a.m. from a new country—we flag it, fast.

Secure Token and Secret Management

We stopped using localStorage for tokens a while ago. It’s just too risky. One XSS bug, and it’s all over.

Instead, we store tokens in HttpOnly cookies. They’re invisible to JavaScript, and with the Secure and SameSite flags set, they’re much harder to abuse.

Axios and fetch both support cookie credentials. We just add withCredentials: true or credentials: ‘include’, and the browser handles the rest.

We rotate our tokens, too. Every 15 minutes, max. If a token leaks, that window stays small. We log out users if we see their token on two continents at once.

Handle Errors and Responses Carefully

We used to show full stack traces in dev mode—and one day, someone forgot to turn it off. That’s how we learned not to trust error messages either.

Now we show generic messages like “Something went wrong.” The logs still get the full error, but users don’t see internals.

We catch errors with try/catch in fetch or axios. We log them, alert on critical ones, and never dump raw exceptions into the UI.

That one time we leaked a database error? Never again.

Monitor, Log, and Audit API Usage

Logging isn’t optional. We log everything that matters—API calls, errors, failed logins, rate-limit hits.

Each log entry includes:

  • Timestamp
  • IP address
  • User agent
  • Endpoint
  • Status code
  • User ID (if available)

We send logs to a central system that watches for patterns. If something looks weird—like 100 failed tokens from one IP—we know.

Auditing helps after the fact. When we need to know who accessed what and when, the data’s already there.

Secure Usage Practices for Fetch and Axios

Use HTTPS URLs Exclusively

We’ve learned to double-check every endpoint. Even in test code, we don’t allow HTTP URLs. (2)

javascript

CopyEdit

fetch(‘https://api.example.com/data’, { method: ‘GET’ });

axios.get(‘https://api.example.com/data’);

Include Credentials Securely

If we’re using cookie-based auth, we set our fetch calls like this:

javascript

CopyEdit

fetch(‘https://api.example.com/secure-data’, {

  method: ‘GET’,

  credentials: ‘include’,

});

And axios like this:

javascript

CopyEdit

axios.get(‘https://api.example.com/secure-data’, {

  withCredentials: true,

});

The server must set HttpOnly, Secure, and SameSite=Strict on those cookies.

Use Axios Interceptors for Token Management

Instead of repeating ourselves, we attach tokens with interceptors.

javascript

CopyEdit

axios.interceptors.request.use(config => {

  const token = getAuthToken(); // From memory, not localStorage

  if (token) {

    config.headers.Authorization = `Bearer ${token}`;

  }

  return config;

});

We also handle refresh logic in the same interceptor, checking for 401s and requesting a new token quietly.

Validate and Sanitize Data Before Sending

Before a POST or PUT, we validate inputs.

javascript

CopyEdit

import * as Yup from ‘yup’;

const schema = Yup.object().shape({

  email: Yup.string().email().required(),

  password: Yup.string().min(8).required(),

});

async function submit(data) {

  try {

    await schema.validate(data);

    await axios.post(‘https://api.example.com/login’, data);

  } catch (err) {

    console.error(‘Validation failed:’, err);

  }

}

We don’t let bad data leave the browser.

Avoid Exposing Tokens in URLs or Logs

Tokens never go in query strings:

javascript

CopyEdit

// ❌ Don’t do this

axios.get(`https://api.example.com?token=${token}`);

// ✅ Use headers

axios.get(‘https://api.example.com’, {

  headers: { Authorization: `Bearer ${token}` },

});

And we don’t log them. Ever. Not even during debugging.

Implement CSRF Protection if Using Cookies

If we use cookies for auth, we set SameSite and add CSRF tokens for extra coverage. The server verifies these on each request.

Practical Advice for Developers

Credits: Josh tried coding

Secure Storage of Tokens and Secrets

We gave up on localStorage a while back. SessionStorage too. JavaScript can see both. HttpOnly cookies are our answer, even if it takes more server config.

Regular Rotation and Revocation of Keys

We don’t wait until a breach. API keys and tokens have lifespans—usually 15 to 30 minutes. Refresh tokens help keep the experience smooth.

We also built a revoke list. If a token gets flagged, it goes on the list, and access shuts down fast.

Use API Gateways for Centralized Security

Our gateway handles rate limits, token verification, logging, and threat detection. It simplifies backend services—they just focus on logic.

We don’t rely on the client for security checks. Ever.

Keep Dependencies Up to Date

Axios updates? We watch for them. Same with our validation libraries and backend tools.

Outdated packages invite known exploits. We’ve set up alerts and regular dependency scans.

Monitor and Audit API Usage

It’s not just logs. We watch behavior.

  • Failed logins?
  • New devices?
  • Excessive calls?

We set alerts and review them daily.

Educate Teams on Security Best Practices

Security isn’t solo work. Our devs know what CSRF means, our testers know what SQLi looks like, and our ops team knows what suspicious logs smell like.

We train quarterly. We test with real scenarios. It’s worth the effort.

Common API Security Vulnerabilities and How to Avoid Them

Injection Attacks

We reject raw SQL, command injection, and anything we didn’t expect. Parametrized queries and ORMs are a must.

SPO Triple: Untrusted input → causes → Injection vulnerabilities.

Cross-Site Scripting (XSS)

We sanitize all output. We use CSP headers. If someone tries to inject <script> tags, they get nothing.

SPO Triple: Malicious scripts → create → XSS threats.

Cross-Site Request Forgery (CSRF)

We enforce SameSite cookies and use CSRF tokens when needed.

SPO Triple: Unauthorized requests → exploit → Cookie-based sessions.

Broken Authentication and Session Management

Our sessions expire fast, and we lock out on repeated failures. Password resets are strict. Sessions can’t be reused.

Insufficient Rate Limiting

We cap requests at every level—user, IP, key. Spikes trigger blocks.

Sensitive Data Exposure

We encrypt in transit and at rest. No plaintext tokens. No detailed error messages in the wild.

Advanced Security Measures for JavaScript API Calls

Mutual TLS (mTLS)

We use mTLS in high-security environments. Each side has a certificate. No cert, no access.

Content Security Policy (CSP)

We set headers like:

http

CopyEdit

Content-Security-Policy: default-src ‘self’; script-src ‘self’

Helps block injected scripts.

API Request Encryption

For extra protection, we encrypt payloads manually. Both sides know how to decrypt.

Token Revocation and Blacklisting

Revoked tokens can’t be used again. Our system checks the blacklist before processing any request.

Secure Cookie Attributes

Every auth cookie gets:

  • HttpOnly
  • Secure
  • SameSite=Strict

No exceptions.

Handling Errors and Responses Securely

Avoid Leaking Sensitive Information

We only show generic errors to users. Internals stay in the logs.

Graceful Error Handling in Fetch and Axios

We wrap every request:

javascript

CopyEdit

try {

  const res = await axios.get(‘/api/data’);

} catch (err) {

  console.error(‘Something went wrong.’);

}

Timeout and Retry Strategies

Axios has timeout settings. We retry once, maybe twice—no endless loops.

Monitoring and Auditing API Security

Logging Best Practices

We log:

  • Auth attempts
  • IPs
  • Endpoints
  • Timestamps

We don’t log passwords. Ever.

Real-Time Monitoring

We use tools that alert on patterns: too many 401s, unusual IPs, or location jumps.

Security Audits and Penetration Testing

We test ourselves quarterly—internal scans, external pen testers, and open-source checklists.

Conclusion

We teach our teams that securing JavaScript API calls with fetch and axios is never just one fix—it’s a habit built on layers. We use strong authentication, enforce HTTPS, validate every input, and keep a close eye on token handling.

We’re careful with error messages and always update our dependencies. For extra protection, we look at mutual TLS and token revocation. By sticking to these habits, we help our developers build apps that keep user data safe and trust intact.

Want to level up your API security skills?
Join the Secure Coding Practices Bootcamp and get hands-on training in secure software development—no jargon, just real-world code.

Related Articles

References

  1. https://en.wikipedia.org/wiki/Web_API_security
  2. https://www.strongdm.com/blog/api-security-best-practices 
Avatar photo
Leon I. Hicks

Hi, I'm Leon I. Hicks — an IT expert with a passion for secure software development. I've spent over a decade helping teams build safer, more reliable systems. Now, I share practical tips and real-world lessons on securecodingpractices.com to help developers write better, more secure code.