Authorization header to php-fpm

(Lewis De Payne) #1

For this particular customer, I am running caddy without any proxy. I need to pass the Authorization header to the php-fpm process. Apparently, after searching and reading dozens of other similar posts, this is not possible in caddy? Assuming the following relevant stuff (silent.inc isn’t relevant), is there any way of passing the authorization header to the fastcgi (a php-fpm process)?

rpc.someone.com:443 {
  root /www/website/rpc.someone.com
  fastcgi / 127.0.0.1:9000 php
  import /www/webconf/silent.inc
  rewrite /audit/v1/ /audit/rpc-server.php/{file}
}

Due to HIPAA and audit reasons, I don’t want to use the caddy JWT/auth plugins, as that opens up a whole new can of worms. I’ve also looked at the rewrite rules, and they don’t seem to support what I want to do. I guess I’d just like confirmation that this still isn’t possible in caddy. For the time being, I’m also setting a ‘jwt’ cookie with the authorization header value, but duplication isn’t ideal if another solution exists. @matt, any advice? Thanks.

(Matthew Fay) #2

I didn’t think communication through FastCGI works in terms of HTTP headers, per se. Information is available to the scripts via environmental variables.

You’re probably wanting to set a variable for the PHP script.

env key value

env sets an environment variable named key with the given value ; the env property can be used multiple times and values may use request placeholders.

https://caddyserver.com/docs/fastcgi

So, you can try env Authorization {>Authorization} inside your fastcgi directive…

That said, the code already does this. It should already be available as the variable HTTP_AUTHORIZATION, if I’m not mistaken.

1 Like
(Lewis De Payne) #3

PHP only parses the Authorization header for Basic and Digest. Since I’m using Bearer auth, none of that works. A popular solution is to rewrite the header, prefixing it with “HTTP_” so that php regurgitates it:

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

But there seems to be no way of doing that in caddy (for a request header). Pulling the request header using the caddy env keyword doesn’t work. I’ve tried these variations:

env Authorization {>Authorization}
env BEARER {>Authorization}

I’m not sure why the env solution is not working, since it’s the equivalent of this in Apache:

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

Of course, Postman shows that I’m sending the proper header:

Authorization: Bearer eyJhbGciO…f0E

Sadly, nothing works so far, and I’m stuck with setting a cookie for the bearer.

(Matthew Fay) #4

Hi LewPayne,

Caddy’s definitely setting those variables. It sets every single one regardless of its contents. I’m not sure why they wouldn’t be available for your PHP environment.

Here’s what I’ve tried, tested working.

Projects/www/test
➜ echo "<?php print_r($_SERVER) ?>" > index.php

Projects/www/test via 🐘 v7.3.5
➜ caddy -version
Caddy v1.0.0 (h1:KI6RPGih2GFzWRPG8s9clKK28Ns4ZlVMKR/v7mxq6+c=)

Projects/www/test via 🐘 v7.3.5
➜ caddy -port 2016 "fastcgi / /var/run/php/fpm.sock php"
Activating privacy features... done.

Serving HTTP on port 2016
http://:2016

And the request:

Projects/www/test via 🐘 v7.3.5
➜ curl -iH "Authorization: Bearer foobar123" localhost:2016
HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Server: Caddy
X-Powered-By: PHP/7.3.5
Date: Tue, 14 May 2019 02:46:36 GMT
Content-Length: 1011

Array
(
    [USER] => whitestrake
    [HOME] => /Users/whitestrake
    [SERVER_PORT] => 2016
    [REQUEST_METHOD] => GET
    [REMOTE_HOST] => ::1
    [AUTH_TYPE] =>
    [HTTP_AUTHORIZATION] => Bearer foobar123
    [HTTP_HOST] => localhost:2016
    [DOCUMENT_ROOT] => /Users/whitestrake/Projects/www/test
    [SERVER_SOFTWARE] => Caddy/v1.0.0
    [PATH_INFO] =>
    [REMOTE_IDENT] =>
    [HTTP_USER_AGENT] => curl/7.54.0
    [SCRIPT_FILENAME] => /Users/whitestrake/Projects/www/test/index.php
    [REQUEST_URI] => /
    [DOCUMENT_URI] => /index.php
    [REMOTE_PORT] => 50900
    [REMOTE_ADDR] => ::1
    [CONTENT_LENGTH] => 0
    [GATEWAY_INTERFACE] => CGI/1.1
    [HTTP_ACCEPT] => */*
    [SERVER_PROTOCOL] => HTTP/1.1
    [REQUEST_SCHEME] => http
    [SERVER_NAME] =>
    [REMOTE_USER] =>
    [QUERY_STRING] =>
    [CONTENT_TYPE] =>
    [SCRIPT_NAME] => /index.php
    [FCGI_ROLE] => RESPONDER
    [PHP_SELF] => /index.php
    [REQUEST_TIME_FLOAT] => 1557801996.4314
    [REQUEST_TIME] => 1557801996
)

Note the presence of [HTTP_AUTHORIZATION] => Bearer foobar123.

1 Like
(Lewis De Payne) #5

Matthew - You really went out of your way to test this… thank you. As it turns out, this is neither a caddy nor a php-fpm issue. I was using phpinfo() to spit out everything it was seeing, and it turns out phpinfo() refuses to show Authorization headers (at least for the Bearer type). I got used to the fact that for basic and digest auth, phpinfo()'s default behavior was to show (and parse) authorization components.

In the end, Postman was showing that I was sending the header, but phpinfo was suppressing it. I am mildly annoyed by the amount of time I spent diagnosing this, and I apologize for taking up your time. There was also an added dimension - how the header behaves during a CORS preflight request. I’ve sorted out that annoyance as well.

1 Like
(Matthew Fay) #6

Heh, good to see it was helpful, at least.

I’d like to say it took me no time at all because I have Caddy with PHP already set up in a couple of places. But I actually tested this on my mac, which was a wild ride because I discovered for some reason that Homebrew PHP-FPM was no longer listening on port 9000.

So I actually spent about 30 minutes sorting out Homebrew, dealing with some libicui18n.62.dylib issue, changing the FPM listener to a socket. But my local PHP environment works again, so I’ve got that going for me.