Many modern APIs use Bearer Token authentication (often JWTs - JSON Web Tokens) to authorize requests. This involves sending an Authorization header with the value Bearer <your_token>. Python's popular requests library and the built-in urllib module both provide ways to include this header in your HTTP requests.
This guide demonstrates how to send Bearer tokens correctly using requests (directly and via a custom auth class) and urllib.request.
Understanding Bearer Token Authentication
Bearer authentication is an HTTP authentication scheme involving security tokens called bearer tokens. The client sends this token in the Authorization header of the HTTP request to access protected resources. The server receiving the request verifies the token to grant access. The standard format for the header is:
Authorization: Bearer <token>
Where <token> is the actual token string (e.g., a long JWT).
Method 1: Using requests with the headers Argument (Recommended)
The requests library (install via pip install requests) provides the most straightforward way to add custom headers, including the Authorization header.
Setting the Authorization Header
You create a Python dictionary representing the headers and pass it to the headers parameter of the request function (requests.get, requests.post, etc.).
Example: POST Request with Bearer Token
import requests
import json # Often needed for request/response body
API_ENDPOINT = 'https://jsonplaceholder.typicode.com/posts' # Example endpoint
YOUR_BEARER_TOKEN = 'YOUR_ACTUAL_SECRET_TOKEN_HERE'
post_data = {'title': 'foo', 'body': 'bar', 'userId': 1}
request_headers = {
'Authorization': f'Bearer {YOUR_BEARER_TOKEN}',
'Content-Type': 'application/json' # Often needed for POST data
}
try:
print(f"Sending POST request to {API_ENDPOINT}...")
response = requests.post(
API_ENDPOINT,
headers=request_headers,
json=post_data, # Use json parameter for dict data -> auto-sets Content-Type
timeout=10 # Good practice to set a timeout
)
response.raise_for_status() # Raise an exception for bad status codes (4xx or 5xx)
print(f"Status Code: {response.status_code}") # e.g., 201 Created
response_data = response.json()
print("Response JSON:")
print(response_data)
except requests.exceptions.RequestException as e:
print(f"An error occurred: {e}")Example Output (if token was valid and endpoint worked):
Sending POST request to https://jsonplaceholder.typicode.com/posts...
Status Code: 201
Response JSON:
{'title': 'foo', 'body': 'bar', 'userId': 1, 'id': 101}- We create the
request_headersdictionary. - The
'Authorization'key's value starts withBearerfollowed by the token. - This dictionary is passed via the
headers=argument torequests.post(). - The same
headersdictionary can be used withrequests.get(),requests.put(), etc.
Formatting the Header Value
You can construct the Authorization header string in several ways:
YOUR_BEARER_TOKEN = 'YOUR_ACTUAL_SECRET_TOKEN_HERE'
header_fstring = f'Bearer {YOUR_BEARER_TOKEN}'
print(f"f-string: '{header_fstring}'")
header_concat = 'Bearer ' + YOUR_BEARER_TOKEN
print(f"Concatenation: '{header_concat}'")
header_format = 'Bearer {}'.format(YOUR_BEARER_TOKEN)
print(f"str.format(): '{header_format}'")f-strings are generally the most readable option in modern Python.
Method 2: Using requests with a Custom AuthBase Class
For reusable authentication logic, especially if handling token refresh or complex schemes, requests allows you to create custom authentication classes inheriting from requests.auth.AuthBase.
Creating a BearerAuth Class
import requests
class BearerAuth(requests.auth.AuthBase):
"""Custom Auth class for Bearer Token."""
def __init__(self, token):
self.token = token
def __call__(self, request_obj):
request_obj.headers['Authorization'] = f'Bearer {self.token}'
return request_obj # Return the modified requestThis class takes the token during initialization and adds the correct header when attached to a request via the auth parameter.
Example: Using the Custom Class for GET/POST
import requests
API_ENDPOINT_USERS = 'https://jsonplaceholder.typicode.com/users/1' # GET example
API_ENDPOINT_POSTS = 'https://jsonplaceholder.typicode.com/posts' # POST example
YOUR_BEARER_TOKEN = 'YOUR_ACTUAL_SECRET_TOKEN_HERE'
post_data = {'title': 'new post', 'body': 'content', 'userId': 5}
bearer_auth = BearerAuth(YOUR_BEARER_TOKEN)
try:
print(f"\nSending GET request to {API_ENDPOINT_USERS}...")
response_get = requests.get(API_ENDPOINT_USERS, auth=bearer_auth, timeout=10)
response_get.raise_for_status()
print(f"GET Status Code: {response_get.status_code}")
except requests.exceptions.RequestException as e:
print(f"GET Error: {e}")
try:
print(f"\nSending POST request to {API_ENDPOINT_POSTS}...")
response_post = requests.post(API_ENDPOINT_POSTS, json=post_data, auth=bearer_auth, timeout=10)
response_post.raise_for_status()
print(f"POST Status Code: {response_post.status_code}")
print(f"POST Response: {response_post.json()}")
except requests.exceptions.RequestException as e:
print(f"POST Error: {e}")Using the auth parameter keeps the header logic separate from the main request call, which can be cleaner for complex authentication.
Method 3: Using urllib.request
Python's built-in urllib module can also send custom headers, though its API is generally considered less user-friendly than requests.
Adding Headers with urllib.request.Request
You need to create a Request object and add headers to it before opening the URL.
Example: POST Request with urllib
import urllib.request
import json # Needed to encode data and potentially decode response
API_ENDPOINT = 'https://jsonplaceholder.typicode.com/posts'
YOUR_BEARER_TOKEN = 'YOUR_ACTUAL_SECRET_TOKEN_HERE'
post_data_dict = {'title': 'urllib post', 'body': 'test', 'userId': 2}
encoded_data = json.dumps(post_data_dict).encode('utf-8')
request_headers = {
'Authorization': f'Bearer {YOUR_BEARER_TOKEN}',
'Content-Type': 'application/json; charset=utf-8' # Be explicit
}
req = urllib.request.Request(API_ENDPOINT, data=encoded_data, headers=request_headers, method='POST')
print(f"\nSending POST request to {API_ENDPOINT} using urllib...")
try:
with urllib.request.urlopen(req, timeout=10) as response:
print(f"Status Code: {response.getcode()}")
response_body_bytes = response.read()
response_body_str = response_body_bytes.decode('utf-8')
response_data = json.loads(response_body_str)
print("Response JSON (urllib):")
print(response_data)
except urllib.error.URLError as e:
print(f"urllib Error: {e}")
except json.JSONDecodeError as e:
print(f"JSON Decode Error: {e}")Note the need to manually encode the request data to bytes and decode the response bytes.
Example: GET Request with urllib
import urllib.request
import json
API_ENDPOINT = 'https://jsonplaceholder.typicode.com/users/1'
YOUR_BEARER_TOKEN = 'YOUR_ACTUAL_SECRET_TOKEN_HERE'
request_headers = {
'Authorization': f'Bearer {YOUR_BEARER_TOKEN}',
}
req = urllib.request.Request(API_ENDPOINT, data=None, headers=request_headers, method='GET')
print(f"\nSending GET request to {API_ENDPOINT} using urllib...")
try:
with urllib.request.urlopen(req, timeout=10) as response:
print(f"Status Code: {response.getcode()}")
response_body_bytes = response.read()
response_body_str = response_body_bytes.decode('utf-8')
response_data = json.loads(response_body_str)
print("Response JSON (urllib):")
print(response_data)
except urllib.error.URLError as e:
print(f"urllib Error: {e}")
except json.JSONDecodeError as e:
print(f"JSON Decode Error: {e}")Choosing the Right Method
requestswithheadersdict: Highly recommended for most use cases. It's simple, direct, and aligns well with how HTTP headers work.requestswith CustomAuthBase: Good for complex authentication logic, reusing authentication across multiple requests, or integrating with token refresh mechanisms. Might be overkill for simple bearer tokens.urllib.request: Use if you cannot have external dependencies (likerequests). Be prepared for more manual work involving data encoding/decoding and potentially more complex error handling.
Conclusion
Sending Bearer Token authentication with Python HTTP requests involves setting the Authorization header correctly.
- The
requestslibrary makes this easy via theheadersdictionary argument:headers={'Authorization': f'Bearer {token}'}. This is the preferred method for simplicity and readability. requestsalso supports custom authentication classes (auth=BearerAuth(token)) for more structured or reusable authentication logic.- The built-in
urllib.requestmodule requires manually creating aRequestobject and adding the header to itsheadersdictionary, along with manual handling of request/response body encoding.
Choose the method that best suits your project's dependencies and complexity requirements. For most applications, the requests library offers a superior developer experience.