API Authentication Best Practices - API Keys, OAuth, JWT Guide 2026

Published Feb 20, 2026 · Tutorial · 5 min read

Complete guide to API authentication: API keys, OAuth 2.0, JWT tokens, rate limiting, and security best practices for REST APIs in 2026.

API authentication is the gatekeeper of your web service. Whether you're building a public API, a microservice, or integrating with third-party services, understanding authentication methods is critical. This guide covers the three most popular approaches — API keys, OAuth 2.0, and JWT tokens — with practical code examples and security recommendations for 2026.

API Authentication Overview

Authentication answers the question: "Who is making this request?" Authorization answers: "What are they allowed to do?" In REST APIs, authentication typically happens via HTTP headers, query parameters, or cookies. The method you choose depends on your use case:

API Key Authentication

API keys are the simplest and most widely used authentication method for REST APIs. Services like Google Maps, Stripe, OpenAI, and DevProToolkit all use API keys.

How API Keys Work

  1. Developer signs up and receives a unique API key (e.g., sk_live_abc123...)
  2. Developer sends the key with every request, typically in a header
  3. Server validates the key, checks rate limits, and processes the request
  4. Server logs usage per key for billing and analytics

Implementation Example

# Calling an API with an API key (Python)
import requests

response = requests.get(
    "https://api.commandsector.in/api/qr/generate",
    params={"data": "https://example.com", "size": 300},
    headers={"X-API-Key": "your_api_key_here"}
)

# The server validates your key before processing
print(response.status_code)  # 200 if valid, 401 if invalid

Server-Side Validation (FastAPI)

from fastapi import FastAPI, Request, HTTPException

app = FastAPI()

async def validate_api_key(request: Request):
    api_key = request.headers.get("X-API-Key")
    if not api_key:
        raise HTTPException(401, "Missing API key")

    # Look up key in database
    user = await db.get_user_by_key(api_key)
    if not user or not user.is_active:
        raise HTTPException(401, "Invalid API key")

    # Check rate limits
    if await is_rate_limited(user):
        raise HTTPException(429, "Rate limit exceeded")

    return user

@app.get("/api/resource")
async def get_resource(request: Request):
    user = await validate_api_key(request)
    # Process request...
    return {"data": "your resource"}

When to Use API Keys

See API Keys in Action

Get a free API key for 13 production APIs — no credit card required.

Get Free API Key

OAuth 2.0 for APIs

OAuth 2.0 is the industry standard for delegated authorization. It allows users to grant third-party apps limited access to their resources without sharing passwords. You've used OAuth every time you clicked "Sign in with Google" or "Connect your GitHub account."

OAuth 2.0 Flow (Authorization Code)

  1. User clicks "Connect" in your app
  2. App redirects to the OAuth provider (e.g., Google)
  3. User grants permission
  4. Provider redirects back with an authorization code
  5. App exchanges the code for an access token
  6. App uses the access token to call APIs on behalf of the user

When to Use OAuth 2.0

JWT Token Authentication

JSON Web Tokens (JWTs) are compact, self-contained tokens that carry user identity and claims. They're signed (and optionally encrypted) so the server can verify them without a database lookup.

JWT Structure

# A JWT has three parts: header.payload.signature
# Example:
# eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxMjN9.abc123signature

import jwt
from datetime import datetime, timedelta

SECRET_KEY = "your-secret-key"

# Create a token
token = jwt.encode({
    "user_id": 123,
    "email": "dev@example.com",
    "exp": datetime.utcnow() + timedelta(hours=24)
}, SECRET_KEY, algorithm="HS256")

# Verify a token
try:
    payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
    print(f"User ID: {payload['user_id']}")
except jwt.ExpiredSignatureError:
    print("Token expired")
except jwt.InvalidTokenError:
    print("Invalid token")

When to Use JWT

Rate Limiting & Quotas

Rate limiting is essential for any API. It prevents abuse, ensures fair usage, and enables tiered pricing.

Common Rate Limiting Strategies

StrategyHow It WorksBest For
Fixed WindowCount requests per time window (e.g., 100/hour)Simple APIs
Sliding WindowRolling count that smooths traffic spikesProduction APIs
Token BucketTokens refill at a constant rate; each request costs a tokenHigh-traffic APIs
Per-Key QuotasDaily/monthly limits per API keyFreemium models

Tiered Pricing Example

