Nearly every real API requires credentials, and getting auth right keeps secrets safe.
The auth= argument attaches credentials to a request. Common schemes:
- Basic auth:
auth=("user", "pass"), a shortcut forHTTPBasicAuth. The credentials are only base64-encoded, so use it over HTTPS only. - Digest auth:
HTTPDigestAuth("user", "pass"), rare today. - Bearer tokens (OAuth 2 access tokens, API keys): set the header
Authorization: Bearer <token>, either per request or on a session'sheaders. - API keys in a custom header such as
X-API-Key, or occasionally in the query string.
For anything custom, subclass requests.auth.AuthBase and implement __call__(self, r), which receives the PreparedRequest and returns it after modifying headers. This keeps auth logic in one place and lets you set session.auth = MyAuth(...). Request-signing schemes (HMAC signatures over the body) are written this way.
Requests also reads credentials from a ~/.netrc file automatically when no auth= is given. That surprises people when a header they set by hand is replaced, so be aware of it.
Security habits:
- Load secrets from environment variables or a secret manager, not source code.
- Requests strips the
Authorizationheader when a redirect goes to a different host, so credentials do not leak to third parties. - Never log full request headers.
For OAuth 2 flows (getting and refreshing tokens), use a library such as requests-oauthlib or authlib rather than writing the flow by hand.
Example
import os
import requests
from requests.auth import AuthBase
r = requests.get("https://httpbin.org/basic-auth/ada/s3cret",
auth=("ada", "s3cret"), timeout=10)
print(r.status_code, r.json()) # 200 {'authenticated': True, 'user': 'ada'}
class BearerAuth(AuthBase):
def __init__(self, token):
self.token = token
def __call__(self, r): # r is the PreparedRequest
r.headers["Authorization"] = f"Bearer {self.token}"
return r
token = os.environ.get("API_TOKEN", "demo-token")
with requests.Session() as s:
s.auth = BearerAuth(token)
r = s.get("https://httpbin.org/bearer", timeout=10)
print(r.json()) # {'authenticated': True, 'token': 'demo-token'}
print(requests.get("https://httpbin.org/bearer", timeout=10).status_code) # 401Remember
- auth=(user, pass) for Basic; an Authorization header or AuthBase for tokens
- AuthBase.__call__ modifies the prepared request; set it on a session
- Load secrets from the environment; Authorization is dropped on cross-host redirects
Watch out for
- Hard-coding API tokens in source code that ends up in version control.