Getting Past the Gate: API Keys, Bearer/JWT & OAuth2
Most real endpoints are locked. If you can't automate getting through the door, you can't test what's behind it — so this is a must-have skill, not a nice-to-have.
The idea, in one line
Almost every locked API uses one of three ways to check who you are. Learn these three and you can automate the door on nearly anything.
The three schemes
- API key — a fixed secret you send on every call, usually in a header like
X-API-Keyor as a query param. Simplest to automate. Never hard-code it; read it from an environment variable. - Bearer / JWT — you send
Authorization: Bearer <token>. A JWT is a signed token with an expiry built in, so a token can run out mid-suite and give you a surprise 401 — a real failure mode worth testing. - OAuth2 — the token isn't handed to you; you earn it. You POST your client id and secret to a token endpoint, get back an
access_token, then attach it as a Bearer header on every later call.
See it work
OAuth2's client-credentials flow is really just two steps: fetch a token, then use the token. That's the flow worth automating end to end and walking an interviewer through.
▸ try it
import os, requests
# Step 1: trade your secret for a short-lived token.
def get_token(session):
resp = session.post(
"https://auth.example.com/oauth/token",
data={"grant_type": "client_credentials",
"client_id": os.environ["CLIENT_ID"],
"client_secret": os.environ["CLIENT_SECRET"]},
timeout=5)
resp.raise_for_status()
return resp.json()["access_token"]
# Step 2: attach it as a Bearer header for every later call.
def test_authorized_call():
s = requests.Session()
s.headers["Authorization"] = f"Bearer {get_token(s)}"
r = s.get("https://api.example.com/me", timeout=5)
assert r.status_code == 200Read it top to bottom: you asked the token desk for a pass, put that pass on the session so every call carries it, then made an authorized request. Fetch, then use.
Advanced — keep it safe and prove the lock works
- Keep every secret in
os.environ, never in the code - Put the token on a
Sessionso it applies to all calls automatically - Add a negative test: a request with no Authorization header should return 401
Grounded in the Requests quickstart (custom headers) and MDN HTTP Authorization reference
All lessons in API Automation from Zero to Confident
- The HTTP Mental Model & Your First Postman Collection
- Recreate It in Code: requests + pytest with Shared State
- Trust the Shape: Schema Validation & Negative Testing
- Getting Past the Gate: API Keys, Bearer/JWT & OAuth2
- SQL for Testers: Prove the API Actually Wrote to the DB
- Mocking & Contracts: Fast, Offline, Reliable Tests