Skip to main content
Security Guide

What Is a
Bearer Token?

How the Authorization: Bearer header works, how bearer tokens compare to API keys and session cookies, and how to store and transmit them without leaking them into your logs.

8 min read·Updated May 2026

What is a bearer token: "bearer" means whoever holds the token gets access — there's no additional proof of identity required, which makes bearer tokens simple and portable but also means a stolen token grants full access until it expires. The name comes from RFC 6750, the OAuth 2.0 bearer token standard.

Bearer tokens in your logs?

Authorization headers end up in access logs more often than people realise. Use the Log Sanitizer to redact them before sharing logs anywhere.

The Authorization Header

Bearer tokens travel in the HTTP Authorization request header. The format is standardised by RFC 6750 and looks like this:

Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...

The structure has two parts separated by a single space: the scheme (Bearer) and the token itself. The scheme name is case-insensitive in the RFC but Bearer with a capital B is the conventional spelling virtually every server and client library expects.

Other authentication schemes exist and use the same header field — Basic (base64-encoded username:password), Digest (challenge-response), and AWS4-HMAC-SHA256 (AWS Signature Version 4) are the most common alternatives. But Bearer is the dominant scheme for modern REST APIs and everything built on OAuth 2.0.

Common Authorization schemes

Scheme Used for Standard
Bearer OAuth 2.0, most REST APIs RFC 6750
Basic Simple username/password RFC 7617
Digest Challenge-response auth RFC 7616
AWS4-HMAC-SHA256 AWS service requests AWS docs

How Bearer Tokens Are Used — the Request Lifecycle

The typical OAuth 2.0 flow using bearer tokens follows four steps:

  1. Client authenticates. The client sends credentials to a token endpoint — this might be a username and password, an API key, a client ID and secret (client credentials flow), or a social login redirect. The exact method depends on the OAuth grant type.
  2. Server returns a bearer token. On success, the server issues a token — usually a JWT for stateless APIs or an opaque random string for stateful ones — along with an expiry time and often a refresh token.
  3. Client includes the token in every subsequent request. For the lifetime of the token, the client attaches it in the Authorization: Bearer <token> header on every API call. No further credential exchange is needed.
  4. Server validates the token on each request. For JWTs, the server verifies the cryptographic signature and checks the exp (expiry) and aud (audience) claims — no database lookup required. For opaque tokens, the server queries its token store or calls an introspection endpoint to check validity.

This split — authenticate once, then use a token — is what makes bearer tokens practical at scale. The server doesn't need to look up a user record or rehash a password on every request; it just verifies the token.

Bearer Token vs API Key vs Session Cookie

All three are credentials that prove who's making a request. They differ in how they're transmitted, how they expire, and how they can be revoked:

Property Bearer token API key Session cookie
Transmitted in Authorization header Header or query param Cookie header
Format Usually a JWT Opaque string Session ID
Expires Yes (exp claim or TTL) Often doesn't Configurable
Revocable Depends — JWT: no; opaque: yes Yes Yes
Visible to JS If stored in localStorage If embedded in code Only if not httpOnly
Standard RFC 6750 No standard RFC 6265

The key practical difference: API keys are designed for server-to-server calls where a long-lived credential is acceptable. Bearer tokens are designed for delegated access — a user grants an app permission to act on their behalf, and the token encodes that grant with an expiry baked in. Session cookies sit in the middle, typically used for browser sessions where the server maintains state.

Security Risks

Token in the URL

The single biggest bearer token mistake is putting the token in a query parameter rather than the Authorization header:

GET /api/data?access_token=eyJhbGci...   ← never do this

URLs appear verbatim in server access logs, browser history, bookmarks, and Referer headers sent to third-party resources on the page. A token embedded in a URL will be logged in plain text by every proxy, load balancer, and CDN the request passes through. RFC 6750 mentions this as a last-resort transmission method, but every practical guide treats it as off-limits.

Token in localStorage

localStorage is readable by any JavaScript running on the page. A single successful XSS injection — one rogue script tag, one compromised third-party dependency — can exfiltrate every token in localStorage in milliseconds. If the token has a long expiry, the attacker has time to use it long after the page visit ended. For browser apps handling sensitive data, localStorage is not an acceptable token store.

Token in logs

Most web servers and reverse proxies log the full request headers by default. That means Authorization: Bearer <token> ends up in your access log on every authenticated request. A typical Nginx or Apache access log line looks like:

203.0.113.42 - - [02/May/2026:14:23:01 +0000] "GET /api/profile HTTP/1.1" 200 842
  "https://app.example.com/dashboard"
  "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyXzEyMzQ1IiwiZXhwIjoxNzQ2MjkwNTgxfQ.sig"

Anyone with read access to your log files — a developer, a support engineer, a log aggregation service — can see and reuse active tokens. If the token is a JWT, they can also decode the payload without a key, which may expose user IDs, email addresses, roles, and other claims. The log sanitization guide covers this in more detail.

Long-lived tokens

The longer a token's expiry window, the longer a stolen token is useful to an attacker. A 30-day access token leaked into a log gives an attacker 30 days of access before natural expiry. The industry norm for access tokens is 15 minutes to 1 hour, with a longer-lived refresh token (days to weeks) used only to obtain new access tokens — and only over a direct, authenticated channel, not stored in a place JavaScript can reach.

How to Store Bearer Tokens Safely

httpOnly cookie (preferred for browser apps)

An httpOnly, Secure, SameSite=Strict cookie is the best storage for browser-facing bearer tokens. httpOnly makes the cookie completely invisible to JavaScript — no XSS payload can read it. Secure ensures it only travels over HTTPS. SameSite=Strict prevents it from being sent in cross-site requests, which blocks CSRF. The tradeoff is that your JavaScript can't read the token value, so you can't inspect claims client-side without a separate mechanism (like a non-sensitive identity cookie the JS can read).

Memory only (for SPAs)

For single-page applications that need JavaScript access to the token, storing it in a module-scoped variable (in memory only) is safer than localStorage. The token is never written to disk, never persists across page reloads, and is not reachable by XSS payloads that can only read storage APIs. The cost is that the user has to re-authenticate on every page refresh, which is mitigated by a silent token refresh in the background via an httpOnly refresh token cookie.

Never localStorage for sensitive tokens

To be explicit: do not store access tokens for sensitive resources in localStorage or sessionStorage. Both are accessible via window.localStorage and window.sessionStorage from any script on the page. If your app includes third-party analytics, ads, or a compromised npm dependency, those scripts can reach your token store.

How Bearer Tokens Appear in Logs

Even when you've done everything else right, bearer tokens routinely surface in logs because Authorization headers are captured by default. Here's a realistic combined-format access log line from a Node.js/Express app using Morgan:

203.0.113.42 - alice [02/May/2026:09:41:17 +0000] "GET /api/v1/users/me HTTP/1.1" 200 1247 "-" "Mozilla/5.0" Authorization:"Bearer eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ1c2VyXzQ1NiIsImVtYWlsIjoiYWxpY2VAZXhhbXBsZS5jb20iLCJyb2xlIjoiYWRtaW4iLCJleHAiOjE3NDYyOTM2Nzd9.redacted"

This single line exposes the user's IP address, their username, the JWT itself (which anyone can base64-decode to see the email and role claims), and the exact expiry timestamp. If this log file is shared with a third party — pasted into an AI chat, attached to a support ticket, uploaded to a log aggregation service — all of that is exposed. Use the Log Sanitizer to redact Authorization headers and tokens before sharing any log output.

How to Redact Bearer Tokens from Logs

If you want to strip bearer tokens at the source before they're written, here are two common patterns.

sed one-liner — useful for scrubbing an existing log file:

sed -E 's/(Authorization: Bearer )[A-Za-z0-9._~+/=-]+/\1[REDACTED]/g' access.log

Python logging.Filter — redacts tokens before any handler writes the record, so they never reach disk or stdout:

import logging, re

class BearerTokenFilter(logging.Filter):
    _pattern = re.compile(
        r'(Authorization:\s*Bearer\s+)[A-Za-z0-9._~+/=-]+',
        re.IGNORECASE
    )

    def filter(self, record):
        record.msg = self._pattern.sub(r'\1[REDACTED]', str(record.msg))
        if record.args:
            record.args = tuple(
                self._pattern.sub(r'\1[REDACTED]', str(a))
                if isinstance(a, str) else a
                for a in (record.args if isinstance(record.args, tuple)
                          else (record.args,))
            )
        return True

# Attach to the root logger or any specific logger
logging.getLogger().addFilter(BearerTokenFilter())

The filter pattern is the same approach described in the PII redaction in Python guide. Attach it at the root logger level to catch all handlers — file, stdout, and any third-party logging integrations — in one place.

Ready to Scrub Tokens from Your Logs?

Redact Bearer Tokens from Your Logs

Paste the log. Authorization headers and tokens are redacted instantly, in your browser.

Open the Log Sanitizer →

Related Reading