Authorization Bearer Token Header Example for APIs

Authorization bearer token header example for APIs: See how to set the Authorization header with a Bearer token in HTTP requests using Postman or curl.

Jump to section

Jump to section

Jump to section

Bearer token authentication is the most common way to secure API requests, but implementing it correctly in production requires more than just slapping a token in a header. This guide walks through the complete bearer token lifecycle, shows you idiomatic implementation patterns across TypeScript, Python, and Go, and covers the production pitfalls that cause authentication failures.

You'll learn how bearer tokens flow through API requests, why they're different from API keys, common mistakes that break authentication in production, and a systematic approach to debugging when things go wrong.
Quick skim summary: This guide explains what bearer token authentication is, shows you how to use it with the Authorization header, and provides code examples in several languages. We'll cover how the token lifecycle works, common mistakes to avoid in production, and a checklist for debugging when things go wrong.

What is bearer token authentication?

Bearer token authentication is an HTTP authentication scheme where API access is granted to whoever holds, or "bears," the token. You include this token in the Authorization header of your request, prefixed with the word Bearer and a single space, like Authorization: Bearer <your_token>. Because this method is so common, it's critical to implement it securely, which always means transmitting it over HTTPS.

Unlike session-based cookies, bearer tokens are stateless. The server doesn't need to store any session information; instead, it validates the token on each request, making it highly scalable for modern APIs. This is different from a simple API key, as bearer tokens, especially JSON Web Tokens (JWTs), can contain claims or metadata about the user and their permissions.

Using a well-built client library simplifies this process. For example, SDKs created with the Stainless SDK generator can be configured with a single authToken option, and they automatically handle formatting and attaching the correct Authorization header to every API call for you.

How bearer tokens move through an API request

Understanding the token's journey is key to using it correctly. The lifecycle is a simple, repeating loop.

  1. Obtain: The client application first obtains a bearer token, usually through an authentication flow like OAuth 2.0 where the user logs in.

  2. Store: The client then needs to store this token securely. For a server-side application, this is often an environment variable; for a web browser, it might be in memory or a secure cookie.

  3. Send: On every subsequent request to a protected API endpoint, the client includes the token in the Authorization header.

  4. Validate: The API server receives the request, extracts the token from the header, and validates it to ensure it's authentic and not expired.

  5. Expire/Refresh: Tokens are typically short-lived. Once a token expires, the client must use a refresh token or re-authenticate to get a new one, starting the cycle over.

Here is what a raw API call looks like using fetch in JavaScript:

// Raw fetch request
async function getMyData(token) {
  const response = await fetch('https://api.example.com/v1/data', {
    method: 'GET',
    headers: {
      'Authorization': `Bearer ${token}`,
      'Content-Type': 'application/json'
    }
  });
  if (!response.ok) {
    // Handle 401 Unauthorized or other errors
    throw new Error(`API request failed with status ${response.status}`);
  }
  return response.json();
}

An SDK abstracts this boilerplate away, letting you focus on the API's logic, not the auth implementation details—because your API isn't finished until the SDK ships.

// With a Stainless-generated SDK
import ExampleClient from '@stainless/example-sdk';

const client = new ExampleClient({
  authToken: process.env.STAINLESS_API_TOKEN,
});

async function getMyData() {
  // The Authorization header is added automatically
  const data = await client.data.retrieve();
  return data;
}

Bearer token patterns for production APIs

While the underlying Authorization: Bearer ... header is universal, idiomatic usage differs across programming languages. A good SDK generator provides a consistent, high-level pattern that feels natural in each language, so you don't have to worry about the low-level details, and integrating SDK snippets with API docs ensures developers see the right patterns for their language.

TypeScript patterns

In TypeScript and JavaScript, initializing the client is straightforward. You pass the token during instantiation, and it's often read from environment variables for security.

import ExampleClient from '@stainless/example-sdk';

// The client is configured once with the token
const client = new ExampleClient({
  authToken: process.env.STAINLESS_API_TOKEN,
});

// All subsequent calls will be authenticated
async function listUsers() {
  const users = await client.users.list();
  console.log(users);
}

Python patterns

Python SDKs follow a similar pattern, supporting both synchronous and asynchronous clients. The token is passed as an argument to the client's constructor.

import os
from stainless_example_sdk import ExampleClient, AsyncExampleClient

# Synchronous client
client = ExampleClient(
    auth_token=os.environ.get("STAINLESS_API_TOKEN"),
)
users = client.users.list()

# Asynchronous client
async_client = AsyncExampleClient(
    auth_token=os.environ.get("STAINLESS_API_TOKEN"),
)
async_users = await async_client.users.list()

Go patterns

In Go, it's idiomatic to use functional options for configuration. This allows for a clean and extensible way to set the auth token and other client settings.

import (
    "context"
    "os"
    "github.com/stainless/example-sdk-go"
)

