Sitemap
Aysha

Aysha

How Your API Knows Who You Are (and What You Can Do)

8 min read15 hours ago

--

Imagine opening an online shopping app. You log in, browse products, check your orders, and update your profile.

You don’t have to enter your password every time you do something. The app already knows who you are.

But how?

HTTP is stateless. This means each request is independent. The server doesn’t automatically remember who sent the previous request.

So how does your API know that request #2 comes from the same person who logged in a minute ago?

One popular solution is JWT (JSON Web Token).

In this article, we’ll understand how JWT works, what information it carries, how APIs verify it, and how RBAC (Role-Based Access Control) determines what a user can do.

1. First, the problem: How do we remember users?

Let’s say Sara logs into our shopping application.

She enters her email and password. The server verifies her credentials and lets her in.

Now Sara wants to view her orders.

But HTTP doesn’t remember that she just logged in. The new request doesn’t automatically carry her identity.

We need a way to recognize her.

One traditional solution is server-side sessions.

How sessions work

Here’s what happens:

  1. Sara logs in with her credentials.
  2. The server verifies them and creates a session.
  3. The server stores that session in a database or session store.
  4. It sends Sara a session ID, usually through a cookie.
  5. On every future request, Sara’s browser sends that cookie.
  6. The server looks up the session ID to find out who she is.

The session ID is like a reference number. It doesn’t contain all the information about Sara; it helps the server find her stored session.

This works well, but there’s something to consider. The server needs to remember the session.

If our application runs on multiple servers, they need access to the same session store. Otherwise, one server might recognize Sara while another doesn’t.

This is where JWT offers a different approach.

What if the token carries the information?

Instead of looking up a session every time, the server can issue Sara a signed token containing information about her identity.

Whenever Sara makes another request, she sends that token.

The API verifies the token’s signature and checks its claims to determine whether it can be trusted.

It doesn’t need to look up a session for every request.

This is the main advantage of using JWTs for stateless authentication.

2. What is a JWT?

A JWT (JSON Web Token) is a compact string that carries information between two parties.

In our example, the authentication server issues Sara a JWT after successfully verifying her login credentials.

A commonly used signed JWT consists of three parts separated by dots (.):

xxxxx.yyyyy.zzzzz
│ │ │
Header Payload Signature

1. Header

The header contains information about the token, including the signing algorithm.

For example:

{
"alg": "HS256",
"typ": "JWT"
}

Here, HS256 tells us that the token uses HMAC with SHA-256 to create its signature.

2. Payload

The payload contains claims, which are simply pieces of information about the user or token.

For example:

{
"sub": "123",
"name": "Sara",
"roles": ["customer"],
"iat": 1799990000,
"exp": 1799993600
}

This tells us:

  • sub: Sara's user ID is 123.
  • name: Her name is Sara.
  • roles: She has the customer role.
  • iat: When the token was issued.
  • exp: When the token expires.

3. Signature

The signature is what allows the API to verify that the token hasn’t been modified.

When the authentication server creates the token, it signs the encoded header and payload using its signing key.

Later, when Sara sends the token to the API, the API verifies that signature.

If someone changes the payload, the signature will no longer match, and verification will fail.

An important rule: JWT payloads are encoded, not encrypted.

Anyone who gets hold of a normal signed JWT can decode and read its header and payload.

The signature protects their integrity; it doesn’t hide their contents.

So never put passwords, private keys, or sensitive secrets inside a JWT.

3. How does the authentication flow work?

Now let’s connect everything.

Sara has successfully logged in. The authentication server has issued her a JWT.

What happens when she tries to view her orders?

Here’s the complete flow:

  1. Login: Sara sends her email and password to the authentication server.
  2. Token issued: The server verifies her credentials and generates a signed JWT.
  3. Request: Sara’s application sends a request to the API with the token in the authorization header.
  • GET /orders Authorization: Bearer <token>
  1. Verification: The API verifies the token’s signature and checks important claims, such as its expiry, issuer, and audience.
  2. Response: If the token is valid and Sara is allowed to access the resource, the API returns her orders
Press enter or click to view image in full size

But what if something goes wrong?

  • 401 Unauthorized: The request has missing, invalid, or expired authentication credentials.
  • 403 Forbidden: Sara is authenticated, but she doesn't have permission to perform the requested action.

Notice the difference: authentication establishes who Sara is. Authorization determines what she can access.

Also, the resource server doesn’t necessarily need to contact the authentication server for every request. It can verify the token locally using a trusted signing key.

4. Access tokens vs. Refresh tokens

There is one problem with JWTs.

What happens if someone steals Sara’s token?

If an attacker gets a valid access token, they may be able to use it until it expires.

We could make tokens last for a very long time, but that increases the damage a stolen token can cause.

Instead, applications commonly use two types of tokens.

Access token

The access token is what Sara sends with her API requests.

Get Aysha’s stories in your inbox

Join Medium for free to get updates from this writer.

It should have a relatively short lifetime, often around 5–15 minutes, depending on the application’s security requirements.

Refresh token

