API Authentication Types: Basic Auth, API Key, Bearer Token and OAuth 2.0

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.

Quick answerThe main API authentication types are: Basic authentication (username:password, Base64-encoded in the 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.
Advertisement

Authentication vs Authorization

Real-life example: an airport At the entrance, security checks your ID and boarding pass: that’s authentication (proving who you are). At the gate, the boarding pass decides whether you can enter the business lounge or only economy: that’s authorization (what you’re allowed to do). A passenger with a valid ID can still be refused at the lounge door.
Authentication (AuthN)Authorization (AuthZ)
QuestionWho are you?What may you do?
HappensFirstAfter authentication
Failure code401 Unauthorized403 Forbidden (or 404 to hide data)
ExampleLogin, API key, token checkViewer 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

TypeHow it’s sentIdentifiesExpires?Typical real use
Basic authAuthorization: Basic base64(user:pass)A user or service accountNo (password)Internal tools, Jenkins APIs, legacy systems, test environments
API keyX-API-Key: key (or query param)An application/clientUsually no (rotated manually)Google Maps, OpenWeatherMap, SMS gateways
Bearer token (JWT)Authorization: Bearer eyJ...A logged-in user sessionYes (minutes to hours)Mobile and web app backends
OAuth 2.0Bearer access token from an auth serverA user who granted an app accessYes, 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).

Advertisement

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==
Base64 is not encryption Anyone can decode 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.

GEThttps://sqatools.in/wp-json/sqa-api/v1/basic/profile
curl -i \
  -H "Authorization: Basic c3FhX3VzZXI6c3FhQDEyMw==" \
  "https://sqatools.in/wp-json/sqa-api/v1/basic/profile"

Basic auth test cases

ScenarioExpected
Valid credentials200
No Authorization header401 + WWW-Authenticate: Basic realm="..."
Wrong password401, same message as unknown user
Malformed header (not Base64)401, not 500
Credentials over plain HTTPRefused or redirected to HTTPS
Many wrong attemptsLockout 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.

Real-life example: weather in a travel app A travel app shows weather for your destination. Its backend calls a weather provider with 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.
GEThttps://sqatools.in/wp-json/sqa-api/v1/apikey/profile
curl -i \
  -H "X-API-Key: sqa-key-12345" \
  "https://sqatools.in/wp-json/sqa-api/v1/apikey/profile"

API key test cases

ScenarioPractice API result
Valid key in X-API-Key header200
Valid key as ?api_key= query param200 (works, but keys in URLs end up in logs: flag it)
Missing key401
Wrong key403
Key in the wrong header (e.g. Authorization)401
Revoked or expired key401/403
Quota exceeded429 with Retry-After
Real bug pattern: keys in mobile apps and GitHub API keys hardcoded in Android apps or pushed to public GitHub repositories are scraped by bots within minutes. Check that secret keys aren’t in front-end code, and that keys shipped to clients are restricted (by app, domain or IP).
Advertisement

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.

  1. POST /auth/login with username and password → 200 with access_token, expires_in, refresh_token.
  2. GET /auth/me with Authorization: Bearer <access_token> → 200.
  3. When the access token expires, POST /auth/refresh with the refresh token → new tokens without asking for the password again.
  4. POST /auth/logout → the token is revoked.
POSThttps://sqatools.in/wp-json/sqa-api/v1/auth/login
curl -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 return 422.
  • Protected endpoint without a token → 401; with a garbage token → 401.
  • Wrong scheme (Token xyz instead of Bearer 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.

Real-life example: “Login with Google” and a photo-printing app A photo-printing website wants your Google Photos. Instead of asking for your Google password, it redirects you to Google. You log in at Google and approve “view your photos”. Google gives the website an access token limited to that scope. The website can read photos but can’t read your Gmail, and you can revoke access at any time.

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)

FlowUsed whenExample
Authorization Code + PKCEA user logs in through a browser or mobile app“Login with Google/GitHub”
Client CredentialsMachine-to-machine, no userOrder service calling the payment service; partner APIs
Refresh TokenGet a new access token silentlyApp stays logged in for weeks
Device CodeDevices without a keyboardSmart TV “enter this code on your phone”
Implicit, PasswordDeprecated (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.

Advertisement

OAuth 2.0 test cases

  • Token request with wrong client_secret → 401 invalid_client.
  • Token with scope read calling a write endpoint → 403 insufficient_scope.
  • redirect_uri not on the allowed list → rejected (prevents token theft).
  • state parameter 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?

SituationGood choice
Your own mobile or web app’s usersBearer JWT (short-lived) + refresh token, or OIDC
Third-party apps acting for your usersOAuth 2.0 Authorization Code + PKCE
Server-to-server, partnersOAuth 2.0 Client Credentials, mTLS or HMAC-signed requests
Public data APIs with quotasAPI keys
Quick internal tools / test environmentsBasic auth over HTTPS
Advertisement

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.
Advertisement

Authentication Testing Checklist

  1. Every protected endpoint returns 401 without credentials.
  2. Invalid, malformed, expired and revoked credentials return 401.
  3. 401 responses include WWW-Authenticate.
  4. Error messages don’t reveal whether the user exists.
  5. Login and key validation are rate limited.
  6. Credentials travel only over HTTPS and only in headers.
  7. Secrets aren’t logged, cached or returned.
  8. Logout and password change invalidate tokens.
Advertisement

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.

Advertisement
View the full API testing syllabus