API
Python
Bearer Token
Authentication
Programming

Making an API call in Python with an API that requires a bearer token

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

A bearer token is usually sent in the Authorization header to prove that the request is allowed to access the API. In Python, the mechanics are simple: build the header, send the request, and handle failures carefully. The parts that actually matter are token safety, error handling, and making sure the token is not hard-coded into the script.

The Basic Request Pattern

The requests library is the usual starting point. A bearer token request looks like this:

python
1import requests
2
3url = "https://api.example.com/v1/profile"
4token = "YOUR_TOKEN_HERE"
5
6headers = {
7    "Authorization": f"Bearer {token}",
8    "Accept": "application/json",
9}
10
11response = requests.get(url, headers=headers, timeout=30)
12print(response.status_code)
13print(response.text)

The key line is the Authorization header. The API expects the token after the word Bearer.

Parsing JSON Responses Safely

If the API returns JSON, inspect the status first and then decode the body.

python
1import requests
2
3url = "https://api.example.com/v1/profile"
4token = "YOUR_TOKEN_HERE"
5
6headers = {
7    "Authorization": f"Bearer {token}",
8    "Accept": "application/json",
9}
10
11response = requests.get(url, headers=headers, timeout=30)
12response.raise_for_status()
13
14data = response.json()
15print(data)

raise_for_status() is useful because it turns HTTP error statuses such as 401 or 403 into exceptions immediately.

Do Not Hard-Code the Token

For real code, do not store the token directly in the source file. Use an environment variable instead.

python
1import os
2import requests
3
4url = "https://api.example.com/v1/profile"
5token = os.environ["API_TOKEN"]
6
7headers = {
8    "Authorization": f"Bearer {token}",
9    "Accept": "application/json",
10}
11
12response = requests.get(url, headers=headers, timeout=30)
13response.raise_for_status()
14print(response.json())

This is safer because the token can be rotated or injected by deployment tooling without changing the codebase.

Sending JSON Data With a Bearer Token

Many APIs require both authentication and a JSON body. In that case, pass the payload with json=.

python
1import os
2import requests
3
4url = "https://api.example.com/v1/items"
5token = os.environ["API_TOKEN"]
6
7headers = {
8    "Authorization": f"Bearer {token}",
9    "Accept": "application/json",
10}
11
12payload = {
13    "name": "demo-item",
14    "price": 19.99,
15}
16
17response = requests.post(url, headers=headers, json=payload, timeout=30)
18response.raise_for_status()
19print(response.json())

Using json= is better than manually serializing the body because requests also sets the JSON content type correctly.

Handling Common Failure Cases

Bearer-token APIs often fail in predictable ways:

  • '401 Unauthorized usually means the token is missing, invalid, or expired'
  • '403 Forbidden usually means the token is valid but lacks permission'
  • '400 Bad Request usually means the payload or query parameters are wrong'
  • network timeouts usually mean the API is slow or unreachable

A simple error-handling wrapper makes this easier to debug.

python
1import os
2import requests
3
4
5def fetch_profile():
6    url = "https://api.example.com/v1/profile"
7    token = os.environ["API_TOKEN"]
8    headers = {"Authorization": f"Bearer {token}"}
9
10    try:
11        response = requests.get(url, headers=headers, timeout=30)
12        response.raise_for_status()
13        return response.json()
14    except requests.exceptions.HTTPError as exc:
15        print("HTTP error:", exc.response.status_code, exc.response.text)
16        raise
17    except requests.exceptions.RequestException as exc:
18        print("Request failed:", exc)
19        raise

When Tokens Expire

Some APIs issue short-lived bearer tokens. In that case, the request code and the token-refresh code are separate concerns. Your request function should use the current token, while another part of the system is responsible for obtaining a fresh one.

That is a design point worth keeping clear. Mixing refresh logic into every request call usually makes the client harder to maintain.

Common Pitfalls

The biggest mistake is forgetting the Bearer prefix in the Authorization header. The token value alone is usually not enough.

Another mistake is hard-coding the token directly into the script or repository. That creates a security problem and makes rotation awkward.

People also forget to set a timeout. Without one, a hung API call can block much longer than expected.

Finally, do not assume 401 and 403 mean the same thing. One usually points to token validity, while the other points to authorization scope.

Summary

  • Send bearer tokens in the Authorization header as Bearer token_value.
  • Use requests with timeout and raise_for_status() for safer API calls.
  • Prefer environment variables over hard-coded secrets.
  • Use json= when sending JSON payloads.
  • Treat authentication, authorization, and token-refresh logic as separate concerns.

Course illustration
Course illustration

All Rights Reserved.