CallMeTechie
DE Login
Home Products Blog About Contact

Authentication

v1.x · Updated 1 month ago

What does it do?

Authentication controls who may access a route. GateControl offers three tiers:

No authentication:

Client  →  Caddy  →  Backend  ✓  (anyone has access)

Basic Auth:

Client  →  Caddy  →  "Username/password?" (browser dialog)  →  Backend  ✓

Route Auth:

Client  →  Caddy  →  Login page (Email + password + 2FA)  →  Session cookie  →  Backend  ✓

No authentication

The route is publicly accessible. Anyone with the URL can access it.

When useful:

  • Public websites and APIs
  • In combination with Peer ACL (VPN-only access, no login required)
  • Services that bring their own authentication (e.g. Nextcloud, Gitea)

Caution: Without auth and without ACL, the route is visible to the entire internet. The backend should then have its own login function.

Basic Auth

HTTP Basic Authentication — the browser shows a native login dialog.

How it works internally

Caddy inserts an authentication handler before all other handlers:

{
  "handler": "authentication",
  "providers": {
    "http_basic": {
      "accounts": [{
        "username": "admin",
        "password": "$2a$14$..."
      }]
    }
  }
}

Flow:

  1. Client opens the route
  2. Caddy responds with 401 Unauthorized and WWW-Authenticate: Basic
  3. Browser shows native login dialog
  4. Client sends Authorization: Basic <base64(user:pass)> header
  5. Caddy checks the username against the stored value and the password against the bcrypt hash
  6. On success: the request is forwarded to the backend
  7. The Authorization header is sent with every request (no session management)

Properties

Property Value
Password storage bcrypt hash (admin login: argon2id)
Session management None — credentials on every request
Logout Not possible (browser caches credentials)
2FA Not possible
Browser compatibility All browsers
API compatibility All HTTP clients (curl -u user:pass)
Accounts per route 1

Use cases

Protecting developer tools: Route phpmyadmin.example.com → phpMyAdmin. Basic Auth with a strong password. Simple, no setup, works with any browser and tool.

Securing API access: curl -u admin:secret https://api.example.com/data — Basic Auth is ideal for APIs since no cookie/session management is required.

Route Auth

Custom login page with multiple authentication methods and optional two-factor authentication.

How it works internally

