API Authentication: When to Use JWT, Session Cookies, and API Keys

14 min read 2,758 words
API Authentication: When to Use JWT, Session Cookies and API Keys featured image

Understanding API Authentication Methods in PHP

Authentication failures consistently rank among the most exploited vulnerabilities in web applications. Whether you are building a new PHP application from scratch or maintaining an existing system, choosing the right authentication method directly affects your application's security posture and long-term maintainability. The three approaches covered here—API keys, session cookies, and JSON Web Tokens—each solve a different problem, and using the wrong one for your situation creates risks that are difficult to address later without significant refactoring.

This guide explains how each authentication method works, where it performs best, and how to implement each one securely in PHP. It covers the practical trade-offs you need to understand before committing to a particular approach. For context on how these methods fit into a broader API architecture, reviewing API design principles for business applications alongside this guide may be useful.

What API Key Authentication Is and Where It Works Best

An API key is a static string that uniquely identifies the client making a request. The server maintains a list of valid keys, and every request must present a recognised key before the server processes it. This approach has been the foundation of API security since the earliest public APIs became available, and it remains the simplest option for specific use cases.

API keys are typically passed in a request header. Here is how that looks in practice:

GET /api/resource HTTP/1.1
Host: api.example.com
X-API-Key: sk_live_a1b2c3d4e5f6g7h8i9j0

The server reads the header, checks the key against a database or configuration, and either processes the request or returns a 403 Forbidden response. Revoking access is straightforward—just remove or disable the key on the server side.

API key authentication works well in these scenarios:

  • Server-to-server communication: when two backend systems communicate and both are under your control.
  • Public APIs with rate limiting: when you need to identify which application is making requests without tracking individual end users.
  • Simple integrations: when the complexity of JWT or OAuth is not justified by the sensitivity of the data being accessed.

API keys are a poor choice when you need to identify individual users, track session state, or grant short-lived access without a backend session store. Storing API keys in client-side JavaScript or mobile app code creates a significant risk because decompilation exposes the key to anyone who downloads your application.

How Session Cookie Authentication Works in PHP

Session-based authentication uses server-side storage to track logged-in users. When a user submits credentials, the server validates them and stores a session identifier in a database or memory store. This identifier is sent back to the browser as a cookie. On every subsequent request, the browser automatically sends the cookie, and the server looks up the session to identify the current user.

PHP provides session handling as a built-in feature:

session_start();

if (password_verify($_POST['password'], $stored_hash)) {
    $_SESSION['user_id'] = $user['id'];
    $_SESSION['login_time'] = time();
}

PHP manages the cookie transmission automatically. Your code only needs to check $_SESSION on each request to determine who is making the call. Sessions also integrate naturally with PHP's CSRF token mechanisms, which matters for any application that processes form submissions.

Session authentication works well in these situations:

  • Traditional server-rendered applications: when your application generates HTML pages on the server and serves them to a browser.
  • Applications requiring server-side state: when user data should not be exposed to the client at all.
  • Browser-based workflows with forms: where CSRF protection is straightforward to implement using PHP's built-in tools.

Sessions are not a good fit for pure API-driven applications where the frontend runs separately from the backend, or when the API must be accessible from mobile apps or external services that do not maintain browser cookies. For a detailed look at PHP session vulnerabilities that are easy to overlook, the PHP session security guide covers the specific problems that cause issues in production systems.

JSON Web Token Authentication: How It Works and When It Helps

A JSON Web Token is a self-contained string that carries claims about the user. The token is cryptographically signed by the server using a secret key or private key, and any recipient can verify the signature without querying a database. This stateless verification makes JWTs particularly useful when multiple services need to confirm user identity independently.

A JWT has three Base64-encoded parts separated by dots: the header, the payload, and the signature. The payload contains the claims, such as the user ID and expiration time. Here is how to decode a JWT in PHP using a common library:

use Firebase\JWT\JWT;
use Firebase\JWT\Key;

$token = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
$token = str_replace('Bearer ', '', $token);
$decoded = JWT::decode($token, new Key($secret, 'HS256'));
$user_id = $decoded->sub;

When a user logs in, the server creates a token with an expiration claim, signs it, and sends it to the client. The client stores the token and includes it with every subsequent request. The server verifies the signature on each request without querying a database, which removes a database round-trip on every authenticated call.

JWT authentication works well in these situations:

  • Microservices and distributed systems: when multiple services need to verify user identity without contacting a central database.
  • Single Page Applications: when the frontend and backend are separate applications and managing cookies is inconvenient.
  • Temporary access grants: when you need to issue credentials that expire automatically after a set time.

