Handling Authentication
- APIs often require authentication to control access, rate limits, and auditing.
- Without authentication, requests to protected endpoints will fail with codes like 401 (Unauthorized) or 403 (Forbidden).
- This section demonstrates a simple GET to a protected endpoint, illustrating why auth is needed.
Why Authentication?
- Authentication tells the API who you are, enabling personalized data and higher rate limits.
- It prevents unauthorized access to private resources and supports auditing of actions.
- Authenticated requests often succeed where anonymous requests would be blocked or limited.
GITHUB_ENDPOINT = "https://api.github.com"
HTTPBIN_ENDPOINT = "https://httpbin.org"
import requests
urls = {
"public_endpoint": f"{GITHUB_ENDPOINT}/zen",
"protected_endpoint": f"{GITHUB_ENDPOINT}/user",
}
for description, url in urls.items():
res = requests.get(url, timeout=5)
print(f"{description} ({url}) : {res.status_code}")
print(res.text[:200])
Basic Authentication
- Basic Auth sends a username and password with each request, encoded in the
Authorization header.
requests accepts an auth=(username, password) tuple and handles encoding automatically.
- Servers return
401 Unauthorized when credentials are missing or incorrect.
import requests
import json
url = f"{HTTPBIN_ENDPOINT}/basic-auth/myuser/myotherpwd"
try:
res = requests.get(url, auth=("myuser", "mypasswd"), timeout=10)
res.raise_for_status()
print(f"Status code: {res.status_code}")
print("Response JSON:")
print(json.dumps(res.json()))
except requests.exceptions.HTTPError as err:
print(err)
Token-Based Authentication
- Modern APIs use API keys or bearer tokens passed via the
Authorization header.
- For GitHub PATs, use `Authorization: token - Always load tokens from environment variables to avoid hardcoding secrets.
import requests
import os
from dotenv import load_dotenv
load_dotenv(override=True)
token = os.getenv("GH_PAT", "")
print(f"Token: {token[:15]}")
urls = {
"public_endpoint": f"{GITHUB_ENDPOINT}/zen",
"protected_endpoint": f"{GITHUB_ENDPOINT}/user",
}
for description, url in urls.items():
try:
headers = {
"Authorization": f"Bearer {token}"
}
res = requests.get(url, headers=headers, timeout=10)
res.raise_for_status()
print(f"Status code: {res.status_code}")
print(f"Authenticated user: {res.json().get("login")}")
except requests.exceptions.JSONDecodeError as err:
print(f"Invalid JSON in response body. Defaulting to text:")
print(res.text[:200])
except requests.exceptions.HTTPError as err:
print(err)
Common Pitfalls & How to Avoid Them
- Using the wrong header format (e.g.,
Bearer vs token) causes 401/403 errors. Follow API docs.
- Hardcoding secrets risks accidental exposure; always use environment variables or secret managers.
python