👨Shadab Perwez
· API Authentication Workshop
🔐 Auth Playground — Step-by-Step Visualizer
Click through each auth flow to see exactly what happens: how credentials
are encoded, how the request packet travels to the server, which lines of code run,
and how the response returns to the client.
step in progress
step succeeded
step failed
step not started yet
1️⃣ Basic Auth
2️⃣ API Key
3️⃣ JWT (2-step)
Basic Authentication — 6 steps
▶ Run with these credentials
⚠ Run with WRONG password
↻ Reset
🖥️ Client (browser)
Step 1 · Combine
alice:password123
Step 2 · Base64-encode
YWxpY2U6cGFzc3dvcmQxMjM=
Step 3 · Build HTTP header
Authorization: Basic YWxp…
🌐 Network
🔒
HTTPS in production — base64 is NOT encryption!
🛠️ Server (Flask)
Step 4 · Parse header
request.headers["Authorization"]
Step 5 · Base64-decode + split
base64.b64decode(...).split(":", 1)
Step 6 · Check USERS dict
USERS.get(user) == password
📄 Server code that runs:
@app.route("/basic")
def basic_auth():
auth = request.headers.get("Authorization")
encoded = auth.split(" ")[1]
decoded = base64.b64decode(encoded).decode("utf-8")
username, password = decoded.split(":", 1)
if USERS.get(username) != password:
return jsonify({"error": "Invalid ..."}), 401
return jsonify({"message": f"Hello {username}!"})
📬 Server response:
// click "Run" above
API Key Auth — 4 steps
▶ Run with correct key
⚠ Run with WRONG key
↻ Reset
🖥️ Client
Step 1 · Read key
student123
Step 2 · Add custom header
X-API-Key: student123
🌐 Network
🔑
No encoding — just a header. Use HTTPS!
🛠️ Server
Step 3 · Read header
request.headers.get("X-API-Key")
Step 4 · Compare
key == API_KEY
📄 Server code that runs:
@app.route("/apikey")
def api_key_auth():
key = request.headers.get("X-API-Key")
if key != API_KEY:
return jsonify({"error": "Invalid or missing API key"}), 401
return jsonify({"message": "Access granted using API Key!"})
📬 Server response:
// click "Run" above
JWT Auth — 2 phases, 10 steps
▶ Phase 1: POST /login
⚠ Login with WRONG password
▶ Phase 2: GET /jwt with token
⚠ Phase 2 with TAMPERED token
↻ Reset
🖥️ Client
Step 1 · Build JSON body
{"username":"alice","password":"…"}
Step 2 · Receive & store token
token = "eyJhbGci…"
Step 3 · Send token in header
Authorization: Bearer eyJhbGci…
🌐 Network
📨
Token = header.payload.signature (3 base64 parts)
🛠️ Server
Step 4 · Verify credentials
USERS[user] == password ?
Step 5 · Build payload + expiry
{"user": ..., "exp": +30min}
Step 6 · Sign with SECRET_KEY
jwt.encode(payload, KEY, HS256)
Step 7 · Parse "Bearer <token>"
auth.split(" ")[1]
Step 8 · Verify signature + exp
jwt.decode(token, KEY, HS256)
📄 Server code that runs:
@app.route("/login", methods=["POST"])
def login():
data = request.get_json()
if USERS.get(data["username"]) != data["password"]:
return jsonify({"error": "Invalid credentials"}), 401
payload = {"user": ..., "exp": now + 30min}
token = jwt.encode(payload, SECRET_KEY, "HS256")
return jsonify({"token": token})
@app.route("/jwt")
def jwt_protected():
token = request.headers["Authorization"].split(" ")[1]
payload = jwt.decode(token, SECRET_KEY, ["HS256"]) # verifies signature + exp
return jsonify({"message": f"Hello {payload['user']}!"})
🔬 Decoded token contents (only shown after login):
// login first
📬 Server response:
// click "Phase 1" above