96

I'm currently trying to read the authorization header in a PHP script that I'm calling with a POST request. The Authorization header is populated with a token. It seems the Authorization header is somehow removed before it arrives at my PHP script. I'm executing the post request with Postman (Chrome addon) and I enabled CORS in my PHP script. I don't have access to the apache server directly.

HTTP Request:

Accept:*/*
Accept-Encoding:gzip,deflate
Accept-Language:de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4,ja;q=0.2
Authorization:Bearer mytoken
Cache-Control:no-cache
Connection:keep-alive
Content-Length:32
Content-Type:text/plain;charset=UTF-8
Host:www.myhost.com
Origin:chrome-extension://fdmmgilgnpjigdojojpjoooidkmcomcm
 User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)       
 Chrome/38.0.2125.104 Safari/537.36

PHP script:

header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: Authorization, Origin, X-Requested-With, Content-Type,      Accept");
header("Content-Type: application/json");

$headers = getallheaders();
echo $headers['Authorization'];

The above script outputs '' (= nothing).

igorsantos07
  • 4,456
  • 5
  • 43
  • 62
jimmy
  • 4,471
  • 3
  • 22
  • 28

11 Answers11

263

Somehow, the Authorization header was stripped away. By adding the following lines in my .htaccess, I was able to get it to work.

RewriteEngine On
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]
Zoe
  • 27,060
  • 21
  • 118
  • 148
jimmy
  • 4,471
  • 3
  • 22
  • 28
  • 2
    I had the same problem when trying to use HTTP Basic Authorization with my REST api on Php 5.4 and Apache. I had modified the .htaccess file to support RewriteEngine On for the rest api and similarly all my request headers seemed to be there except authorization when I query them in PHP. Your fix is correct, thanks! – Deemoe Dec 16 '14 at 20:04
  • 1
    This fixes the same problem occurring when using CodeIgniter 3 using the codeigniter-restserver library when custom routes are being used. Interestingly enough it also creates two headers, `HTTP_AUTHORIZATION` and `REDIRECT_HTTP_AUTHORIZATION`, both with an identical value. – TJ L Mar 15 '17 at 19:12
  • Awesome answer, works perfectly. If you have other conditions in your .htaccess file, I've placed this at the top (first). – Calin Jul 10 '17 at 12:52
  • 15
    4 years later on PHP 7.2 and this is still relevant! Awesome fix! – spice Dec 28 '18 at 21:48
  • 1
    glad I found it at the first hit in google, saved me headache... works perfectly – Joey Feb 19 '19 at 07:39
  • 16
    I was going to upvote this... then I realized I already had, the last time I had this problem. – Jerry Mar 22 '19 at 23:06
  • 5
    Excellent solution... Now can someone explain what is going on? This only happens on some servers. Why does it get stripped out? – James John McGuire 'Jahmic' May 02 '20 at 09:30
  • 11
    I was curious about this too; apparently Apache does not pass the `Authorization` header by default for security reasons. Instead, you must manually enable it (circa 2.4.13) with the `CGIPassAuth` directive, valid in `.htaccess` or in directory configs. This functionality has applied to previous versions as well, but I'm not able to find documentation explaining this for those older versions. – patricknelson Aug 12 '20 at 00:59
  • 1
    This is still relevant in the year 2021 for the version PHP 7.4. – Pradip Shenolkar Mar 24 '21 at 11:46
  • in IIS , how i can make that ? could you please help me ? – Quentin Merlin Jun 11 '21 at 15:03
  • Found this interesting note -- This is a "security feature", to prevent the user's credentials from being passed to all CGI scripts (which might not be trusted, if you don't control the server). PHP normally sets the $_SERVER['HTTP_AUTHORIZATION'] superglobal (and associated array elements) from the HTTP Authorization header, but if it's been stripped by Apache then it can't. The RewriteRule directive in .htaccess attempts to "fix" this by setting an HTTP_AUTHORIZATION – Ncoder Jun 06 '22 at 13:00
  • Thanks, solved half of our problem. The only issue with this solution is that, if your HTTP header validation differs among provided and non-provided HTTP Headers, this solution actually generates an `Authorization` header with a value of an empty string, even if none was provided. Using `CGIPassAuth On` does not do this, and passes the `Authorization` header properly to your scripts. – DevelJoe Jun 18 '23 at 23:12
79

I had first to add this to my machines Apache config file:

SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1

On Linux in /etc/apache2/apache2.conf

On Mac using Homebrew in /usr/local/etc/httpd/httpd.conf

On Mac with "native" Apache: /private/etc/apache2/httpd.conf or: /etc/apache2/httpd.conf

Adding this to .htaccess didn't work for any reason:

RewriteEngine On
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]

Update 2022:

According to multiple comments you can achieve the same result in multiple ways (can't confirm it though due to switching to nginx in all my projects a couple of years ago):

you can place SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1 in .htaccess per project basis, but also 'globally' in httpd.conf, or per project in the httpd-vhosts.conf file within <VirtualHost> block.

FullStack Alex
  • 1,783
  • 19
  • 31
  • 12
    You can add `SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1` in .htaccess. That worked for me. – Mohit Sep 14 '19 at 08:08
  • 2
    It worked for me. I'm using aws lightsail so.. I added the code in /opt/bitnami/apache2/conf/httpd.conf. In addition I think restarting server is necessary. sudo /opt/bitnami/ctlscript.sh restart apache. – mazend Feb 08 '20 at 02:43
  • @Mohit For me this had to be in the Apache config file (or virtualhost config) – i.e. it did *not* work when added to the .htaccess file. I don't know why this is because I have `AllowOverride ALL` set – Ade Mar 15 '20 at 20:43
  • I was having errors with Laravel Passport, the server returned Unauthenticated. With this response I was able to fix it. Lifesaver! – David Copano Jiménez May 09 '20 at 16:48
  • This solved the issue on a Bitnami wordpress server too. The Apache2 config is put in the file opt/bitnami/apache2/conf/httpd.conf I added `SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1` and it got rid of the error. Thank you – Hevski Mar 11 '21 at 22:16
  • Thank you! Updating .htaccess alone did not do the trick, but adding that to my httpd.conf file did the trick after a restart. – prafferty Apr 24 '21 at 18:01
  • How to do that in iIS ? – Quentin Merlin Jun 13 '21 at 20:19
  • For brevity, this works within `` elements in the httpd-vhosts.conf file as well. FYI, local apache server on windows – soulshined Dec 13 '21 at 02:18
  • 1
    Just for clarity: you can place `SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1` in .htaccess per project basis, but also 'globally' in httpd.conf, or per project in the httpd-vhosts.conf file within block. – ViBoNaCci Nov 01 '22 at 11:16
20

The most elegant solution to this problem is enabling this directive in .htaccess.

CGIPassAuth On

This directive is part of the apache core and doesn't require any special module to be enabled. See the documentation here.

The problem happens when using php-fpm with apache (as oposed to using the php module directly in apache).

This is a security measure that prevents sensitive data to be transfered from apache to php through fcgi.

This solution fixes not only $_SERVER["HTTP_AUTHORIZATION"] but also $_SERVER["PHP_AUTH_USER"], used in "Basic" authentication as described in php's official documentation.

In my opinion, all other solutions that involve setting the HTTP_AUTHORIZATION environment variable through SetEnvIf or with RewriteRules are workarounds and don't solve the root problem.

I tested this solution in 2021 with php7.4.

santiago arizti
  • 4,175
  • 3
  • 37
  • 50
15

if you use WHM + CPanel + PHP and if your show result like this here missing Authorization

Array
(
    [Host] => domain.com
    [Connection] => keep-alive
    [Cache-Control] => max-age=0
    [Upgrade-Insecure-Requests] => 1
    [User-Agent] => Mozilla/5.0
    [Accept] => text/html,application/xhtml+xml
    [Sec-Fetch-Site] => none
    [Sec-Fetch-Mode] => navigate
    [Sec-Fetch-User] => ?1
    [Sec-Fetch-Dest] => document
    [Accept-Encoding] => gzip, deflate, br
    [Accept-Language] => en
)

Now just flow these steps.

Step 1: .htaccess file add

RewriteEngine On

RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

Step 2: add in your PHP file like index.php

1. getallheaders();

2. apache_request_headers();
 
3. $SERVER['REDIRECT_HTTP_AUTHENTICATION'];

You can use anyone.

Step 3: go to WHM Panel and flow this navigation

Home » Service Configuration » Apache Configuration » Include Editor » Pre VirtualHost Include » All Version 

Add this line

SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1

and Restart Apache Server (if not restart the server then not working properly)

Step 4: My Result Show

Array
(
    [Authorization] => hhRbRZtypswriasabjn3xHT+9Fe9sWHjejhID/YTmookDdrN7WyTUULWwCvmMRiW0RaDRtozLVnvjnl
    [User-Agent] => PostmanRuntime/7.26.8
    [Accept] => */*
    [Cache-Control] => no-cache
    [Host] => domain.com
    [Accept-Encoding] => gzip, deflate, br
    [Connection] => keep-alive
    [Content-Type] => application/x-www-form-urlencoded
    [Content-Length] => 3
    [X-Https] => 1
)

