Files
docudjeex/content/en/3.serveex/3.security/4.tinyauth.md
T

9.1 KiB

title, description
title description
TinyAuth Install TinyAuth, a lightweight forward-auth proxy, and pair it with Pocket ID to add SSO login in front of your self-hosted apps.

:ellipsis{left=0px width=40rem top=10rem blur=140px zIndex=60}

TinyAuth

::note 🎯 Objectives:

  • Install TinyAuth
  • Log in via Pocket ID (OIDC)
  • Protect an app behind Swag with forward-auth ::

TinyAuth is a small forward-auth proxy: a single login page that Swag can insert in front of any app before letting a request through, similar in spirit to Authentik's reverse-proxy mode, but without the rest of Authentik's identity-provider machinery.

It supports a simple local username/password login out of the box, and can also delegate login to an external OIDC provider. Here we'll use Pocket ID, so anyone visiting a protected app first authenticates with a passkey via Pocket ID, then gets forwarded through.

::note

This guide assumes you've already installed Pocket ID. You can skip the Pocket ID sections below and use TinyAuth with just a local username/password instead. ::

Installation

Folder structure:

root
└── docker
    └── tinyauth
        ├── compose.yaml
        ├── .env
        └── data

Create the data folder:

sudo mkdir -p /docker/tinyauth/data

Generate a password hash for your local account:

sudo docker run -i -t --rm ghcr.io/tinyauthapp/tinyauth:v5 user create --interactive

::note

Enable "Format for Docker" when prompted, so the generated hash is already escaped for use in a .env file. ::

Open Dockge, click compose, name the stack tinyauth, and add the following config:

---
services:
  tinyauth:
    image: ghcr.io/tinyauthapp/tinyauth:v5
    container_name: tinyauth
    restart: unless-stopped
    env_file:

      - .env
    volumes:

      - /docker/tinyauth/data:/data
    ports:

      - 3000:3000

::tip Add the Watchtower label to automate updates:

services:
  tinyauth:
    #...
    labels:

      - com.centurylinklabs.watchtower.enable=true

::

Fill in the .env file:

TINYAUTH_APPURL=https://tinyauth.mydomain.com
TINYAUTH_AUTH_USERS=
Variable Value Example
TINYAUTH_APPURL{lang=properties} The public URL you'll use to reach TinyAuth (see exposure below) https://tinyauth.mydomain.com
TINYAUTH_AUTH_USERS{lang=properties} The hash generated above user:$$2a$$10$$UdLYoJ5lgPsC0RKq...

Deploy the stack. The local interface is available at http://yourserverip:3000.

Exposing TinyAuth with Swag

TinyAuth needs its own subdomain: it's the page users land on before being forwarded to the app they actually want.

::note

We assume you have the subdomain tinyauth.mydomain.com with a CNAME pointing to mydomain.com in your DNS zone. And of course, unless you use Cloudflare Zero Trust, your box's port 443 must be forwarded to your server's port 443 in NAT rules. ::

Go to Dockge and edit SWAG's compose file by adding TinyAuth's network:

services:
  swag:
     container_name: # ...
      # ... 
     networks:               # Attach container to custom network 
      # ...           

      - tinyauth             # Name of the declared network

networks:                    # Define the custom network
  # ...
  tinyauth:                  # Declared network name
    name: tinyauth_default   # Actual external network name
    external: true           # Marks it as externally defined

Redeploy the stack and wait for SWAG to be fully operational.

::note

Here we assume the TinyAuth network name is tinyauth_default. You can check the connection by visiting SWAG's dashboard at http://yourserverip:81. ::

In the Swag folders, create the file tinyauth.subdomain.conf:

::tip{icon=""} Tip: Use File Browser to navigate and edit files instead of using terminal commands. ::

sudo nano /docker/swag/config/nginx/proxy-confs/tinyauth.subdomain.conf

Paste the following configuration:

## Version 2023/12/19

server {
    listen 443 ssl;
    listen [::]:443 ssl;

    server_name tinyauth.*;

    include /config/nginx/ssl.conf;

    client_max_body_size 0;

    location / {
        include /config/nginx/proxy.conf;
        include /config/nginx/resolver.conf;
        set $upstream_app tinyauth;
        set $upstream_port 3000;
        set $upstream_proto http;
        proxy_pass $upstream_proto://$upstream_app:$upstream_port;
    }
}

