# OAuth2 Tokens Explained

OAuth2 relies on tokens to grant access to resources securely. But not all tokens serve the same purpose. Understanding **Access Tokens, Refresh Tokens, and ID Tokens** is key to implementing authentication correctly.

## The Three Types of Tokens

OAuth2 defines **Access Tokens** and **Refresh Tokens**, while **ID Tokens** come from OpenID Connect (OIDC), an authentication layer on top of OAuth2.

Each serves a different purpose:

- **Access Token** → Used to authorize API requests
- **Refresh Token** → Used to obtain new Access Tokens
- **ID Token** → Represents user identity (OIDC only)

### Access Tokens

Access Tokens are short-lived and sent with API requests to grant access to protected resources. They can be **opaque** (random strings validated by the authorization server) or **JWTs** (self-contained tokens with encoded claims).

```json
{
  "iss": "https://idp.example.com",
  "sub": "user-123",
  "aud": "https://api.example.com",
  "exp": 1714759200,
  "scope": "read:contacts"
}
```

APIs must **always validate** the Access Token before accepting a request. If a JWT is used, it should be verified against the authorization server’s public keys.

### Refresh Tokens

Refresh Tokens are long-lived and used to obtain new Access Tokens when they expire. They **should never be exposed to the frontend** because they allow attackers to generate new tokens indefinitely if stolen.

Instead, they should be **stored securely on the server**, often in a session.

```txt
POST /token
Host: idp.example.com
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token&
client_id=YOUR_CLIENT_ID&
refresh_token=YOUR_REFRESH_TOKEN
```

### ID Tokens (OpenID Connect)

ID Tokens are **not** part of OAuth2 but come from OpenID Connect. They contain identity information about the user and are **always JWTs**.

Unlike Access Tokens, ID Tokens **should not be used to authorize API requests**. They are only meant for authentication.

```json
{
  "iss": "https://idp.example.com",
  "sub": "user-123",
  "email": "user@example.com",
  "name": "John Doe",
  "exp": 1714759200
}
```

## Token Storage Strategies

How tokens are stored depends on the application architecture:

- **Backend-for-Frontend (BFF)** → Store **Refresh Tokens** securely in a backend session.
- **SPAs & Mobile Apps** → Store **Access Tokens** in memory, avoid storing Refresh Tokens.
- **Server-to-Server APIs** → Use only Access Tokens (no need for Refresh Tokens).

## Security Considerations

Access Tokens **should never be stored in localStorage or sessionStorage** due to XSS risks. The safest approach is to use **HTTP-only cookies**.

If the app is a **purely client-side SPA**, the best approach is:

- Store the Access Token in memory
- Use short-lived Access Tokens
- Refresh the token frequently

## Why Refresh Tokens Are Risky in the Frontend

If a Refresh Token is stolen, an attacker can continuously generate new Access Tokens. This is why they **should always be stored on the server**.

Backend-for-Frontend (BFF) architecture solves this problem by keeping Refresh Tokens in a secure session and issuing **short-lived Access Tokens** to the frontend.

If you **can’t use a BFF**, a good alternative is making sure the **frontend and API share the same domain** so tokens can be stored in **HTTP-only cookies** managed by the API. This keeps them secure while avoiding client-side storage risks.

## ID Tokens vs. Access Tokens

An API should **never accept an ID Token as an Access Token**.

- **ID Token** → Identifies the user (who they are)
- **Access Token** → Authorizes actions (what they can do)

## Best Practices

To ensure a secure OAuth2 implementation:

✅ Use **short-lived** Access Tokens  
✅ Store Refresh Tokens **only on the backend**  
✅ Use **PKCE** for SPAs & mobile apps  
✅ Rotate Refresh Tokens to limit risks  
✅ Never use an ID Token to authorize API calls

## Conclusion

Understanding the differences between Access, Refresh, and ID Tokens is essential for designing **secure authentication and authorization flows**.

If you’re building an OAuth2-based app, knowing where to store tokens and how to use them properly **makes all the difference**.

---

Want to master secure OAuth2 flows in React Router apps?

📘 My book *React Router OAuth2 Handbook* is now available!

It covers everything from the basics to advanced topics like PKCE, refresh tokens, and E2E auth testing.

→ [books.sergiodxa.com/release](https://go.sergiodxa.com/x6EE88z)