this work has done. after you flow these steps and again show the same error please comment here

Purvesh Tejani
  • 151
  • 1
  • 2
8

Below array holds request headers, that may be missing in $_SERVER variable

$headers = apache_request_headers();

(Especially true for 'HTTP_X_REQUESTED_WITH' ajax header, which will be found this way as: $headers['X_REQUESTED_WITH']

Grigoreas P.
  • 2,452
  • 25
  • 19
  • Although this is correct, I can see the correct header in there (and this is much better than using the .htaccess solution!) the key in the array are CASE SENSITIVE. So you can't easily access them without tweaking the array first... – Alexis Wilke Nov 03 '18 at 23:52
  • 1
    See this answer about transforming the keys of an array to lower or upper case: https://stackoverflow.com/questions/4240001/php-array-keys-case-insensitive-lookup#answer-4240019 – Alexis Wilke Nov 04 '18 at 00:09
  • BE AWARE! apache_request_headers() is a function which is only defined when you use Apache as a web server. So everyone with nginx etc. is left out. – Alex Abreu Mulet Aug 02 '23 at 14:24
3

I want to extend the previous answers with a specific case.

I'm using LAMP (bitnami) on AWS (Lightsail). My code is written using CodeIgniter 3. So I already have a .htacess file and this is what's in it:

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ index.php/$1 [L]
</IfModule>

I wanted to implement jimmy's solution:

RewriteEngine On
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]

