CodingNic

Web APIs and Backend Communication

Sending Authentication

Web APIs and Backend Communication 15 min read

Sending Authentication

Objectives

By the end of this chapter, you should be able to:

  • Send a token with the Authorization header
  • Explain the difference between a 401 and a 403 in practice
  • Explain where a token typically comes from and where it’s commonly stored

💡 Why this matters: Most real APIs aren’t fully public. Almost anything that shows a specific user their own data, their orders, their profile, their messages, needs to know who’s asking before it answers.

⚠️ A note on verification: JSONPlaceholder, this module’s practice API, doesn’t require authentication at all, there’s no real login endpoint to demonstrate against. The pattern below is accurate and extremely common (this exact header shape is used by countless real APIs), but this lesson’s examples use a placeholder domain rather than a live, verifiable one, since no real request was made against it.

The Authorization Header

Authentication is almost always sent as a header on the request, not in the URL and not in the body. The most common shape is the Bearer token.

javascript
const response = await fetch("https://api.example-books.com/orders", {
  headers: {
    Authorization: "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  },
});

Bearer is a literal word, part of the standard, <space>, then the actual token, usually a long, random-looking string. The server checks this header on every request, decides who’s asking, and either responds normally or rejects the request.

Where the Token Comes From

A token isn’t invented by the client, it comes from the server, typically after a login request.

javascript
async function login(email, password) {
  const response = await fetch("https://api.example-books.com/login", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ email, password }),
  });

  const data = await response.json();
  return data.token;
}

A real login endpoint checks the email and password, and if they’re correct, responds with a token, a string the server itself generated and will recognize on future requests. This course doesn’t cover building that server-side check, only using the token it returns.

Storing the Token

Once you have a token, every subsequent request needs it, which means it has to be saved somewhere between requests. localStorage (Module 5) is the common choice.

javascript
async function loginAndSave(email, password) {
  const token = await login(email, password);
  localStorage.setItem("authToken", token);
}

async function getOrders() {
  const token = localStorage.getItem("authToken");

  const response = await fetch("https://api.example-books.com/orders", {
    headers: {
      Authorization: `Bearer ${token}`,
    },
  });

  return response.json();
}

Saving the token once at login, then reading it back out of localStorage for every later request, means the user doesn’t have to log in again every time the page reloads, exactly the same reasoning behind saving anything else to localStorage.

401 vs. 403, Revisited

Both status codes (introduced last lesson) relate to authentication, but they mean different things, and reacting to them correctly matters.

javascript
const response = await fetch("https://api.example-books.com/orders", {
  headers: { Authorization: `Bearer ${token}` },
});

if (response.status === 401) {
  console.log("Not logged in, or the token expired. Redirect to login.");
} else if (response.status === 403) {
  console.log("Logged in, but not allowed to see this. Don't redirect to login, it won't help.");
}

401 Unauthorized really means “unauthenticated,” no valid token was sent at all, or it expired. The fix is logging in again. 403 Forbidden means the token is valid, the server knows exactly who’s asking, they’re just not allowed to do this specific thing, viewing another user’s private order, for instance. Sending them back to a login screen wouldn’t help, they’re already logged in, correctly, and logging in again changes nothing.

API Keys: A Simpler Alternative

Not every API uses login-based tokens. Some, especially ones meant for automated access rather than an individual logged-in user, use a fixed API key instead, issued once, used on every request.

javascript
const response = await fetch("https://api.example-weather.com/forecast?city=London", {
  headers: {
    "X-API-Key": "your-api-key-here",
  },
});

The exact header name varies by API, X-API-Key is common, some use Authorization for this too. Whichever pattern an API uses, its documentation states it explicitly, worth checking before assuming.

Try It

  1. Write a fetch() call to "https://api.example-books.com/profile" that sends a token stored in a variable called authToken as a Bearer token.
  2. Write a function getAuthToken() that reads a token from localStorage under the key "authToken", and returns null if none is saved.
  3. Given a response with status === 401, and a separate response with status === 403, write the different message you’d show a user for each, and explain why redirecting to a login page only makes sense for one of them.

Recap

  • Authentication is sent as a header, most commonly Authorization: Bearer <token>.
  • A token comes from the server, typically returned by a login request, and is commonly saved to localStorage so it survives a page reload.
  • 401 means not authenticated at all (or an expired token), fix it by logging in again. 403 means authenticated, but not permitted, logging in again won’t change anything.
  • Some APIs use a fixed API key in a header instead of a login-based token, the exact header name depends on the specific API’s documentation.

Next lesson: CRUD operations end to end, creating, reading, updating, and deleting the same resource in one connected example.