Nginx + tinyauth: A Lightweight Solution for Application Authentication
tinyauth is a simple, lightweight authentication middleware designed to protect your web applications with a basic login screen. The project leverages Nginx and Go to act as a reverse proxy, sitting in front of your applications. Its main purpose is to handle the authentication layer, allowing your main application to focus on its core business logic.
This is particularly useful in scenarios like
Protecting internal dashboards or admin panels
You can place tinyauth in front of a dashboard that doesn't have its own authentication, like a Grafana or Kibana instance.
Securing development or staging environments
Quickly add a login screen to your pre-production sites without changing the application's code.
Simple, single-user access
It's perfect for situations where you just need a single username and password to grant access to a small team or yourself.
The key benefit here is separation of concerns. By outsourcing authentication to tinyauth, your application becomes simpler and more secure, as it no longer needs to handle login forms, password hashing, or session management.
The implementation involves two main parts
configuring tinyauth itself and then configuring Nginx to use it.
First, you need to set up the tinyauth service. The easiest way is to use a configuration file, typically named config.yaml. Here, you'll define the port it listens on and the credentials for the login screen.
Here’s a basic config.yaml example
listen: ":8081"
user: "admin"
pass: "securepassword"
listen
This is the address tinyauth will listen on. You'll point Nginx to this address.
user
The username for the login screen.
pass
The password for the login screen. You should use a strong, unique password.
Next, you need to tell Nginx to act as a reverse proxy. When a user tries to access your application, Nginx will first forward the request to tinyauth. If tinyauth authenticates the user, it will then pass the request back to Nginx, which will send it to your application. If authentication fails, tinyauth will handle the login screen.
Here is a sample Nginx configuration snippet. You would place this inside your server block.
location / {
# Forward the request to the tinyauth service
auth_request /auth;
error_page 401 = @login;
# If authenticated, pass the request to your application
proxy_pass http://your_application_service;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
location = /auth {
# This location handles the authentication check
internal;
proxy_pass http://127.0.0.1:8081; # This should be the tinyauth service address
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
}
location @login {
# This location redirects to the tinyauth login page
return 302 http://127.0.0.1:8081;
}
auth_request /auth;
This is the key directive. It tells Nginx to make a subrequest to the /auth location. Nginx will only proceed with the main request if the subrequest returns a 200 OK status code.
proxy_pass http://127.0.0.1:8081;
This forwards the authentication subrequest to the tinyauth service running on port 8081.
error_page 401 = @login;
If tinyauth returns a 401 Unauthorized status code, Nginx redirects the user to the @login location.
return 302 http://127.0.0.1:8081;
This location handles the redirect to the tinyauth login page, which will serve the login form.
Let's imagine you have a simple web application running on http://localhost:3000. We want to protect it using tinyauth.
First, let's create the config.yaml for our tinyauth service.
config.yaml
listen: ":8081"
user: "dev-user"
pass: "supersecretpass"
Next, you'd run the tinyauth application. If you have the Go code, you would compile and run it. You can also run it in a Docker container.
go run main.go --config config.yaml
Now, tinyauth is running and listening for requests on http://localhost:8081.
Now, let's configure our Nginx server block to use tinyauth to protect our application.
nginx.conf
server {
listen 80;
server_name my-protected-app.com;
# This is the main application that we are protecting
upstream my_app_backend {
server localhost:3000;
}
location / {
auth_request /auth;
error_page 401 = @login;
proxy_pass http://my_app_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# This location is for the authentication check
location = /auth {
internal;
proxy_pass http://localhost:8081; # tinyauth service
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
}
# This location handles the redirect to the login page
location @login {
return 302 http://localhost:8081;
}
}
With this setup, if a user tries to access http://my-protected-app.com, Nginx will first check with tinyauth on port 8081. If the user isn't logged in, they will be redirected to the login page served by tinyauth. After a successful login, tinyauth will return a 200 OK, and Nginx will then proxy the request to your application running on port 3000.