web php
HTTP Authentication
HTTP authentication uses request and response headers to authenticate a request. Instead of posting a login form, the client sends credentials in an Authorization header.
The common schemes PHP developers meet are Basic authentication and Bearer token authentication. Basic is often used for simple internal tools or development endpoints. Bearer tokens are common for APIs.
The Authorization header
An HTTP request might include:
Authorization: Bearer example-token
In PHP, this can appear in $_SERVER['HTTP_AUTHORIZATION'], depending on the web server and framework. Many frameworks normalize it for you.
<?php
declare(strict_types=1);
$headers = ['Authorization' => 'Bearer example-token'];
$authorization = $headers['Authorization'] ?? '';
if (!str_starts_with($authorization, 'Bearer ')) {
echo 'Authentication required' . PHP_EOL;
} else {
$token = substr($authorization, 7);
echo 'Received bearer token prefix: ' . substr($token, 0, 7) . PHP_EOL;
}
// Prints:
// Received bearer token prefix: example
Do not log full tokens. Treat them like passwords.
401 responses and challenges
A protected endpoint should reject missing or invalid credentials before running the protected action. For HTTP auth, a 401 Unauthorized response can include a WWW-Authenticate header that tells the client which scheme is expected.
<?php
declare(strict_types=1);
function authenticationChallenge(string $scheme): array
{
return [
'status' => 401,
'headers' => ['WWW-Authenticate' => $scheme],
'body' => 'Authentication required',
];
}
$response = authenticationChallenge('Bearer');
echo $response['status'] . ' ' . $response['headers']['WWW-Authenticate'] . PHP_EOL;
// Prints:
// 401 Bearer
In real web code, the response array would become http_response_code(401), header('WWW-Authenticate: Bearer'), and a short response body.
Basic authentication
Basic authentication sends a base64-encoded username:password value. Base64 is not encryption. Basic authentication must only be used over HTTPS.
<?php
declare(strict_types=1);
function decodeBasicCredentials(string $authorization): ?array
{
if (!str_starts_with($authorization, 'Basic ')) {
return null;
}
$decoded = base64_decode(substr($authorization, 6), true);
if ($decoded === false || !str_contains($decoded, ':')) {
return null;
}
[$username, $password] = explode(':', $decoded, 2);
return ['username' => $username, 'password' => $password];
}
$credentials = decodeBasicCredentials('Basic ' . base64_encode('admin:secret'));
echo $credentials['username'] ?? 'missing';
// Prints:
// admin
Compare secrets using hash_equals() where appropriate so comparisons do not leak timing information.
Bearer authentication
Bearer authentication means whoever has the token can use it. That makes storage, expiry, rotation, and logging important.
<?php
declare(strict_types=1);
function bearerToken(string $authorization): ?string
{
if (!str_starts_with($authorization, 'Bearer ')) {
return null;
}
$token = trim(substr($authorization, 7));
return $token === '' ? null : $token;
}
echo bearerToken('Bearer api_123') ?? 'missing';
// Prints:
// api_123
Extracting the token is not the same as validating it. Real validation may involve checking a database token hash, verifying a JWT signature, checking expiry, and confirming the user or client is still active.
HTTP auth is not form login
HTTP auth happens at the request-header level. Form login usually posts credentials to an application route, then creates a session cookie.
Use form login for normal browser sign-in flows where you need custom UI, sessions, CSRF protection, password reset flows, and account lockout.
Use HTTP auth for APIs, service calls, simple protected tools, or endpoints where header-based credentials are the expected interface.
What to check in a project
Check that missing credentials are rejected before protected work begins.
Check that endpoints return the right status: 401 for missing or invalid authentication, and 403 when the user is authenticated but not allowed.
Check that Basic authentication only runs over HTTPS and does not log passwords.
Check that bearer tokens are not printed, logged, or placed in URLs.
Check that token validation is real validation, not only "does the header start with Bearer".
What you should be able to do
After this lesson, you should be able to parse Basic and Bearer auth headers, return a proper 401 challenge, explain why HTTPS is required, and distinguish extracting credentials from validating them.
Practice
Task: Parse HTTP Auth Headers
Write a small PHP script that parses HTTP authentication headers and returns a clear result.
Requirements
- Use
declare(strict_types=1);. - Detect a Bearer token.
- Decode Basic credentials.
- Return
missingfor unsupported or empty headers. - Include one Bearer case, one Basic case, and one missing case.
- Do not print a full password or full token in the output.
Check Your Work
Run the script and confirm that it identifies the scheme while keeping secrets out of the printed output.
Show solution
This solution extracts enough information to route validation without exposing full secrets.
<?php
declare(strict_types=1);
function describeHttpAuth(string $authorization): string
{
if (str_starts_with($authorization, 'Bearer ')) {
$token = trim(substr($authorization, 7));
return $token === '' ? 'missing' : 'bearer token prefix ' . substr($token, 0, 4);
}
if (str_starts_with($authorization, 'Basic ')) {
$decoded = base64_decode(substr($authorization, 6), true);
if ($decoded === false || !str_contains($decoded, ':')) {
return 'missing';
}
[$username] = explode(':', $decoded, 2);
return $username === '' ? 'missing' : 'basic username ' . $username;
}
return 'missing';
}
$headers = [
'api' => 'Bearer api_123456',
'basic' => 'Basic ' . base64_encode('admin:secret'),
'none' => '',
];
foreach ($headers as $label => $authorization) {
echo $label . ': ' . describeHttpAuth($authorization) . PHP_EOL;
}
// Prints:
// api: bearer token prefix api_
// basic: basic username admin
// none: missing
Parsing only identifies the supplied scheme. A real endpoint would then validate the bearer token or Basic credentials and return a 401 response if they are missing or invalid.
Why This Works
The examples cover both common header schemes and the empty case. The output proves the parser does not need to reveal full secrets to be useful during debugging.