The refresh token is used to obtain a new access token when the old one expires.

It usually has a longer lifetime and is not sent with every API request.

Here’s how they work together:

  1. Sara logs in.
  2. The server issues an access token and a refresh token.
  3. Sara uses the access token to access protected endpoints.
  4. The access token expires.
  5. Her application sends the refresh token to the authentication server.
  6. If the refresh token is valid, the server issues a new access token.

Sara doesn’t have to enter her password again.

But refresh tokens need protection too.

A common approach is to store refresh-token records server-side, protect their values, rotate them whenever they’re used, and detect reuse of previously rotated tokens.

If an old refresh token is reused, the server can revoke the associated token family.

One important detail: revoking a refresh token prevents future access tokens from being issued through it. It doesn’t automatically invalidate an access token that has already been issued.

That is why short-lived access tokens are useful.

5. Adding RBAC: What can a user actually do?

So far, we’ve answered one question:

Who is Sara?

But our shopping application needs to answer another question:

What is Sara allowed to do?

For example:

  • Sara can view products
  • Sara can view her own orders.
  • Sara cannot delete products.
  • An admin can add, update, and delete products.

This is where authorization comes in.

There are two concepts to understand:

  • Authentication: Verifies who you are.
  • Authorization: Determines what you’re allowed to do.

What is RBAC?

RBAC stands for Role-Based Access Control.

Instead of assigning individual permissions to every user, we group permissions into roles.

For example:

Press enter or click to view image in full size

We assign users a role, and that role determines which permissions they receive.

For example, Sara’s JWT might contain:

{
"sub": "123",
"roles": ["customer"]
}

An admin might have:

{
"sub": "456",
"roles": ["admin"]
}

When Sara makes a request to delete a product, the API first verifies her JWT.

Then it checks her role and determines whether that role has permission to perform the action.

Since Sara is a customer, the API rejects the request with 403 Forbidden.

Important: Never trust a role simply because it appears in a decoded JWT. Verify the token’s signature and claims first. Also remember that roles inside a token can become outdated if a user’s permissions change before the token expires.

This is how RBAC helps applications control access to protected resources.

6. Common Vulnerabilities in JSON Web Tokens

JWT makes authentication convenient, but a poorly implemented authentication system can introduce serious security vulnerabilities.

1. Weak signing secrets

Suppose an application uses HS256 with a secret like:

secret123

An attacker can attempt to guess the secret offline.

If they discover it, they can create their own valid signatures and forge tokens.

How to prevent it: Use a cryptographically random secret of at least 256 bits (32 bytes) for HS256. Alternatively, use an asymmetric algorithm such as RS256 or ES256, with proper private-key protection.

2. Token theft through XSS

Cross-Site Scripting (XSS) happens when an attacker manages to inject malicious JavaScript into a website.

If access tokens are stored in localStorage, injected JavaScript can read and steal them.

How to prevent it: Consider storing browser authentication cookies with:

  • HttpOnly: Prevents JavaScript from reading the cookie.
  • Secure: Sends the cookie only over HTTPS.
  • SameSite: Controls when the browser sends the cookie in cross-site requests.

A Content Security Policy (CSP) also helps reduce the risk of XSS.

However, HttpOnly doesn't completely solve XSS. Malicious JavaScript running on the page may still make requests as the logged-in user.

3. Stolen refresh tokens

Refresh tokens usually live longer than access tokens.

If someone steals one, they may be able to keep obtaining new access tokens.

How to prevent it: Use refresh-token rotation, protect refresh tokens against theft, track their usage, and revoke the associated token family if a previously rotated token is reused.

4. Cross-Site Request Forgery (CSRF)

When authentication relies on cookies, browsers automatically attach those cookies to matching requests.

An attacker could exploit this behavior by tricking a logged-in user into sending an unwanted request to the application.

For example, a malicious website might attempt to trigger a request that changes Sara’s account details.

How to prevent it: Use appropriate CSRF protections, such as CSRF tokens and SameSite=Lax or Strict cookies where suitable.

SameSite provides useful defense-in-depth, but shouldn’t automatically be treated as a complete replacement for CSRF protection.

5. JWT algorithm attacks

JWT headers contain an alg field that identifies the signing algorithm.

If an API blindly trusts whatever algorithm the token specifies, an attacker may exploit that behavior.

Two examples are:

  • alg: none: Attempts to make the server accept an unsigned token.
  • Algorithm confusion: Attempts to trick a server configured for RS256 into treating an RSA public key as an HMAC secret.

How to prevent it: Configure an explicit allowlist of accepted algorithms in your JWT verification library. Make sure the key type matches the expected algorithm, and never rely on the token header alone to determine how it should be verified.

7. Go deeper

If you want to understand JWT and authentication security in more detail, these are useful resources:

Final thoughts

JWT gives applications a way to carry verifiable identity information between requests. But authentication is only one part of the picture.

You still need to think about authorization, token expiration, refresh-token security, and how permissions are enforced.

A valid token tells your API who the user is. It doesn’t automatically mean the user is allowed to do everything.

--

--