Authentication & Headers
Bearer tokens, API keys, Basic auth, and how auth flows work
Free tier: read the explanation here. Upgrade to Pro for Drills, Speed challenges & Mastery badges.
UpgradeKnowledge Debt detected
You can study this freely — but your score may plateau if these foundations have gaps. The Mastery badge requires them to be solid.
Explanation
Authentication tells the server who you are. Authorization tells it what you're allowed to do.
Bearer Token (JWT) — most common:
python import httpx def make_request(token: str, url: str) -> dict: return httpx.get( url, headers={"Authorization": f"Bearer {token}"} ).json()
API Key — two common patterns:
python # 1. In header httpx.get(url, headers={"X-API-Key": api_key}) # 2. In query parameter (less secure — shows up in logs) httpx.get(url, params={"api_key": api_key})
Basic Auth — username:password base64 encoded:
python import httpx httpx.get(url, auth=("username", "password")) # Sets: Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
OAuth2 flow (simplified):
1. User clicks "Login with Google" 2. You redirect to Google with client_id + scopes 3. User grants permission 4. Google redirects back with a code 5. You exchange code → access_token (POST to token endpoint) 6. Use access_token as Bearer on subsequent requests 7. Refresh token when it expires
JWT structure (three base64 parts separated by dots): `` header.payload.signature eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjo0Mn0.abc123 `` The payload is not encrypted — it's just encoded. Don't put secrets in it.
Security rules:
- Always use HTTPS — tokens in HTTP are visible to anyone on the network
- Never log auth headers
- Store tokens in environment variables, never in code
Examples
Token refresh pattern
Token caching with expiry — avoids a token refresh on every request
import httpx
from datetime import datetime, timedelta
class APIClient:
def __init__(self, base_url: str, client_id: str, client_secret: str):
self.base_url = base_url
self.client_id = client_id
self.client_secret = client_secret
self._token: str | None = None
self._token_expires: datetime = datetime.min
def _get_token(self) -> str:
if self._token and datetime.now() < self._token_expires:
return self._token # reuse cached token
r = httpx.post(f"{self.base_url}/auth/token", json={
"client_id": self.client_id,
"client_secret": self.client_secret,
})
r.raise_for_status()
data = r.json()
self._token = data["access_token"]
self._token_expires = datetime.now() + timedelta(seconds=data["expires_in"] - 60)
return self._token
def get(self, path: str) -> dict:
token = self._get_token()
return httpx.get(
f"{self.base_url}{path}",
headers={"Authorization": f"Bearer {token}"},
).json()Reading JWT payload (without verification)
JWT payloads are just base64-encoded JSON — not encrypted, just signed
import base64
import json
def decode_jwt_payload(token: str) -> dict:
"""Read payload without verification — for debugging only."""
parts = token.split(".")
if len(parts) != 3:
raise ValueError("Not a valid JWT")
# Add padding back (base64url strips it)
payload = parts[1] + "=" * (4 - len(parts[1]) % 4)
return json.loads(base64.urlsafe_b64decode(payload))
token = "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjo0MiwiZXhwIjoxNzA0MDY3MjAwfQ.sig"
print(decode_jwt_payload(token)) # {'user_id': 42, 'exp': 1704067200}How well did you understand this?
Next in Web & HTTP
CORS