Route Auth uses Caddy's forward_auth mechanism:

  1. Caddy forwards /route-auth/* paths directly to GateControl (port 3000) (login page, assets)
  2. For all other paths: forward-auth subrequest to GET /route-auth/verify
  3. GateControl checks the session cookie
  4. On a valid session (2xx): the request is forwarded to the backend
  5. On an invalid session: 302 Redirect to the login page
{
  "handler": "reverse_proxy",
  "upstreams": [{ "dial": "127.0.0.1:3000" }],
  "rewrite": { "method": "GET", "uri": "/route-auth/verify" },
  "headers": {
    "request": {
      "set": {
        "X-Route-Domain": ["app.example.com"],
        "X-Forwarded-Method": ["{http.request.method}"],
        "X-Forwarded-Uri": ["{http.request.uri}"]
      }
    }
  }
}

Three login methods

Email & Password

Classic login with email address and password.

  • Password is stored as a bcrypt hash
  • No external service required
  • Simplest method

Email & Code

A 6-digit one-time code is sent by email.

  • Requires configured SMTP (Settings → Email)
  • Code is time-limited
  • No password required — only access to the email
  • Ideal for users who don't want to remember passwords

TOTP (Time-based One-Time Password)

Authenticator app generates 6-digit codes.

  • Compatible with: Google Authenticator, Microsoft Authenticator, Authy, 1Password, etc.
  • No password, no email access required
  • Requires one-time QR-code setup

Two-factor authentication (2FA)

Route Auth supports optional 2FA. Email & Password is used as the first factor combined with:

  • Email Code as the second factor: after the password, a 6-digit code is sent by email
  • TOTP as the second factor: after the password, a TOTP code from the authenticator app is required

Session management

Property Value
Session duration Configurable: 1h, 12h, 24h, 7d, 30d
Session storage Cookie
Logout Yes (destroys the session)
Multiple devices Yes (separate sessions)

Custom branding

Each route can have its own login page:

  • Logo (upload or URL)
  • Title and description text
  • Colors (primary, background)
  • Background image

TOTP setup (step by step)

  1. Create/edit route → Auth Type: Route Auth
  2. Select Method: TOTP (or as second factor for 2FA)
  3. Save the route
  4. Open the route again in the edit modal
  5. A QR code appears in the TOTP section
  6. Scan the QR code with an authenticator app
  7. Enter the 6-digit confirmation code
  8. TOTP is active

Important: The QR code is only displayed once the route has been saved. When creating a new route, the edit modal must be reopened after the first save.

Comparison table

Property No Auth Basic Auth Route Auth
Security level None Medium High
Login UI None Browser dialog Custom login page
Password storage bcrypt bcrypt
2FA possible No No Yes
Session/Logout No/No Yes/Yes
API-compatible Yes Yes (curl -u) No (cookie-based)
Custom branding No Yes
Accounts per route 1 1
Email required No No Yes (for email methods)
SMTP required No No Only for Email Code
Works with L4 No No

Combination with other features

Combination Effect
Auth + ACL First the VPN-IP check, then login
Auth + Force HTTPS Mandatory with Basic Auth (otherwise credentials in plaintext!)
Auth + Rate Limiting Basic Auth: rate limit before auth. Route Auth: rate limit after auth
Auth + IP filter Route Auth + IP filter: IP is checked in forward-auth. Basic Auth + IP filter: cannot be combined

Important notes

  • Basic Auth and Route Auth are mutually exclusive. A route can only use one of the two methods.
  • Basic Auth without HTTPS is insecure. The password is base64-encoded (not encrypted) in the Authorization header. Force HTTPS must be active.
  • Route Auth is not API-compatible. It is based on session cookies and a login page. For API access use Basic Auth.
  • Authentication is only available for HTTP routes, not for L4 (TCP/UDP).
  • With Route Auth: the forward-auth subrequest runs on every request (session cookie check). This adds minimal latency (~1-5ms).
  • Basic Auth has no built-in brute-force protection. Combine it with Rate Limiting for additional security.
  • TOTP secrets are stored in the database. A database backup also secures the TOTP configuration.

Admin login

Independent of Route Auth, GateControl protects its own Admin UI (port 3000 behind Caddy) via POST /login:

  • The password hash in users.password_hash is argon2id. Older bcrypt hashes are migrated on the next login.
  • Sessions are server-side (express-session); on a successful login the session ID is regenerated (session fixation protection).
  • After too many failed attempts a lockout kicks in: 5 attempts / 15 minutes per username (configurable under Settings → Security, security.lockout.max_attempts / security.lockout.duration).
  • Lockouts are stored in login_attempts; after the lockout expires the account is automatically unlocked. An admin can manually unlock a locked account (lockout.unlockAccount).

Details on response codes and payloads are in the canonical API.md (section Auth).

API tokens and machine fingerprint

API tokens (gc_…) are scoped (see API.mdToken Scopes). Relevant properties:

  • Stored as SHA-256 hash; the plaintext token is only shown once at creation.
  • scopes is required (e.g. read-only, full-access, routes, client, gateway).
  • Optional: expires_at, binding to user_id or peer_id, and machine fingerprint binding: on first use the SHA-256 fingerprint of the calling machine is stored; later calls must send the same fingerprint or are rejected. Reset only via the Admin UI.
  • Route Auth uses the same lockout table (type = 'route_auth').

Cookie Settings

We use cookies to improve your experience. Essential cookies are always active.

Privacy Policy
ESC
↑↓ navigate open esc close