Press :kbd{value="Ctrl+O"}, then :kbd{value="Enter"} to save, and :kbd{value="Ctrl+X"} to exit.

Wait a few minutes, then open https://tinyauth.mydomain.com in your browser and log in with the username/password you created above.

::caution

If it fails: check your firewall rules. ::

Connecting TinyAuth to Pocket ID

First, register TinyAuth as an OIDC client in Pocket ID, using this callback URL:

https://tinyauth.mydomain.com/api/oauth/callback/pocketid

Copy the Client ID and Client Secret Pocket ID gives you, then edit TinyAuth's .env file:

sudo nano /docker/tinyauth/.env

Add the following:

TINYAUTH_OAUTH_PROVIDERS_POCKETID_NAME=Pocket ID
TINYAUTH_OAUTH_PROVIDERS_POCKETID_CLIENTID=
TINYAUTH_OAUTH_PROVIDERS_POCKETID_CLIENTSECRET=
TINYAUTH_OAUTH_PROVIDERS_POCKETID_AUTHURL=https://id.mydomain.com/authorize
TINYAUTH_OAUTH_PROVIDERS_POCKETID_TOKENURL=https://id.mydomain.com/api/oidc/token
TINYAUTH_OAUTH_PROVIDERS_POCKETID_USERINFOURL=https://id.mydomain.com/api/oidc/userinfo
TINYAUTH_OAUTH_PROVIDERS_POCKETID_REDIRECTURL=https://tinyauth.mydomain.com/api/oauth/callback/pocketid
TINYAUTH_OAUTH_PROVIDERS_POCKETID_SCOPES=openid email profile
Variable Value
CLIENTID{lang=properties} The client ID copied from Pocket ID
CLIENTSECRET{lang=properties} The client secret copied from Pocket ID
AUTHURL / TOKENURL / USERINFOURL{lang=properties} Pocket ID's public URL, with the paths shown above

Press :kbd{value="Ctrl+O"}, then :kbd{value="Enter"} to save, and :kbd{value="Ctrl+X"} to exit.

Redeploy the TinyAuth stack. On your next visit to https://tinyauth.mydomain.com, you'll see a "Login with Pocket ID" option alongside the local login form.

::tip To skip straight to Pocket ID and hide the local login form, add TINYAUTH_OAUTH_AUTOREDIRECT=pocketid to the same .env file. ::

Protecting an app via reverse proxy

Unlike Authentik, Swag doesn't ship a ready-made include file for TinyAuth, so we'll add the forward-auth check directly to the app's own *.subdomain.conf. We'll use Dockge as an example.

Open the file:

sudo nano /docker/swag/config/nginx/proxy-confs/dockge.subdomain.conf

Add an internal /tinyauth location, and reference it from the app's location / block with auth_request:

server {
    listen 443 ssl;
    listen [::]:443 ssl;

    server_name dockge.*;

    include /config/nginx/ssl.conf;

    client_max_body_size 0;

    location /tinyauth {
        internal;
        proxy_pass http://tinyauth:3000/api/auth/nginx;
        proxy_pass_request_body off;
        proxy_set_header Content-Length "";
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Host $http_host;
        proxy_set_header X-Forwarded-Uri $request_uri;
    }

    location @tinyauth_login {
        return 302 https://tinyauth.mydomain.com/login?redirect_uri=$scheme://$http_host$request_uri;
    }

    location / {
        auth_request /tinyauth;
        error_page 401 = @tinyauth_login;

        include /config/nginx/proxy.conf;
        include /config/nginx/resolver.conf;
        set $upstream_app dockge;
        set $upstream_port 5001;
        set $upstream_proto http;
        proxy_pass $upstream_proto://$upstream_app:$upstream_port;
    }
}

::note

The location /tinyauth block must be able to reach the TinyAuth container by its Docker name (tinyauth here). Add TinyAuth's network to this stack's compose file the same way you did for Swag if it isn't already attached. ::

Press :kbd{value="Ctrl+O"}, then :kbd{value="Enter"} to save, and :kbd{value="Ctrl+X"} to exit.

That's it! Visiting https://dockge.mydomain.com now redirects to TinyAuth first. Repeat this location /tinyauth / auth_request pattern in any other app's *.subdomain.conf to protect it the same way.

::note

Repeat this process for each app you want to protect (unless it has native OIDC support, in which case you can point it directly at Pocket ID instead). ::