Authorization and chaining requests
The Authorization tab, and a login whose token the next requests pick up on their own.
Most real APIs want credentials. Postman has a tab for them on every request, collection and folder, and it handles the common schemes for you. The harder part is the login flow: one request returns a token, and every request after it needs that token. Copying it by hand works once. This lesson makes the requests pass it along on their own.
The examples use the authentication test API, whose demo credentials are published for exactly this. If you want to understand the schemes themselves rather than how Postman sends them, the authentication tutorial covers each one in depth.
The Authorization tab
Each request has an Authorization tab with a type list. The type decides which header or parameter Postman builds:
| Type | What you fill in | What Postman sends |
|---|---|---|
| Basic Auth | Username apibee, password password123 | Authorization: Basic YXBpYmVl…, the pair in Base64 |
| API Key | Key X-API-Key, value apibee-key-123, add to Header | X-API-Key: apibee-key-123, or a query parameter if you pick that instead |
| Bearer Token | Token {{accessToken}} | Authorization: Bearer <the token> |
| OAuth 2.0 | Grant type, URLs, client ID and so on | A bearer token it fetched for you, once you've got one |
| Inherit auth from parent | Nothing | Whatever the folder or collection above it is set to |
The last row is the useful one at scale. Set the auth once on a folder or the collection, leave every request on Inherit, and changing the credentials becomes one edit instead of fifty. Requests that must not send credentials, such as a test that checks what happens without them, should be set to No Auth explicitly, so they don't inherit anything.
Chaining: a login that feeds the next requests
The JWT test API issues a token from POST /api/auth/jwt/loginsign in to see that expires after 15 minutes. The request 03 Auth and chaining / JWT login (saves the tokens) sends this body:
{
"username": "user",
"password": "user123"
}And it has a post-response script that saves what comes back:
pm.test("login succeeds", () => pm.response.to.have.status(200));
const body = pm.response.json();
pm.collectionVariables.set("accessToken", body.accessToken);
pm.collectionVariables.set("refreshToken", body.refreshToken);The next two requests use Bearer Token auth with {{accessToken}}. Send the login, then send JWT: who am I, and it just works. When the token expires, send the login again; nothing else changes.
Run the whole folder and you can watch the token travel. This is the real output:
$ newman run testingapis-postman-collection.json -e testingapis-postman-environment.json --folder "03 Auth and chaining"
□ 03 Auth and chaining
└ Basic auth
GET https://api.testingapis.com/api/auth/basic [200 OK, 314B, 134ms]
√ Basic credentials accepted
└ API key in a header
GET https://api.testingapis.com/api/auth/api-key/header [200 OK, 330B, 41ms]
√ API key accepted
└ JWT login (saves the tokens)
POST https://api.testingapis.com/api/auth/jwt/login [200 OK, 1.02kB, 32ms]
√ login succeeds
└ JWT: who am I
GET https://api.testingapis.com/api/auth/jwt/me [200 OK, 863B, 31ms]
√ the token from the login works
√ it belongs to user
└ JWT: admin endpoint refuses a user token
GET https://api.testingapis.com/api/auth/jwt/admin [403 Forbidden, 210B, 45ms]
√ a valid token without the admin role gets 403
└ OAuth 2.0: client credentials token
POST https://api.testingapis.com/api/auth/oauth/token [200 OK, 420B, 45ms]
√ token issued
√ token responses are never cached
└ OAuth 2.0: protected resource
GET https://api.testingapis.com/api/auth/oauth/protected [200 OK, 397B, 29ms]
√ the OAuth token is acceptedThe fifth request is as important as the fourth. A test that checks the admin endpoint refusesa user's token catches a whole class of bug, a role check that was never wired up, that a test checking only the happy path never will.
Logging in only when needed
Running the login request first works in a planned run. When you're clicking around, it's nicer if a request fetches its own token when there isn't one. pm.sendRequest sends a request from inside a script, and a pre-request script can use it to log in first:
// Log in only when there's no token yet; the request waits for the callback to finish
if (!pm.collectionVariables.get("accessToken")) {
pm.sendRequest({
url: pm.variables.replaceIn("{{baseUrl}}/api/auth/jwt/login"),
method: "POST",
header: { "Content-Type": "application/json" },
body: { mode: "raw", raw: JSON.stringify({ username: "user", password: "user123" }) }
}, (err, response) => {
if (err) throw err;
pm.collectionVariables.set("accessToken", response.json().accessToken);
console.log("logged in, status", response.code);
});
}Postman waits for the callback before sending the request itself, so the token is in place in time. This version was checked with Newman: it logged in, saved the token, and the request that followed used it. In the Postman app the saved token stays in the collection, so later sends skip the login until you clear it. Newer versions of Postman also accept await pm.sendRequest(...), but Newman 6 doesn't, so the callback form is the one that works everywhere.
OAuth 2.0 with Postman's helper
For OAuth 2.0, Postman can run the whole authorization code flow, PKCE included, and keep the token. Set the Authorization type to OAuth 2.0 on a request or folder, and fill in the configuration:
| Field | Value |
|---|---|
| Grant type | Authorization Code (With PKCE) |
| Callback URL | Tick "Authorize using browser", which uses https://oauth.pstmn.io/v1/callback |
| Auth URL | https://api.testingapis.com/api/auth/oauth/authorizesign in to see |
| Access Token URL | https://api.testingapis.com/api/auth/oauth/tokensign in to see |
| Client ID | apibee-public |
| Client Secret | Leave empty: this is a public client |
| Code Challenge Method | SHA-256 |
| Scope | read profile |
- Choose Get New Access Token. Postman opens the browser at the authorize URL.
- The test server approves automatically and redirects to Postman's callback address with a code. The server accepts that address: it's on its list of registered redirect URIs.
- Postman exchanges the code and the verifier for a token, and offers to use it.
Field names shift a little between Postman versions, but the pieces are always these. What the helper hides is the part you need to understand when it fails: the verifier, the challenge and the exchange. The PKCE lessondoes every step by hand, which is what you want when the helper reports an error you don't recognise. For a service-to-service token, the collection's OAuth 2.0: client credentials token request shows the simpler route: a plain POST with the client ID and secret as Basic auth, and a script that saves access_token.
Auth checklist for a collection
- Credentials live in variables, never typed into individual requests.
- Auth is set once on the collection or folder; requests inherit it.
- Tests that check unauthenticated access are set to No Auth explicitly.
- Every login request saves its token with a script, and a test fails if the login does.
- At least one test checks that a wrong or weaker credential is refused, with 401 or 403.
Exercise
Add a folder called Admin with its auth set to Bearer Token {{adminToken}}. Inside it, put a login request for admin / admin123 that saves adminToken, and a request to /api/auth/jwt/adminsign in to seeset to inherit. The login itself should be set to No Auth. Why does it matter that the login doesn't inherit the folder's auth? Then run the folder twice in a row and check that both runs pass.