Skip to main content

NGINX + WebAuthn for your small scale web applications

What is this for?

If you run some small services on a public-facing server that you would like to protect (i.e. Jupyter of VS code-server) and have a Yubikey or similar, you can use this repository to add secure, public-key authentication to them without modifying the original service itself.

How to set up?

Run nginx -V and check it is compiled with auth_request_module otherwise recompile it with --with-http_auth_request_module configuration parameter. Then set up NGINX to proxy your service, note that you will also need SSL because WebAuthn only works over HTTPS.

server {
    server_name myserver.bennewhouse.com; # managed by Certbot

    # Redirect everything that begins with /auth to the authorization server
    location /nginx_fido_auth {
        proxy_pass http://127.0.0.1:8000;
    }

    # If the authorization server returns 401 Unauthorized, redirect to /atuh/login
    error_page 401 = @error401;
    location @error401 {
        return 302 /nginx_fido_auth/login$request_uri;
    }

    root /var/www/html;
    index index.html;
    location / {
        auth_request /nginx_fido_auth/check; # Ping /auth/check for every request, and if it returns 200 OK grant access
        # The next two lines are ptional config for authentication header needed by your application.
        # Replace X-SSL-CERT with any header your application expects to carry the user ID.
        auth_request_set $fido $upstream_http_fido_user;
        passenger_set_header 'X-SSL-CERT' $fido;

        # Here is where you would put other proxy_pass info to forward to Jupyter, etc. In this example I'm just serving raw HTML
    }

    # Override the application logout url with the fido auth logout url. Replace /users/logout with url where your application logout button points to.
    location /users/logout {
        return 302 /nginx_fido_auth/logout
    }

    listen [::]:443 ssl ; # managed by Certbot
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/myserver.bennewhouse.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/myserver.bennewhouse.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}

Reload NGINX with the aforementioned configuration. Next install the nginxwebauthn Python package as root -- dependencies needs to be installed globally to be able to add user credentials later. Other option is to change privileges to /opt/nginxwebauthn to be able to write there by regular user which may be a security flaw. Install script takes two arguments -- user and group for the script to be started as.

sudo su
pip3 install nginxwebauthn-jv
nginxwebauthn-ubuntu-install.py user group

If nginxwebauthn-ubuntu-install.py fails for any reason you can try to replicate steps in cat `which nginxwebauthn-install.py` . Basically it creates a directory structure in /opt/nginxwebauthn and configures systemd service to run the nginxwebauthn.py script as a daemon.

How to use?

Browse to your site with appended /nginx_fido_auth/register in a browser that supports WebAuthn. Insert your security key when requested, and the page will tell you to run a command that looks like:

sudo python3 nginx-webauthn.py save-client myserver.bennewhouse.com *big long base64 string* *big long base64 string* auth_name

Replace auth_name with something unique that will help you identify the credential and run that on the server. You only need to do this once per key. The credentials are stored in /opt/nginxwebauthn/credentials/auth_name. If you set up your NGINX to expect the HTTP header to distinguish the authenticated user put the header contents to /opt/nginxwebauthn/headers/auth_name. The header file is paired with credential file by file name. \n characters in headers are replaced with \t and sent back to the NGINX server.

That's it! Navigating back to your website will now authenticate you using the key you just saved.

How to build pip package

sudo python3 -m pip install --upgrade pip setuptools wheel
sudo -H pip3 install keyring
git clone https://github.com/jan-vitek/nginxwebauthn
cd nginxwebauthn
python3 setup.py bdist_wheel

Then you can distribute the .whl file from dist to your server and install it with pip3 install nginxwebauthn_jv-*.whl. Or if you are registered to PyPI.org you can upload the package this way:

cat << EOF > ~/.pypirc
[distutils] 
index-servers=pypi
[pypi] 
repository = https://upload.pypi.org/legacy/ 
username = your_pypi_username
EOF

python -m twine upload dist/*

Limitations

  • This uses the built-in python3 server, which isn't designed for high-volume. You'd want to port this to a uwsgi setup if you wanted to productionize it.

Version 0.2

New features

  • concurrent registrations
  • concurrent authentications
  • self registration
  • invitations

Configuration

#/etc/nginxwebauthn.conf

[Global]
# after succesful token registration a form is displayed where user can fill in the token name and their personal information
# the token is then stored in /opt/nginxwebauthn/registrations
AllowPreregistration = false

# if FromEmail and AdminEmail are configured the user personal information is sent to the AdminEmail
#FromEmail = root@localhost
#AdminEmail = root@localhost
# SMTP server defaults to localhost
#SMTPServer = localhost

Self registrations

If enabled users can identify themselves during the registration process. The token data are then stored in /opt/nginxwebauthn/registrations and user information is sent to the admin email. The admin can later finish the registration process by moving the file to /opt/nginxwebauthn/credentials

Invitations

The registration form can preload data for the inputs from the url params. The selected inputs can be hidden using the hiddenElements param. To later pair the registration data with your user there is a hidden field externalId.

The credential file is stored in /opt/nginxwebauthn/registrations with externalId as a prefix.

Fields:

  • username
  • tokenName
  • name
  • phone
  • email
  • externalId

Example URL: https://example.com/nginx_fido_auth/register?email=john.doe@example.com&externalId=1234uniqueToken&name=John Doe&phone=555123456&username=john.doe&hiddenElements=["username", "name", "phone", "email"]

FAQ

Why do I need to run the save-client command?

This seemed easier than setting up a potentially insecure password so that you could authorize your key. Instead it asserts that you have shell access by requiring that you run a command.

Release files for nginxwebauthn-jv 0.2.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distribution (wheel)

Table of built distributions (wheels) for nginxwebauthn-jv 0.2.3
File Interpreter ABI Platform
nginxwebauthn_jv-0.2.3-py3-none-any.whl Python 3 none any Details

Release files / nginxwebauthn_jv-0.2.3-py3-none-any.whl

Download URL nginxwebauthn_jv-0.2.3-py3-none-any.whl
Size 10.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
83fdf1bda6d9f41af59875ce230d78f0ee9647067f212369e1645f3f06e4710b
BLAKE2b-256 checksum
How to use checksums
4ed293148d111638edd10aba6c66959f13256036c8add6924f4083921365c05b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.8.0 pkginfo/1.8.2 readme-renderer/34.0 requests/2.28.1 requests-toolbelt/0.9.1 urllib3/1.26.9 tqdm/4.63.0 importlib-metadata/4.11.3 keyring/18.0.1 rfc3986/2.0.0 colorama/0.4.4 CPython/3.8.10

Release history Release notifications | RSS feed

This release

0.2.3 This release

1 release file

0.2.2

1 release file

0.2.1

1 release file

0.2.0

1 release file

0.1.4

1 release file

0.1.3

1 release file

0.1.2

1 release file

0.1.1

1 release file

0.1

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page