JWTs have important limitations that cause real problems when ignored. A token cannot be revoked before expiration because verification is stateless. If a token is compromised, the attacker has access until the expiration time. Storing sensitive data in the payload is unsafe because anyone can Base64-decode the token and read the contents. These limitations mean JWTs are not a universal replacement for sessions. Applications that need immediate revocation should implement a token blocklist or use shorter expiration windows.

Security Configuration for Session Cookies

Proper session configuration is one of the most important security steps in any PHP application. Without the correct cookie flags, sessions are vulnerable to theft through cross-site scripting and network eavesdropping. PHP provides the settings you need, but they require explicit configuration.

Always set the httponly, secure, and samesite flags when initialising sessions:

session_set_cookie_params([
    'lifetime' => 0,
    'path' => '/',
    'domain' => '',
    'secure' => true,
    'httponly' => true,
    'samesite' => 'Lax'
]);
session_start();

The httponly flag prevents JavaScript from reading the session cookie, which blocks theft through cross-site scripting. The secure flag ensures the cookie is only transmitted over HTTPS, protecting it from interception on the network. The samesite flag helps prevent cross-site request forgery by controlling when the browser sends the cookie.

Beyond cookie flags, also configure PHP's session management directives in php.ini or through ini_set:

  • session.use_strict_mode: prevents the session handler from accepting an uninitialised session ID.
  • session.cookie_httponly: as shown above, blocks JavaScript access to the cookie.
  • session.use_only_cookies: prevents session IDs from being passed through URLs, which exposes them in server logs and browser history.
  • session.gc_maxlifetime: controls how long sessions remain valid before garbage collection removes them.

Comparing Authentication Methods Side by Side

Understanding the differences between these approaches helps you make informed decisions for each part of your application rather than forcing a single pattern everywhere.

The fundamental differences between these authentication methods:

  • State management: API keys are stateless and static. Sessions are stateful with server-side storage. JWTs are stateless but self-contained with signed claims.
  • Revocation speed: API keys and sessions can be revoked immediately. JWTs cannot be revoked without a blocklist or shorter expiration windows.
  • Storage requirements: API keys need a database lookup. Sessions need a session store or database. JWTs need only the signing secret.
  • Browser compatibility: Sessions work automatically with browsers. API keys should never be stored in browser code. JWTs can be stored in localStorage or httpOnly cookies.
  • Scaling characteristics: JWTs scale horizontally without shared state. Sessions require a shared session store across all application servers. API key lookups scale with database performance.

For PHP applications specifically, the choice often depends on whether the application is server-rendered or API-driven. Server-rendered applications naturally benefit from session cookies. API-first architectures typically work better with JWTs or API keys. Many real-world applications use a combination of these methods, which is perfectly reasonable as long as each is applied in the appropriate context.

Common Implementation Mistakes and How to Avoid Them

Authentication implementations regularly contain the same mistakes that lead to security vulnerabilities. Recognising these errors helps you avoid them in your own code.

Committing API keys to version control is the most common and most damaging mistake with API key authentication. Use environment variables or a secrets manager instead. Even private repositories can be exposed through accidents, and any key that has been in version control should be treated as compromised and rotated immediately.

Using sessions for API-only applications creates unnecessary server-side state and complicates horizontal scaling. If your application exposes an API consumed by mobile apps, Single Page Applications, or external services, prefer JWTs or API keys over sessions.

Storing API keys as plain text in the database is catastrophic if the database is compromised. Always store a hashed version of the key and verify by hashing the presented key and comparing the results. You cannot display the full key to the user after initial creation, but this prevents a database leak from exposing valid credentials.

Failing to validate JWT expiration is a common error. Always check the expiration claim and handle the expired case separately from an invalid signature. This distinction matters for user experience:

try {
    $decoded = JWT::decode($token, new Key($secret, 'HS256'));
} catch (ExpiredException $e) {
    http_response_code(401);
    echo json_encode(['error' => 'Token expired']);
    exit;
} catch (\Throwable $e) {
    http_response_code(401);
    echo json_encode(['error' => 'Invalid token']);
    exit;
}

Using the same JWT signing secret across environments increases risk. If a secret leaks in development, it may be reused accidentally in production. Keep secrets separate per environment, store them in environment variables or a secrets manager, and rotate them regularly.

Choosing the Right Authentication Method for Your Situation

Use API keys for machine-to-server communication where the client is a server, a CLI tool, or a trusted application under your control. This model works well for background jobs, webhooks, and internal service calls. API keys are particularly appropriate when the calling service is a backend system you manage and the risk of exposure is controlled through proper secrets management.

Use session cookies for traditional server-rendered web applications where users interact through a browser. PHP's built-in session handling is well-tested and becomes secure with proper configuration. For PHP-based applications serving HTML pages, sessions remain the most straightforward choice for browser-based authentication.

