API Authentication Types: Basic Auth, API Key, Bearer Token and OAuth 2.0
Every serious API asks one question before it does anything: who are you? That is authentication. Get it wrong and anyone can read customer data; test it badly and you’ll miss the bug that leaks it. In this lesson you will learn the four authentication methods you’ll meet in real projects (Basic auth, API keys, Bearer tokens/JWT and OAuth 2.0), where each one is used in real life, and exactly which tests to run for each one on the live practice API.
Authorization header), API key (a secret key in a header such as X-API-Key, identifying an application), Bearer token / JWT (a signed, expiring token obtained at login and sent as Authorization: Bearer <token>) and OAuth 2.0 (a framework where an authorization server issues access tokens, used for “Login with Google” and third-party access). Missing or invalid credentials should return 401; valid credentials without permission should return 403.Authentication vs Authorization
| Authentication (AuthN) | Authorization (AuthZ) | |
|---|---|---|
| Question | Who are you? | What may you do? |
| Happens | First | After authentication |
| Failure code | 401 Unauthorized | 403 Forbidden (or 404 to hide data) |
| Example | Login, API key, token check | Viewer can’t delete; user can’t see others’ orders |
This lesson covers authentication. Authorization gets its own lesson: roles and 401 vs 403.
The 4 Main Authentication Types at a Glance
| Type | How it’s sent | Identifies | Expires? | Typical real use |
|---|---|---|---|---|
| Basic auth | Authorization: Basic base64(user:pass) | A user or service account | No (password) | Internal tools, Jenkins APIs, legacy systems, test environments |
| API key | X-API-Key: key (or query param) | An application/client | Usually no (rotated manually) | Google Maps, OpenWeatherMap, SMS gateways |
| Bearer token (JWT) | Authorization: Bearer eyJ... | A logged-in user session | Yes (minutes to hours) | Mobile and web app backends |
| OAuth 2.0 | Bearer access token from an auth server | A user who granted an app access | Yes, with refresh tokens | “Login with Google”, GitHub apps, UPI/bank partner APIs |
Others you may meet: Digest auth (older, rarely used), HMAC signatures (AWS, payment webhooks), mutual TLS (bank-to-bank APIs) and session cookies (covered in the cookies lesson).
1. Basic Authentication
The client joins username and password with a colon, encodes it in Base64 and sends it in every request:
sqa_user:sqa@123 → Base64 → c3FhX3VzZXI6c3FhQDEyMw==
Authorization: Basic c3FhX3VzZXI6c3FhQDEyMw==
c3FhX3VzZXI6c3FhQDEyMw== back to the password in one second. Basic auth is only acceptable over HTTPS, and never for end-user logins in modern apps.Practice credentials (public, for this API only): sqa_user / sqa@123.
https://sqatools.in/wp-json/sqa-api/v1/basic/profilecurl -i \
-H "Authorization: Basic c3FhX3VzZXI6c3FhQDEyMw==" \
"https://sqatools.in/wp-json/sqa-api/v1/basic/profile"Basic auth test cases
| Scenario | Expected |
|---|---|
| Valid credentials | 200 |
| No Authorization header | 401 + WWW-Authenticate: Basic realm="..." |
| Wrong password | 401, same message as unknown user |
| Malformed header (not Base64) | 401, not 500 |
| Credentials over plain HTTP | Refused or redirected to HTTPS |
| Many wrong attempts | Lockout or rate limit (429) |
2. API Key Authentication
An API key is a long random string issued to an application, not to a person. The server looks it up to know which client is calling, which plan it’s on and how many calls it may make.
appid=YOUR_KEY. The provider counts calls per key, blocks the key at its free-plan limit and bills the company on a paid plan. No end user ever logs in to the weather service.https://sqatools.in/wp-json/sqa-api/v1/apikey/profilecurl -i \
-H "X-API-Key: sqa-key-12345" \
"https://sqatools.in/wp-json/sqa-api/v1/apikey/profile"API key test cases
| Scenario | Practice API result |
|---|---|
Valid key in X-API-Key header | 200 |
Valid key as ?api_key= query param | 200 (works, but keys in URLs end up in logs: flag it) |
| Missing key | 401 |
| Wrong key | 403 |
Key in the wrong header (e.g. Authorization) | 401 |
| Revoked or expired key | 401/403 |
| Quota exceeded | 429 with Retry-After |
3. Bearer Token Authentication (JWT)
The user logs in once with username and password. The server returns a short-lived access token, and the client sends it as a “bearer” in every request. “Bearer” means whoever holds this token gets access, so it must be protected like a password.
POST /auth/loginwith username and password →200withaccess_token,expires_in,refresh_token.GET /auth/mewithAuthorization: Bearer <access_token>→200.- When the access token expires,
POST /auth/refreshwith the refresh token → new tokens without asking for the password again. POST /auth/logout→ the token is revoked.
https://sqatools.in/wp-json/sqa-api/v1/auth/logincurl -i \
-X POST \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"admin@123"}' \
"https://sqatools.in/wp-json/sqa-api/v1/auth/login"The practice API’s access tokens are JWTs that last 900 seconds (15 minutes). Users: admin / admin@123 (can write) and viewer / viewer@123 (read-only). JWT internals, expiry and tampering tests are covered in depth in JWT Token Testing.
Bearer token test cases
- Valid login returns a token; wrong password returns
401; missing fields return422. - Protected endpoint without a token →
401; with a garbage token →401. - Wrong scheme (
Token xyzinstead ofBearer xyz) →401. - Expired, tampered or revoked token →
401. - The password is never echoed back; the token never appears in URLs.
4. OAuth 2.0
OAuth 2.0 is an authorization framework: it lets a user give an application limited access to their data on another service without sharing their password.
The four roles
- Resource owner: you (the user).
- Client: the app that wants access (the printing site).
- Authorization server: issues tokens (Google’s accounts server, Okta, Keycloak, Auth0).
- Resource server: the API holding the data (Google Photos API).
Common OAuth 2.0 grant types (flows)
| Flow | Used when | Example |
|---|---|---|
| Authorization Code + PKCE | A user logs in through a browser or mobile app | “Login with Google/GitHub” |
| Client Credentials | Machine-to-machine, no user | Order service calling the payment service; partner APIs |
| Refresh Token | Get a new access token silently | App stays logged in for weeks |
| Device Code | Devices without a keyboard | Smart TV “enter this code on your phone” |
| Deprecated (insecure) | Flag them if you see them |
OpenID Connect (OIDC) adds identity on top of OAuth 2.0: an ID token (a JWT) telling the app who the user is. “Login with Google” is OIDC.
OAuth 2.0 test cases
- Token request with wrong
client_secret→401 invalid_client. - Token with scope
readcalling a write endpoint →403 insufficient_scope. redirect_urinot on the allowed list → rejected (prevents token theft).stateparameter checked (prevents CSRF in the login flow).- Authorization code can be used only once and expires quickly.
- Revoked consent stops access immediately (or at token expiry).
In Postman, the Authorization → OAuth 2.0 tab can run these flows for you and store the token; you’ll use it in the Postman tutorial.
Which Authentication Should an API Use?
| Situation | Good choice |
|---|---|
| Your own mobile or web app’s users | Bearer JWT (short-lived) + refresh token, or OIDC |
| Third-party apps acting for your users | OAuth 2.0 Authorization Code + PKCE |
| Server-to-server, partners | OAuth 2.0 Client Credentials, mTLS or HMAC-signed requests |
| Public data APIs with quotas | API keys |
| Quick internal tools / test environments | Basic auth over HTTPS |
Automating All Auth Types with Playwright
import { test, expect } from '@playwright/test';
const BASE = 'https://sqatools.in/wp-json/sqa-api/v1';
test('Basic auth: valid and missing credentials', async ({ request }) => {
const basic = 'Basic ' + Buffer.from('sqa_user:sqa@123').toString('base64');
expect((await request.get(`${BASE}/basic/profile`, { headers: { Authorization: basic } })).status()).toBe(200);
const none = await request.get(`${BASE}/basic/profile`);
expect(none.status()).toBe(401);
expect(none.headers()['www-authenticate']).toContain('Basic');
});
test('API key: valid, wrong and missing', async ({ request }) => {
const url = `${BASE}/apikey/profile`;
expect((await request.get(url, { headers: { 'X-API-Key': 'sqa-key-12345' } })).status()).toBe(200);
expect((await request.get(url, { headers: { 'X-API-Key': 'wrong-key' } })).status()).toBe(403);
expect((await request.get(url)).status()).toBe(401);
});
test('Bearer token: login then call a protected endpoint', async ({ request }) => {
const login = await request.post(`${BASE}/auth/login`, {
data: { username: 'admin', password: 'admin@123' },
});
expect(login.status()).toBe(200);
const { access_token, token_type, expires_in } = await login.json();
expect(token_type).toBe('Bearer');
expect(expires_in).toBe(900);
const me = await request.get(`${BASE}/auth/me`, { headers: { Authorization: `Bearer ${access_token}` } });
expect((await me.json()).data).toMatchObject({ username: 'admin', role: 'admin', can_write: true });
});
Playwright also supports Basic auth globally through httpCredentials in the config, and you’ll learn to share a login token across tests with fixtures in Module 6.
Common Authentication Bugs
- Different error messages for “unknown user” and “wrong password” (lets attackers find valid usernames).
- No rate limit on login (brute force), or on OTP verification.
- Tokens that never expire, or that still work after logout or password change.
- Tokens or keys in URLs, logs or error messages.
- Endpoints that someone forgot to protect (often new or “internal” ones). Call every endpoint with no credentials.
- 500 errors for malformed Authorization headers.
Authentication Testing Checklist
- Every protected endpoint returns 401 without credentials.
- Invalid, malformed, expired and revoked credentials return 401.
- 401 responses include
WWW-Authenticate. - Error messages don’t reveal whether the user exists.
- Login and key validation are rate limited.
- Credentials travel only over HTTPS and only in headers.
- Secrets aren’t logged, cached or returned.
- Logout and password change invalidate tokens.
Interview Questions: API Authentication
What is the difference between authentication and authorization?
Authentication verifies who the caller is (login, API key, token). Authorization decides what the authenticated caller may do (roles, permissions, ownership). Authentication failures return 401; authorization failures return 403 or sometimes 404.
What types of API authentication have you tested?
A strong answer lists the types with specifics: Basic auth for an internal tool, API keys for a partner integration, JWT Bearer tokens with refresh for a mobile backend, and OAuth 2.0 client credentials between services, plus the negative cases you covered.
Is Basic authentication secure?
Only over HTTPS and only for limited cases. Base64 is encoding, not encryption, so the credentials are readable by anyone who intercepts the request. It also sends the real password on every call and has no expiry.
What is the difference between an API key and a Bearer token?
An API key identifies an application, is usually long-lived and is issued once. A Bearer token represents an authenticated user session, is short-lived, is obtained by logging in and can carry claims such as role and expiry.
What is OAuth 2.0?
An authorization framework that lets a user grant an application limited, scoped access to their resources on another service through an authorization server, without sharing their password. The app receives access tokens and optionally refresh tokens.
What is the difference between OAuth 2.0 and OpenID Connect?
OAuth 2.0 is about authorization (access tokens for APIs). OpenID Connect is an identity layer on top of OAuth 2.0 that adds an ID token so the app knows who the user is; it powers “Login with Google”.
Which OAuth flow is used for machine-to-machine communication?
The Client Credentials grant: the service authenticates with its client id and secret and receives an access token, with no user involved.
Why should API keys not be sent as query parameters?
URLs are stored in server logs, proxy logs, browser history and analytics tools, so keys in query strings can leak. Headers are the safer place.
What should happen when a protected endpoint is called without a token?
It should return 401 Unauthorized with a WWW-Authenticate header indicating the expected scheme, and no data.
How do you test a login API for security?
Check the same generic error for wrong user and wrong password, rate limiting and lockout, HTTPS only, no password in responses or logs, token expiry, token invalidation on logout and password change, and that SQL injection or very long input doesn’t cause errors.