func main() {
    client := example.NewClient(
        example.WithAuthToken(os.Getenv("STAINLESS_API_TOKEN")),
    )

    // The client automatically adds the Authorization header
    user, err := client.Users.Get(context.Background(), "user_123")
    if err != nil {
        // Handle error
    }
    // ...

Common bearer token mistakes in production

Bearer tokens are powerful, but they come with responsibilities. Here are some common pitfalls developers encounter when deploying applications that use them.

Unsafe token transmission

  • The Mistake: Sending the token over an unencrypted HTTP connection. This exposes the token to anyone listening on the network, allowing them to impersonate the user.

  • The Fix: Always use HTTPS for any endpoint that handles authentication or transmits bearer tokens. Enforcing HTTP Strict Transport Security (HSTS) is also a best practice to prevent downgrade attacks.

Insecure storage patterns

  • The Mistake: Storing tokens in insecure locations. In a browser, this means using localStorage, which is vulnerable to Cross-Site Scripting (XSS) attacks. On a server, it means hardcoding tokens directly in the source code.

  • The Fix: In browsers, store tokens in memory for the duration of a session or in a secure, HttpOnly cookie. On the server, always use environment variables or a dedicated secrets management service.

Token lifecycle failures

  • The Mistake: Using tokens that never expire or having no mechanism to refresh them. Long-lived tokens increase the risk if they are compromised, while a lack of a refresh mechanism leads to a poor user experience, forcing users to log in again frequently.

  • The Fix: Implement short-lived access tokens (e.g., 15-60 minutes) and a robust refresh token flow. Your client should be able to detect a 401 Unauthorized response, use the refresh token to get a new access token, and then retry the original request.

Why bearer tokens fail in production

When an authenticated request fails, debugging can be frustrating. The issue usually falls into one of a few categories.

Failure Category

Common Causes

How to Debug

Header Formatting

Missing Bearer prefix, extra spaces, wrong capitalization, wrong header name (Authentication vs. Authorization).

Use cURL to make a raw request and double-check the exact header being sent.

Server Validation

Invalid signature (for JWTs), expired token, clock skew between client and server, token intended for a different audience (aud claim).

Check your API server logs. A good API will log the specific reason for a 401 error.

Client-Side Issues

Token is null or undefined, an old/expired token is cached, incorrect environment variable name.

Enable verbose logging in your SDK to inspect the exact request headers. Verify the token value just before the request is made.

Header formatting issues

This is the most common and easiest problem to fix. The Authorization header value must be Bearer followed by a single space, followed by the token.

  • Authorization: Bearer my-token-123 (Correct)

  • Authorization: Bearer my-token-123 (Incorrect, double space)

  • Authorization: bearer my-token-123 (Incorrect, lowercase 'b')

  • Authorization: my-token-123 (Incorrect, missing 'Bearer ' prefix)

A quick cURL command can help you isolate the issue from your application code:
curl -H "Authorization: Bearer your-token-here" https://api.example.com/v1/me

Server-side validation gaps

If the header is formatted correctly, the issue is likely on the server. For JWTs, validation failure can happen for many reasons:

  • Expired Signature: The exp claim in the token is in the past.

  • Invalid Signature: The token was tampered with or signed with the wrong key.

  • Clock Skew: The server's clock is out of sync with the client's, causing valid tokens to appear expired or not yet valid.

Your first step should always be to check the API server's logs, which should provide a specific error message for why authentication failed.

Client-side debugging steps

If the server logs show no incoming request, the problem is on the client. First, confirm your code is actually including the token. Many SDKs, including those generated by Stainless, allow you to enable verbose logging to see the exact HTTP request being sent, headers and all. This helps you confirm that the Authorization header is present and correctly formatted before it even leaves your machine.

Frequently asked questions about bearer tokens in production

How do I pass a bearer token in the authorization header?

You pass it in the Authorization HTTP header with the scheme Bearer followed by a space and then the token itself. For example: Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9....

Why does capitalization of Bearer matter?

While the official RFC 7235 specification states the scheme name is case-insensitive, many web frameworks and gateways implement a strict, case-sensitive check. To ensure compatibility, you should always use the capitalized Bearer.

Is an API key the same as a bearer token?

No, they serve similar purposes but are conceptually different. An API key is typically a static, long-lived secret, whereas a bearer token is often short-lived, dynamically generated, and may contain user-specific permissions within it (as a JWT).

How do SDKs refresh expired tokens?

Most SDKs do not handle token refreshing automatically, as the logic is specific to your auth provider. However, good SDKs provide hooks or middleware where you can implement this logic yourself, such as a beforeRequest function that checks token expiry and refreshes it if needed, using custom code that persists through regenerated code.

Where should I store bearer tokens in frontend apps?

For Single-Page Applications (SPAs), the safest place is in your application's memory. Avoid localStorage or sessionStorage as they are accessible via JavaScript and vulnerable to XSS attacks. If you must persist the token, use a secure, HttpOnly cookie managed by your backend.

Ready to simplify authentication and more for your API users? After creating OpenAPI specs, you can generate high-quality, idiomatic SDKs from them in minutes. Get started for free.