But how? Everyone seems to "suggest" something, but not be specific about it. Having multiple rewrite conditions/rules seemed problematic. I'm not an Apache guru, so I had to experiment. I managed to get it working in the following way:

<IfModule mod_rewrite.c>
    RewriteEngine On
    
    RewriteCond %{HTTP:Authorization} ^(.*)
    RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]
    
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ index.php/$1 [L]
</IfModule>

Now, there's an "HTTP_AUTHORIZATION" key in the $_SERVER array.

Edit: There seems to be also another key "REDIRECT_HTTP_AUTHORIZATION" with the same value.

akinuri
  • 10,690
  • 10
  • 65
  • 102
2

In my case if found it in $_SERVER["REDIRECT_HTTP_AUTHORIZATION"]

Pavel Popov
  • 111
  • 1
  • 3
1

This solution (mentioned above) worked for me after tricking httpd.conf file:

RewriteEngine On
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]

To make this work, httpd.conf had to include these directives in my Alias section:

AllowOverride All
Options FollowSymLinks

The first one is too open (yes, I know), but .htaccess is totally avoided if you put AllowOverride None.

Also, RewriteRule is avoided too is you don't use FollowSymLinks or so (based in Apache docs)

hgc2002
  • 318
  • 2
  • 11
1

For me, enabling PHP-FPM on PHP 8.1 fixed the issue, without any amendment in htaccess.

Mahmoud
  • 11
  • 1
0

We were able to address this same issue by switching to use the php-fpm (FastCGI) instead of using mod_php for apache. The header is passed unmolested to FastCGI but seems to be stripped by mod_php.

nullability
  • 10,545
  • 3
  • 45
  • 63
0

I have used a slightly different syntax which I found in some other place (don't remember where that was) and this also works for me on the project's .htacess file.

RewriteEngine On
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
ulrich
  • 1,431
  • 3
  • 17
  • 46