|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2017-09-28 05:57 UTC] ramsey@php.net
Description:
------------
When attempting to implement Bearer tokens[1] for OAuth 2, I discovered an issue where PHP is always forcing the HTTP response status code to 401 when setting the WWW-Authenticate header. As a result, I am unable to follow the Bearer token RFC or the HTTP Authentication RFC[2].
In RFC 6750, section 3 states:
> If the protected resource request does not include authentication
> credentials or does not contain an access token that enables access
> to the protected resource, the resource server MUST include the HTTP
> "WWW-Authenticate" response header field; it MAY include it in
> response to other conditions as well.
It goes on to describe conditions that would result in 401, 403, and other 4xx responses, each of which may include a WWW-Authenticate header.
In RFC 7235, section 4.1 states:
> A server generating a 401 (Unauthorized) response MUST send a
> WWW-Authenticate header field containing at least one challenge. A
> server MAY generate a WWW-Authenticate header field in other response
> messages to indicate that supplying credentials (or different
> credentials) might affect the response.
Admittedly, earlier RFCs (2616 and 2617) were ambiguous on this point, leading many implementations to force WWW-Authenticate to 401 responses only, and it appears PHP is one of these cases.
In main/SAPI.c[3], around lines 829-830, we see the following:
} else if (!strcasecmp(header_line, "WWW-Authenticate")) {
sapi_update_response_code(401);
I think these are the lines that force all responses setting WWW-Authenticate header to have the 401 status code.
[1]: https://tools.ietf.org/html/rfc6750
[2]: https://tools.ietf.org/html/rfc7235
[3]: https://github.com/php/php-src/blob/a51cb393b1accc29200e8f57ef867a6a47b2564f/main/SAPI.c#L829-L830
Test script:
---------------
<?php
header('HTTP/1.1 403 Forbidden');
header('WWW-Authenticate: Bearer realm="Foo"');
Expected result:
----------------
HTTP/1.1 403 Forbidden
Connection: close
Content-type: text/html; charset=UTF-8
Date: Thu, 28 Sep 2017 05:55:32 +0000
Host: localhost:8000
WWW-Authenticate: Bearer realm="Foo"
X-Powered-By: PHP/7.1.3
Actual result:
--------------
HTTP/1.1 401 Unauthorized
Connection: close
Content-type: text/html; charset=UTF-8
Date: Thu, 28 Sep 2017 05:55:32 +0000
Host: localhost:8000
WWW-Authenticate: Bearer realm="Foo"
X-Powered-By: PHP/7.1.3
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Fri Oct 24 16:00:02 2025 UTC |
Workaround: header("WWW-Authenticate: ...", true, 403); or setting the response code after the header. I agree, though, that it might be an option to change the default behavior to check whether another response code has already been set (IIRC just like we already do for 30X response codes).