TierDaily RequestsRate LimitPrice
Free10010/minute$0
Pro10,000120/minute$9.99/mo
Enterprise1,000,000600/minute$49.99/mo

This is the exact pricing model used by DevProToolkit API Hub, which offers 13 APIs under a single key with tiered access.

Security Best Practices

  1. Always use HTTPS — Never transmit API keys or tokens over unencrypted HTTP
  2. Store keys securely — Use environment variables, not hardcoded strings
  3. Rotate keys regularly — Allow users to regenerate keys without downtime
  4. Use short-lived tokens — JWTs should expire within hours, not days
  5. Log all access — Track which keys access which endpoints for audit trails
  6. Implement IP allowlisting — For enterprise keys, restrict to known IPs
  7. Hash stored keys — Store only hashed versions of API keys in your database
  8. Return proper error codes — Use 401 for invalid auth, 403 for insufficient permissions, 429 for rate limits

Method Comparison

FeatureAPI KeysOAuth 2.0JWT
ComplexityLowHighMedium
User contextNo (machine identity)YesYes
StatelessNo (DB lookup)NoYes
RevocableYes (delete key)YesHard (need blocklist)
Best forPublic APIsUser-facing appsMicroservices
Example servicesStripe, OpenAI, DevProToolkitGoogle, GitHubAuth0, Firebase

Full Implementation: API Key System with FastAPI

Here's a complete API key authentication system you can copy into your FastAPI project:

from fastapi import FastAPI, Request, HTTPException, Depends
import sqlite3, secrets, hashlib, time
from functools import wraps

app = FastAPI()

def create_api_key(email: str, tier: str = "free"):
    """Generate and store a new API key."""
    raw_key = f"sk_{secrets.token_hex(24)}"
    hashed = hashlib.sha256(raw_key.encode()).hexdigest()

    conn = sqlite3.connect("api_keys.db")
    conn.execute(
        "INSERT INTO api_keys (key_hash, email, tier) VALUES (?, ?, ?)",
        (hashed, email, tier)
    )
    conn.commit()
    conn.close()

    return raw_key  # Only returned once, never stored in plain text

RATE_LIMITS = {
    "free": {"daily": 100, "per_minute": 10},
    "pro": {"daily": 10000, "per_minute": 120},
}

async def get_api_user(request: Request):
    """Dependency that validates API key and enforces rate limits."""
    key = request.headers.get("X-API-Key", "")
    if not key:
        raise HTTPException(401, {"error": "Missing X-API-Key header"})

    hashed = hashlib.sha256(key.encode()).hexdigest()
    conn = sqlite3.connect("api_keys.db")
    row = conn.execute(
        "SELECT email, tier, is_active FROM api_keys WHERE key_hash = ?",
        (hashed,)
    ).fetchone()
    conn.close()

    if not row:
        raise HTTPException(401, {"error": "Invalid API key"})
    if not row[2]:
        raise HTTPException(403, {"error": "API key disabled"})

    return {"email": row[0], "tier": row[1]}

@app.get("/api/protected")
async def protected_endpoint(user=Depends(get_api_user)):
    return {"message": f"Hello {user['email']}!", "tier": user["tier"]}

This pattern is used by professional API services like DevProToolkit, which manages 13 APIs, 104+ endpoints, and multiple pricing tiers with a single unified authentication system.

Skip Building Auth from Scratch

DevProToolkit provides 13 ready-to-use APIs with built-in authentication, rate limiting, and usage tracking. Get a free key and start building.

Get Free API Key   Try API Playground

Frequently Asked Questions

What is the best API authentication method?

It depends on your use case. API keys are best for public developer APIs and server-to-server communication. OAuth 2.0 is best for user-facing apps that need delegated access. JWT tokens are best for stateless auth in microservice architectures.

Should I use API keys or OAuth?

Use API keys when your consumers are developers or machines. Use OAuth when end users need to grant and revoke access. Many services (like GitHub) offer both: API keys for personal use and OAuth for third-party apps.

How do I implement rate limiting?

Start with a fixed window counter (count requests per API key per day). For production, use a sliding window or token bucket algorithm. Store counters in Redis for performance, or SQLite for simplicity.

Quick Start

Get your free API key and start making requests in minutes.

curl "http://147.224.212.116/api/..." \
  -H "X-API-Key: YOUR_API_KEY"

Start Using This API Today

Get a free API key with 100 requests/day. No credit card required.

Get Free API Key