Authentication vs. Authorization

Before diving into mechanisms, understand the two concepts:

  • Authentication (AuthN) — “Who are you?” Verifying the identity of the client making the request.
  • Authorization (AuthZ) — “What can you do?” Determining what resources and actions the authenticated client is allowed to access.

A user might be authenticated (logged in) but not authorized (lacks permission) to delete another user’s account. Testing both aspects is critical.

API Key Authentication

The simplest form of API authentication. The server issues a unique key that the client includes with every request.

How It Works

GET /api/weather?city=London HTTP/1.1
Host: api.weather.com
X-API-Key: sk_live_abc123def456

Or as a query parameter (less secure):

GET /api/weather?city=London&api_key=sk_live_abc123def456

Testing API Keys

Test ScenarioExpected Result
Valid API key200 OK with data
Missing API key401 Unauthorized
Invalid/expired API key401 or 403
Revoked API key401 Unauthorized
API key from wrong environment401/403
Rate limit exceeded for key429 Too Many Requests
API key in URL vs headerBoth should work (or URL should be rejected)

Security Concerns

  • API keys should never be in URLs (they appear in server logs and browser history)
  • Keys should be transmitted over HTTPS only
  • Keys should have scoped permissions (read-only vs read-write)

Basic Authentication

Sends username and password encoded in Base64 with every request. Simple but not very secure.

How It Works

GET /api/users HTTP/1.1
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=

The value after “Basic” is username:password encoded in Base64. It is not encrypted — anyone intercepting the request can decode it.

Testing Basic Auth

# Encode credentials
echo -n "admin:secret123" | base64
# Result: YWRtaW46c2VjcmV0MTIz

# Use in request
curl -H "Authorization: Basic YWRtaW46c2VjcmV0MTIz" https://api.example.com/users

Test scenarios: valid credentials, wrong password, non-existent user, empty credentials, malformed Base64.

OAuth 2.0

The industry standard for authorization. OAuth 2.0 allows third-party applications to access user resources without sharing passwords.

OAuth 2.0 Flows

Authorization Code Flow (most common for web apps):

  1. User clicks “Login with Google”
  2. App redirects to Google’s authorization server
  3. User logs in and grants permission
  4. Google redirects back with an authorization code
  5. App exchanges code for access token (server-to-server)
  6. App uses access token to call APIs

Client Credentials Flow (server-to-server, no user):

  1. App sends client_id and client_secret to auth server
  2. Auth server returns access token
  3. App uses token to call APIs

Key tokens in OAuth 2.0:

  • Access Token — short-lived, used to access APIs (15 min to 1 hour)
  • Refresh Token — long-lived, used to get new access tokens (days to months)

Testing OAuth 2.0

Test ScenarioExpected Result
Valid access token200 OK
Expired access token401 Unauthorized
Refresh token flowNew access token issued
Expired refresh tokenForce re-authentication
Invalid scope403 Forbidden
Token with insufficient scope403 with scope error
Revoked token401 Unauthorized
Using access token after logout401 Unauthorized

JSON Web Tokens (JWT)

JWT is a compact, self-contained token format commonly used for authentication. It allows the server to verify the token without querying a database.

JWT Structure

A JWT has three parts separated by dots: header.payload.signature

eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFsaWNlIn0.signature

Header (algorithm and type):

{
  "alg": "HS256",
  "typ": "JWT"
}

Payload (claims — user data):

{
  "sub": "1234567890",
  "name": "Alice",
  "role": "admin",
  "iat": 1716239022,
  "exp": 1716242622
}

Signature (verification):

HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

Important JWT Claims

ClaimNamePurpose
subSubjectUser identifier
iatIssued AtWhen the token was created
expExpirationWhen the token expires
issIssuerWho created the token
audAudienceWho the token is intended for
roleRoleUser’s permissions (custom)

Testing JWT Authentication

Token validation tests:

  • Valid token — 200 OK
  • Expired token — 401 Unauthorized
  • Tampered payload (modified claims) — 401 (signature invalid)
  • Missing signature — 401
  • Token signed with wrong secret — 401
  • Token with alg: none — 401 (critical security test)

Token lifecycle tests:

  • Verify token contains expected claims after login
  • Verify expired tokens are rejected
  • Test refresh flow generates new valid token
  • Verify old tokens are invalid after password change
  • Test token works across different API endpoints

Decode JWT for testing (use jwt.io or command line):

# Decode payload (middle part)
echo "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFsaWNlIn0" | base64 -d

Common Authentication Vulnerabilities to Test

1. Broken Authentication

  • Can you access protected endpoints without any token?
  • Does the API accept tokens after they should be invalidated?
  • Are passwords transmitted in plain text?

2. Token Manipulation

  • Can you modify JWT claims and still access resources? (weak/missing signature verification)
  • Does alg: none bypass signature verification?
  • Can you use a token from one environment in another?

3. Brute Force Protection

  • Is there a lockout after multiple failed login attempts?
  • Are rate limits applied to authentication endpoints?
  • Do error messages reveal whether a username exists?

4. Session Management

  • Are tokens invalidated on logout?
  • Does password change invalidate existing tokens?
  • Can multiple active sessions exist simultaneously?

Hands-On Exercise

  1. Set up JWT testing: Use jwt.io to create and decode JWTs. Modify claims and observe what happens when you send tampered tokens.
  2. Test authentication flows: Using a public API that requires authentication (GitHub API with personal access tokens), test valid auth, invalid auth, and missing auth scenarios.
  3. Create a test matrix: For an imaginary API with admin and user roles, create a matrix of endpoints x roles x expected status codes.
  4. Test token expiration: If available, get a short-lived token and verify it’s rejected after expiration.

Key Takeaways

  • Authentication verifies identity (who you are); authorization verifies permissions (what you can do)
  • API Keys are simple but limited — best for server-to-server and public API rate limiting
  • OAuth 2.0 is the standard for third-party access with multiple flows for different use cases
  • JWTs are self-contained tokens with header, payload, and signature — the payload is readable by anyone
  • Always test the complete lifecycle: valid tokens, expired tokens, revoked tokens, tampered tokens, and missing tokens