This is a simple technical blog post because I just had to do this and there's literally nothing out there on the Internet!
First, some background
We have used Yubico YubiKeys for some time as one of the multi-factor authentication tools supported by our systems. What does multi-factor authentication mean? It means the scenario where an action, typically on the Internet, requires more than one level of authentication to complete.
Often this will be a password plus something else. A phrase you might hear to describe multi-factor, or sometimes second-factor or two-factor authentication, is the act of verifying yourself requires "something you know and something you own" to complete.
A good real-life example of this most of you will be familiar with is online banking. If you want to add a beneficiary to your account using online banking, you'll have to login with a username and password (something you know), then you'll probably have to use one of those banking fobs or a phone app or receive an SMS to carry out the actual act of adding a beneficiary (something you own, either the fob or your mobile phone).
Multiple, or at least two different factors of authentication. Someone might know your password, but without your fob or phone, it's no use to them.
Or vice versa, they might steal your banking fob but if they don't know your password it's no use to them. This is clearly a good way of making online applications more secure.
In our case, one of the things you can own is a YubiKey, so that a simple press of the little button on top provides your second factor of authentication. No need to go fishing for your phone and typing in SMS codes or authenticator app read-outs. Handy!
The supporting software for the earlier YubiKeys is pretty old now, but it's just PHP apps and we want to continue using it, so I was in the process of moving it to the latest versions of Debian (11) and PHP (8.0). I didn't want to use the Apache web server it ships with, because we prefer Nginx as an organisation, so I set about looking for a configuration that would work for Nginx. And I couldn't find anything!
It took me a good few hours of reading manuals and testing before I managed to create a working configuration, so in the interest of being a good open-source developer, I decided to share it. Here's what a working config for Nginx looks like:
server { listen 80 default_server; server_name MYSERVER; error_log /var/log/nginx/error.log notice; access_log /var/log/nginx/access.log; root "/var/www"; location ~ \.php(/|$) { include fastcgi_params; # Other app settings fastcgi_index verify.php; fastcgi_split_path_info ^(.+\.php)(/.*)$; fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; fastcgi_param DOCUMENT_ROOT $realpath_root; fastcgi_pass 127.0.0.1:9074; } location /wsapi/2.0/verify { include fastcgi_params; # Set the script path to the correct file set $path $request_uri; if ($request_uri ~ ^/wsapi/2.0/verify(.*)$ ) { set $path /verify.php$1; } # Configure fastcgi vars fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass 127.0.0.1:9074; fastcgi_index verify.php; fastcgi_param SCRIPT_FILENAME $document_root/wsapi/2.0/verify.php; } }
Be sure to set fastcgi_pass according to your environment, it might be a Unix socket instead of an IP and port like mine. Our fastcgi_params file is more or less the same as the one in the Nginx manual:
Note, it is very important that the Nginx $resource_uri variable isn't altered and that ykval is served on the path http://MYSERVER/wsapi/2.0/verify, because the code uses this to check which version of the API it should be applying. You can see the code for that here, which shows why it matters:
And that's all! Nothing particularly complicated, but hopefully a time-saver for someone tackling the same challenge.
If you're interested in finding out more about free, open-source 2FA services or need support configuring tools such as YubiKeys, SimpleSAMLphp or LinOTP2 contact us.