Skip to content
Home
API Authentication: JWT, OAuth2, and API Keys

API Authentication: JWT, OAuth2, and API Keys

API Development API Development 8 min read 1582 words Beginner ExcellentWiki Editorial Team

API authentication verifies the identity of clients making requests. Choosing the right authentication method is critical for security, usability, and scalability.

This guide covers the major authentication approaches: API keys, JWT (JSON Web Tokens), OAuth2, and session-based authentication, along with guidance on when to use each.

API Keys

API keys are the simplest form of authentication. The server generates a unique key for each client, and the client includes it in requests.

GET /api/users?api_key=abc123def456

Or more commonly in a header:

X-API-Key: abc123def456

Pros

  • Simple to implement and understand
  • No token expiry to manage (keys are long-lived)
  • Easy to revoke — delete the key from the database

Cons

  • Low security — keys can be intercepted and reused
  • No user context — cannot distinguish between users sharing a key
  • Prone to accidental exposure in code repositories

Best Practices

const apiKey = req.headers['x-api-key'];
const client = await db.clients.findByApiKey(apiKey);

if (!client) {
  return res.status(401).json({ error: 'Invalid API key' });
---

req.client = client;
next();

Never expose API keys in client-side code, URLs, or logs. Store them as environment variables or in a secrets manager. Use API keys only for server-to-server communication or public, read-only data.

JWT (JSON Web Tokens)

JWT is a compact, self-contained token format. The token contains JSON claims (user ID, roles, expiry) signed by the server. Clients present the token, and the server verifies the signature without consulting a database.

JWT Structure

A JWT consists of three Base64-encoded parts separated by dots:

header.payload.signature

Header: Token type and signing algorithm

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

Payload: Claims (data)

{
  "sub": "user_42",
  "name": "Alice Smith",
  "role": "admin",
  "iat": 1700000000,
  "exp": 1700003600
---

Signature: Verifies the token hasn’t been tampered with

Implementation

const jwt = require('jsonwebtoken');

// Sign (create token)
const token = jwt.sign(
  { userId: user.id, role: user.role },
  process.env.JWT_SECRET,
  { expiresIn: '1h' }
);

// Verify (validate token)
try {
  const decoded = jwt.verify(token, process.env.JWT_SECRET);
  req.user = decoded;
  next();
--- catch (err) {
  return res.status(401).json({ error: 'Invalid token' });
---

Pros

  • Stateless — no session storage required
  • Self-contained — carries user data and permissions
  • Works across domains and microservices

Cons

  • Cannot revoke individual tokens without a blocklist or short expiry
  • Token size grows with claims
  • Secret key management is critical

Best Practices

Use short expiration times (15-60 minutes). Implement refresh tokens for long-lived sessions. Store tokens securely — HTTP-only cookies for web apps, secure storage for mobile apps. Never store sensitive data in the payload (it is Base64-decoded, not encrypted).

OAuth2

OAuth2 is an authorization framework that lets third-party apps access resources on behalf of a user without sharing credentials. It is the standard behind “Sign in with Google” or “Connect to GitHub.”

Grant Types

Authorization Code Grant — The most common flow for web and mobile apps:

  1. App redirects user to the authorization server
  2. User authenticates and grants permission
  3. Authorization server returns a code
  4. App exchanges the code for an access token (and optionally a refresh token)

Client Credentials Grant — For server-to-server communication without a user context.

Implicit Grant — Deprecated for security reasons (use Authorization Code with PKCE instead).

Authorization Code with PKCE — Recommended for mobile and single-page apps. PKCE (Proof Key for Code Exchange) adds a cryptographic challenge that prevents authorization code interception attacks. The client generates a code verifier and a code challenge; the authorization server validates the challenge during token exchange.

OAuth2 Roles

  • Resource Owner — The user who owns the data
  • Client — The application requesting access
  • Authorization Server — Issues tokens after authentication
  • Resource Server — Hosts the protected resources

Implementation Example

const oauth2 = require('simple-oauth2');

const config = {
  client: {
    id: process.env.CLIENT_ID,
    secret: process.env.CLIENT_SECRET,
  },
  auth: {
    tokenHost: 'https://provider.example.com',
  },
---;

const client = new oauth2.AuthorizationCode(config);

// Redirect to authorization URL
const authorizationUri = client.authorizeURL({
  redirect_uri: 'https://myapp.com/callback',
---);

// Exchange code for token
const result = await client.getToken({
  code: req.query.code,
  redirect_uri: 'https://myapp.com/callback',
---);

Token Storage Strategies

How you store tokens on the client affects security and usability. For web applications, store access tokens in HTTP-only cookies to prevent XSS-based token theft. Set the Secure flag to restrict cookies to HTTPS connections and SameSite=Strict to prevent CSRF attacks. For mobile applications, use the platform’s secure storage — iOS Keychain for Swift apps, Android Keystore for Kotlin/Java apps, and React Native Keychain for cross-platform apps. Never store tokens in localStorage or sessionStorage for web applications — any XSS vulnerability exposes all tokens. For refresh tokens, consider using the BFF (Backend for Frontend) pattern where the backend stores the refresh token in an encrypted session cookie and proxies authenticated requests, keeping the long-lived credential off the client entirely.

SAML Authentication

Security Assertion Markup Language (SAML) is an XML-based authentication protocol commonly used in enterprise environments for single sign-on (SSO). Unlike OAuth2 which focuses on delegated authorization, SAML is primarily an authentication protocol that passes identity assertions between an identity provider (IdP) and a service provider (SP). In enterprise API scenarios, SAML is often used to authenticate users before issuing API credentials, with the SAML assertion exchanged for an API token through a federation gateway. SAML 2.0, standardized in 2005, remains widely deployed in corporate environments, particularly for integrations with Active Directory Federation Services (AD FS), Okta, and Azure AD. While SAML is more complex than OAuth2 due to its XML signature verification and certificate management requirements, it provides robust single sign-on for enterprise APIs where security requirements mandate federated identity management with existing corporate directories.

Session-Based Authentication

Sessions store authentication state on the server. The client receives a session ID (cookie).

app.post('/login', async (req, res) => {
  const user = await db.users.findByEmail(req.body.email);
  
  if (!user || !bcrypt.compare(req.body.password, user.password)) {
    return res.status(401).json({ error: 'Invalid credentials' });
  }
  
  req.session.userId = user.id;
  res.json({ success: true });
---);

app.get('/profile', (req, res) => {
  if (!req.session.userId) {
    return res.status(401).json({ error: 'Not authenticated' });
  }
  // Serve profile
---);

Pros

  • Easy to revoke — delete the session from the store
  • No token management on the client side
  • Mature ecosystem and libraries

Cons

  • Requires server-side storage (Redis, database)
  • Harder to scale horizontally — sessions must be shared or sticky
  • Not ideal for mobile or third-party API access

Choosing the Right Approach

ScenarioRecommended
Server-to-server APIAPI keys or JWT
Web application with loginSession or JWT with cookies
Mobile appJWT with refresh tokens
Third-party app accessOAuth2
MicroservicesJWT (stateless) or API keys

Security Best Practices

Always use HTTPS to prevent token interception. Implement rate limiting on authentication endpoints to prevent brute force attacks. Use secure, HttpOnly cookies for web applications. Store refresh tokens separately from access tokens. Rotate signing keys periodically. Log authentication failures and alert on unusual patterns.

FAQ

What is the difference between authentication and authorization? Authentication verifies identity (who you are). Authorization determines access rights (what you can do). API keys and JWTs handle both in practice, but OAuth2 separates them — the authorization server handles authentication, and the resource server enforces authorization.

Should I use JWT or session-based auth? JWT is stateless and works well for microservices and mobile apps. Session-based auth is simpler for traditional web applications and offers easy revocation. JWT is better for cross-domain scenarios; sessions are better when you need fine-grained server-side control.

How do I handle token refresh? Issue a short-lived access token (15-60 minutes) and a long-lived refresh token (days or months). When the access token expires, the client uses the refresh token to obtain a new access token. Store refresh tokens securely and allow users to revoke them individually.

What is PKCE and why is it important? PKCE (Proof Key for Code Exchange) prevents authorization code interception attacks in OAuth2. It generates a cryptographic challenge that only the legitimate client can solve. PKCE is required for mobile apps and single-page applications where the client secret cannot be stored securely.

How do I secure API keys in mobile apps? You cannot fully secure API keys in mobile apps — any key embedded in the app binary can be extracted. Use app attestation (SafetyNet, DeviceCheck), key hashing, and short-lived tokens obtained through an authentication flow. Never rely solely on API keys for mobile app security.

What is the difference between JWT and PASETO? PASETO (Platform-Agnostic Security Tokens) is a newer alternative to JWT that addresses several JWT security concerns. Unlike JWT which has multiple algorithm options (including weak ones like none), PASETO mandates specific, modern cryptographic algorithms — either symmetric (local) or asymmetric (public) modes with no algorithm confusion vulnerabilities. PASETO tokens are shorter and include versioned formats for future-proofing. Adoption is growing but JWT remains far more widely supported across platforms and libraries.

How do I implement API key rotation? Generate keys with a creation date prefix in the key itself (e.g., sk_2024_abc123) so your system knows when each key was issued without querying a database. Allow multiple active keys per client so consumers can rotate without downtime. Provide a grace period where both old and new keys are valid for 30-90 days. Alert when keys approach 80% of their rotation period. Revoke old keys automatically after the grace period expires and log any requests using revoked keys for audit purposes.

Conclusion

Authentication is a security-critical decision. Start simple, use well-established libraries, and never roll your own cryptography. The right choice depends on your clients (web, mobile, third-party), your scalability needs, and your security requirements. JWT with short-lived access tokens and refresh tokens covers most modern API scenarios.

For a comprehensive overview, read our article on Api Caching Strategies.

For a comprehensive overview, read our article on Api Design First Approach.

Section: API Development 1582 words 8 min read Beginner 756 articles in section Report inaccuracy Back to top