Use JWTs when your application needs to scale horizontally without shared session storage, or when multiple independent services need to verify the same authentication token. JWTs are also the right choice when the frontend is a separate application from the backend and managing cookies is impractical. For applications handling sensitive user data, reviewing the OWASP Top 10 for business web applications provides context on the security risks that a solid authentication foundation helps address.

In practice, many applications benefit from using different methods for different parts of the system. A web application might use sessions for browser-based login and JWTs for API access from mobile clients. A microservices architecture might use API keys for service-to-service calls and JWTs for user-facing endpoints. Selecting the right tool for each interaction produces simpler and more maintainable systems than forcing one method everywhere.

Protecting Authentication Systems Against Common Attacks

Regardless of which authentication method you use, certain protections apply to all implementations. Rate limiting on login endpoints makes brute force attacks impractical. Progressive delays after failed login attempts slow down credential stuffing. Multi-factor authentication adds a second verification step for sensitive operations.

Logging authentication events helps detect attacks in progress. Record the IP address, timestamp, and result of every login attempt, including API key presentations. Unusual patterns such as many failed attempts from a single IP or repeated failures against a single account should trigger alerts. This logging is essential for incident response and for understanding normal versus abnormal access patterns.

CSRF protection matters for any session-based application that uses forms. Without CSRF tokens, an attacker can trick a logged-in user into submitting unwanted requests. PHP's built-in session handling works well with CSRF token generation. For a practical implementation guide, the CSRF protection guide for PHP covers token generation and validation in detail.

Putting the Right Authentication in Place

API key authentication is the simplest option for server-to-server communication where the calling service is a trusted backend system. Session cookies are the right choice for traditional browser-based web applications built with PHP, where the server renders HTML pages and the user interacts through a browser. JWTs provide stateless authentication for distributed systems and decoupled frontends, but they require careful handling of expiration and revocation logic.

Choosing the wrong method for your situation adds unnecessary complexity and can introduce security vulnerabilities that are difficult to address later. Understanding what each method actually does, rather than applying a single pattern everywhere, produces more secure and maintainable authentication systems. Many PHP applications benefit from using different authentication methods for different parts of the system, and that mixed approach is not a sign of poor architecture.

If you are building or maintaining a PHP application and want a practical security review of your current authentication setup, prepare a summary of what you have implemented, how user data is currently stored, and what concerns you want to address before getting in touch.

Frequently Asked Questions

Can I use sessions and JWTs in the same application?
Yes. Many applications use sessions for browser-based access and JWTs for API clients. Both mechanisms can coexist as long as each is used in the appropriate context. A common pattern is session-based authentication for the main web interface and token-based authentication for mobile apps, external integrations, or Single Page Applications that share the same backend API.
Where should I store a JWT on the client side?
For browser-based Single Page Applications, storing the token in an httpOnly cookie prevents JavaScript from reading it, which reduces the impact of cross-site scripting attacks. Storing in localStorage is more convenient but exposes the token to any JavaScript running on the page. The httpOnly cookie approach is generally more secure for user authentication tokens because it leverages the browser's existing cookie security model rather than relying on JavaScript access controls.
Should I use the same signing key for all JWTs in my application?
No. If your application has different trust boundaries, such as admin panels versus customer-facing features, use separate signing keys. Compromise of one key then does not automatically affect other areas. This principle of least privilege applies to signing keys just as it does to database access credentials and server permissions.
How often should API keys be rotated?
Rotate API keys immediately whenever there is any suspicion of compromise. For routine rotation without suspected compromise, quarterly or biannual rotation is a reasonable minimum for production systems. Building key rotation support into the system from the start means it can be done without service disruption. Automated rotation with grace periods for old keys is the most robust approach for high-traffic APIs.
What should happen when a JWT expires during an active session?
When a JWT expires, the server rejects it and the client receives a 401 response. Your application needs to handle this gracefully by prompting the user to re-authenticate or by using a refresh token to obtain a new access token without requiring the user to log in again. Implementing proper token refresh logic prevents expired tokens from causing sudden interruptions for active users.
Are sessions more secure than JWTs for PHP applications?
Neither method is inherently more secure than the other. Security depends entirely on implementation. Sessions have been battle-tested in PHP for years and benefit from mature built-in handling. JWTs offer flexibility for distributed systems but require careful implementation of expiration checking and revocation logic. The appropriate choice depends on your architecture rather than a security ranking between the two methods.
What information should I gather before reviewing my current authentication setup?
Before seeking a review of your authentication implementation, document which authentication method you currently use, where user credentials are stored, how sessions or tokens are managed, what cookie flags are set, and whether you have logging in place for authentication events. This information helps identify gaps and prioritise fixes.