Stop Hand-Pasting Bearer Tokens: Two Supported Ways to Manage Auth in Postman
Hand-pasted bearer tokens expire mid-session and 401 your whole collection. Here's how to choose between Postman's built-in OAuth 2.0 helper and a pre-request script that caches tokens in collection variables.
11 Jan 2026, 07:56 UTC

It's 3 p.m., the bearer token someone pasted into the collection this morning has expired, and every request now returns 401. Someone digs up fresh credentials, generates a new token, pastes it into the Authorization tab, and the cycle repeats tomorrow. If that sounds familiar, the fix isn't discipline — it's letting Postman manage the token lifecycle for you.
There are two well-supported approaches: the built-in OAuth 2.0 authorization helper, and a pre-request script that fetches and caches a token in a collection variable. Here's how to choose between them.
Option 1: The built-in OAuth 2.0 helper
On any request, folder, or collection, open the Authorization tab and set the type to OAuth 2.0. Fill in the token URL, client ID, client secret, and grant type (client credentials is the common case for machine-to-machine APIs), then click Get New Access Token. Postman attaches the resulting token as an Authorization: Bearer header automatically.
Two things make this attractive:
- Inheritance. Configure auth once at the collection level and set individual requests to "Inherit auth from parent." Every request uses the same token with zero per-request setup.
- No code. There's nothing to debug when onboarding a teammate.
One caveat: the helper's behavior around automatically refreshing an expired token has varied across Postman releases and grant types. Don't assume it silently refreshes — verify against your current app version (check the Postman console after a token should have lapsed) before relying on it in a long-running monitor.
Option 2: A pre-request script with a cached token
If your identity provider uses a non-standard flow, or you want explicit control over expiry, a pre-request script on the collection gives you that. The pattern: cache the token and its expiry time in collection variables, and only fetch a new one when the cache is missing or about to expire.
// Collection-level Pre-request Script
// Requires environment variables: tokenUrl, clientId, clientSecret
const leewayMs = 60 * 1000; // refresh 60s before actual expiry
const expiresAt = pm.collectionVariables.get("tokenExpiresAt");
const now = Date.now();
if (expiresAt && now < Number(expiresAt) - leewayMs) {
// Cached token still valid; nothing to do.
return;
}
pm.sendRequest({
url: pm.environment.get("tokenUrl"),
method: "POST",
header: { "Content-Type": "application/x-www-form-urlencoded" },
body: {
mode: "urlencoded",
urlencoded: [
{ key: "grant_type", value: "client_credentials" },
{ key: "client_id", value: pm.environment.get("clientId") },
{ key: "client_secret", value: pm.environment.get("clientSecret") }
]
}
}, (err, res) => {
if (err || res.code !== 200) {
console.error("Token fetch failed", err || res.json());
return;
}
const body = res.json();
pm.collectionVariables.set("accessToken", body.access_token);
pm.collectionVariables.set("tokenExpiresAt", Date.now() + body.expires_in * 1000);
});Then set the collection's Authorization type to Bearer Token with the value {{accessToken}}. Every request in the collection picks it up.
Variable scoping does the heavy lifting here: collection variables share the cached token across all requests, environment variables hold per-deployment values like the token URL, and secret-type variables mask credentials in the UI. Documented variable precedence runs local, data, environment, collection, then global — worth re-checking against current docs if you rely on overrides.
One nuance to verify: whether the runtime fully awaits the pm.sendRequest callback before sending the main request has historically been a subtle point. Test it in your current app version; if the first request after expiry races ahead without a token, a simple fallback is to keep the leeway generous (so refresh rarely happens mid-run) or retry the 401 once.
Trade-offs
| OAuth 2.0 helper | Pre-request script | |
|---|---|---|
| Setup effort | Form fields, no code | Script to write and maintain |
| Flexibility | Standard flows only | Any flow you can express in JS |
| Failure modes | Opaque when it misbehaves | You own error handling and clock skew |
| Refresh control | Version-dependent | Explicit expiry check |
Both approaches run identically in Collection Runner, the Newman CLI, and scheduled Monitors, so either works in CI. One limitation applies to both: variables in team workspaces sync through Postman's cloud, so think carefully about where client secrets live. Postman has introduced local-only secret storage (Postman Vault) for exactly this concern — check the current docs before deciding where your client_secret belongs.
Do this week
Pick one collection where tokens get pasted by hand. Move its auth to collection-level OAuth 2.0 if your flow is standard, or drop in the script above if it isn't. Then wire the collection into a scheduled monitor — if auth breaks, you'll find out from the monitor, not from a teammate's 401.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.