Bearer Token: Definition and Headless Browser Use

A bearer token is a credential that grants access to whoever presents it. How the Authorization header works, and how to send one from a headless browser.

By Simon Chiu · Updated

A bearer token is a credential sent in the Authorization: Bearer <token> HTTP header that grants access to whoever presents it, with no further proof of identity.

The name comes from the bearer bond: the holder of the paper owns it. The scheme is defined in RFC 6750, written for OAuth 2.0, and is now the default way to authenticate API calls. This entry is part of the screenshot glossary.

What it means in plain terms

A bearer token works like a ticket, not like a passport. The server does not ask who you are. It checks that the ticket is valid and lets you in. That makes bearer tokens simple to use from any language and any tool, and it makes a leaked token as good as a stolen password until it expires or is revoked.

For screenshots, bearer tokens appear in two places:

  1. Calling a screenshot API. Your server sends its API key as a bearer token.
  2. Capturing a protected page. The headless browser must present a token to the site you capture, for example an internal dashboard behind an API gateway.

How it works technically

 your code / headless browser                 server
 ────────────────────────────                 ──────
 GET /reports/q3
 Authorization: Bearer eyJhbGciOi...  ───────▶ look up or verify token
                                               │ valid   → 200 + page
                                               │ invalid → 401
                                               ▼          WWW-Authenticate: Bearer

The token itself is opaque to the client. It can be a random string the server looks up in a database, or a signed JWT the server verifies without a lookup. Either way:

  • It travels in a header, so it stays out of URLs, browser history and most access logs.
  • It must only travel over HTTPS. Anyone who reads the header can replay it.
  • It has no binding to the sender. Unlike a signed URL or an HMAC signature, it does not prove that the request was not changed.

How to send one from a headless browser

The trap in every tool is scope. A real browser never adds your Authorization header to requests for other hosts, but an automation setting often does. We tested this with two local origins: a page on port 4101 that requires the token and loads an image from port 4102. With the scoped code below, port 4101 received Bearer test-token-123 and port 4102 received no Authorization header.

Puppeteer

page.setExtraHTTPHeaders() sends the header to every host the page contacts. Use request interception to limit it to the target origin:

import puppeteer from 'puppeteer';

const target = new URL(process.argv[2] ?? 'https://example.com/');
const token = process.env.TARGET_TOKEN;
if (!token) throw new Error('Set TARGET_TOKEN');

const browser = await puppeteer.launch();
try {
  const page = await browser.newPage();
  await page.setRequestInterception(true);
  page.on('request', (req) => {
    if (req.isInterceptResolutionHandled()) return;
    const headers = { ...req.headers() };
    if (new URL(req.url()).origin === target.origin) {
      headers.authorization = `Bearer ${token}`;
    }
    req.continue({ headers });
  });
  const res = await page.goto(target.href, { waitUntil: 'networkidle0' });
  if (!res?.ok()) throw new Error(`Target answered ${res?.status()}`);
  await page.screenshot({ path: 'bearer-puppeteer.png' });
} finally {
  await browser.close();
}

Playwright

extraHTTPHeaders on a context has the same problem. A route that matches only the target origin is the clean fix:

import { chromium } from 'playwright';

const target = new URL(process.argv[2] ?? 'https://example.com/');
const token = process.env.TARGET_TOKEN;
if (!token) throw new Error('Set TARGET_TOKEN');

const browser = await chromium.launch();
try {
  const context = await browser.newContext();
  await context.route(`${target.origin}/**`, (route) =>
    route.continue({
      headers: { ...route.request().headers(), authorization: `Bearer ${token}` },
    })
  );
  const page = await context.newPage();
  const res = await page.goto(target.href, { waitUntil: 'networkidle' });
  if (!res?.ok()) throw new Error(`Target answered ${res?.status()}`);
  await page.screenshot({ path: 'bearer-playwright.png' });
} finally {
  await browser.close();
}

Tested on 2026-10-15 with Node 22.18.0, [email protected] and [email protected], against the local two-origin server and against https://example.com. The Puppeteer run used headless: 'shell' because full headless mode stalled on screenshots on the test machine.

RenderScreenshot

Here the two uses separate cleanly. Your API key authenticates you to the API as a bearer token, as described in bearer token authentication. A token for the page you capture goes in network.auth:

curl -X POST https://api.renderscreenshot.com/v1/screenshot \
  -H "Authorization: Bearer $RS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://dashboard.example.com/reports/q3",
    "network": { "auth": { "type": "bearer", "token": "'"$REPORT_TOKEN"'" } }
  }' \
  --output q3.png

In the Node.js SDK the same request is TakeOptions.url(...).authBearer(process.env.REPORT_TOKEN). See network options. For a dashboard that uses cookies instead of a header, read the authenticated pages guide. The API requests on this page were not run for it.

Common mistakes

  • Leaking the token to third parties with a global header setting. Scope it to one origin, as above.
  • Putting the token in a query string because it is easier. URLs end up in logs and Referer headers. For public image links, use a signed URL instead of ?api_key=.
  • Using a long-lived token for captures. Mint a short-lived, read-only token for the screenshot job where the site allows it.
  • Lowercase bearer. The scheme name is case-insensitive in the standard, but some gateways only accept Bearer.
  • Treating a 200 as success. Many apps answer an expired token with a login page and a 200. Check the content, not only the status.

To capture a token-protected page without running a browser, create a free account and send the request above.

Frequently asked questions

What is the difference between a bearer token and an API key?
An API key is a kind of credential; bearer is a way of presenting one. Many APIs, RenderScreenshot included, accept their API key as a bearer token in the Authorization header. Other bearer tokens are short-lived OAuth access tokens or JWTs.
Is a bearer token the same as a JWT?
No. A JWT is a token format that can carry signed claims. It is often sent as a bearer token, but a bearer token can also be a random opaque string that only the server can look up.
Why is page.setExtraHTTPHeaders risky for an Authorization header?
It adds the header to every request the page makes, including requests to analytics, font and ad hosts. Those third parties then receive your token. Add the header only to requests for the origin that needs it.

Related in this topic

Try RenderScreenshot free

150 free credits every month, no credit card required.