basicauthtotp

package module
v0.8.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 6, 2025 License: Apache-2.0 Imports: 23 Imported by: 0

README

BasicAuthTOTP Caddy Plugin

[!Important] This plugin has a successor: caddy-postauth-2fa

The new caddy-postauth-2fa plugin is recommended for all new deployments and offers significant improvements and additional features over BasicAuthTOTP, including:

  • Per-user secrets can be stored as plaintext (totp_secret) or encrypted (totp_secret_encrypted).
  • IP binding is now optional and can be disabled.
  • The secrets file format is now a JSON object mapping usernames to secret objects, not an array.

The Caddy Post-Auth 2FA plugin for Caddy adds a second authentication factor (TOTP-based 2FA) after any primary authentication handler (such as basic_auth or jwtauth).

Please see the caddy-postauth-2fa documentation for details.

[!Important] With version v0.4.0 (released in February 2025) of this plugin, the server-side session management and the logout functionality were dropped in favor of JWT-based (JSON Web Token-based) session management. The configuration options logout_session_path and logout_redirect_url must be removed from your Caddy configuration. With version v0.5.0 a base64-encoded sign_key of at least 32 bytes is now required to securely sign the tokens and ensure their integrity. With version v0.8.0 you can now specify the TOTP code length globally via the totp_code_length option or per user in the secrets JSON file (see below).

The BasicAuthTOTP plugin for Caddy enhances Caddy's basic authentication with Time-based One-Time Password (TOTP) two-factor authentication (2FA). This module supplements basic_auth and does not replace it; therefore, basic_auth must be configured and active for this plugin to function correctly. It's adding an extra layer of security for web applications and services hosted with Caddy.

[!TIP] For more extensive authentication, authorization, and accounting requirements, consider using AuthCrunch / caddy-security. AuthCrunch provides a comprehensive AAA solution, supporting Form-Based, Basic, Local, LDAP, OpenID Connect, OAuth 2.0 (e.g., GitHub, Google, Facebook), SAML Authentication, and 2FA/MFA (including app-based authenticators and Yubico). It also offers authorization with JWT/PASETO tokens, making it ideal for more complex or larger-scale environments.

BasicAuthTOTP is best suited for smaller, perhaps internal user groups who require added security for specific endpoints but do not need a full-featured authentication, and authorization solution. It requires users to authenticate with both a valid TOTP code and basic auth credentials, making it suitable for lightweight, targeted protection of sensitive resources.

Features

This plugin introduces additional authentication steps within Caddy configurations:

  • TOTP Authentication: Requires users to enter a valid TOTP code in addition to basic auth credentials.
  • Configurable TOTP Code Length: You can set the required TOTP code length globally (e.g. 6 or 8 digits) or override it per user in the secrets file.
  • JWT-based session management with configurable inactivity-based expiration and IP-based session validation to prevent session hijacking.

Instead of server-side session management, this module uses JWTs stored in cookies to manage sessions. This approach simplifies session handling and no sessions are lost when Caddy is reloaded or restarted. However, this approach is less secure than server-side session management, as JWTs are not invalidated or blacklisted. To mitigate risks, the module uses IP binding to ensure that the JWT is only valid for the client IP address that created it. If the client IP changes, the user must re-authenticate.

Authentication Flow

When accessing a protected route, users will first be prompted to enter their Basic Authentication credentials. After successfully completing Basic Authentication, they will see a 2FA prompt to enter their TOTP code, as shown below:

TOTP 2FA Input Screen

[!NOTE] Content Security Policy (CSP): The 2FA form applies a dedicated CSP header with a unique nonce for inline styles and sets form-action to 'self', which overwrites any other CSP configuration that might otherwise restrict inline styles or form submissions. This ensures the form functions correctly and securely.

Disclaimer

Experimental Module: This plugin is currently in an experimental phase and is primarily developed to meet specific, personal requirements. While contributions and suggestions are welcome, please be aware that this module may lack certain features or robustness expected in production environments.

[!Important] Due to its experimental nature, this plugin is not yet intended for use in production or mission-critical systems. Use it at your own risk. The author assumes no responsibility for potential security risks, stability issues, or data loss that may arise from its use in such environments.

Building

To build Caddy with this module, use xcaddy:

$ xcaddy build --with github.com/steffenbusch/caddy-basicauth-totp

Caddyfile Config

By default, the basic_auth_totp directive is ordered after basic_auth in the Caddyfile. This enables seamless integration with Caddy's existing basic authentication system. Below is an example configuration, followed by detailed explanations of each configuration option.

:8080 {
    handle /top-secret/* {
        basic_auth {
            user hashed_password
        }

        basic_auth_totp {
            session_inactivity_timeout 2h
            secrets_file_path /path/to/2fa-secrets.json
            cookie_name batotp_sess
            cookie_path /top-secret
            form_template /path/to/custom-2fa-form-template.html
            sign_key AWhvKpXr0CYdbW+Da+bBDTBX5nyqYCTKGNWpC0CeWhY=
            totp_code_length 8
        }

        respond "Welcome, you have passed basic and TOTP authentication!"
    }
}
Configuration Options
  • session_inactivity_timeout: Sets the maximum period of inactivity allowed before a session expires, requiring re-authentication. Default is 60m.

    • Usage Tip: A shorter inactivity timeout improves security by prompting for re-authentication if users are inactive, while a longer timeout enhances convenience for active users.
  • secrets_file_path: Specifies the path to a JSON file containing TOTP secrets for each user, required for validating TOTP codes.

  • cookie_name: Defines a custom name for the session cookie that stores the 2FA token. Default is batotp_sess.

  • cookie_path: Sets the path scope of the session cookie, defining where it will be sent on the server. Default is /.

  • form_template: Path to the HTML template file for the 2FA authentication page. If not specified, an embedded default template default-2fa-form.html will be used.

  • sign_key: The base64-encoded secret key used to sign the JWTs. This key will be decoded to bytes for JWT signing.

  • totp_code_length: (Optional) The TOTP code length that you have chosen when setting up your TOTP secrets (e.g. 6 or 8). Default is 6. Can be overridden per user in the secrets file (see below).

Example JSON structure w/ per-user TOTP Code Length

You can override the global TOTP code length for individual users by specifying a code_length property in the secrets JSON file:

{
  "users": [
    {
      "username": "user1",
      "secret": "F2MV5KORBGRG5GTEUKHKF3YJYXJPC45PS7YHVV4GFIIWEYQE",
      "code_length": 8
    },
    {
      "username": "user2",
      "secret": "BABC3SA2W523ZMLXH73IN46FBWJPEKLLPPL53AO44LWFIS5T"
      // code_length omitted, will use global/default
    }
  ]
}

Each user should have a unique TOTP secret, formatted in Base32 without padding (=). This key will later be used by a TOTP-compatible app (such as Google Authenticator or Authy) to generate time-based one-time passwords. If code_length is set for a user, it will override the global totp_code_length for that user only. Note: The code length must match the length that was chosen when the TOTP secret was generated for the user. The plugin does not enforce a specific code length, but validates the code according to the configuration and/or per-user setting.

Template Context

The available information in the template context includes:

  • Username: The username of the user (HTML escaped).
  • Errormessage: Any error message to be displayed.
  • Nonce: A nonce used for inline styles.
  • TOTPCodeLength: The required code length for the current user (used for input validation in the form).
Session Management Explanation

The session is managed with an inactivity-based expiration. Once a user authenticates with a TOTP code, a session is created with an inactivity timeout (session_inactivity_timeout). Each valid request within this timeout period extends the session expiration by the specified inactivity duration, but only if less than 50% of the timeout remains. This reduces the frequency of session updates, optimizing performance by minimizing lock contention.

Generating a TOTP-compatible Secret

To create a secure, random key in the correct format, you can use the following command:

openssl rand 30 | base32 | tr --delete '='

Explanation of the command:

  • openssl rand 30: Generates 30 random bytes.
  • | base32: Converts the random bytes to Base32 format.
  • | tr --delete '=': Removes any = padding characters, which are not needed in TOTP format.

This Base32 key can then be stored in secrets_file_path and will be used by the TOTP library to generate one-time passwords.

Setting Up the Secret in a 2FA App

If you want to set up the secret directly in a 2FA app, you can also generate a QR code that includes the Base32 secret. A useful tool for this is the 2FA QR Code Generator, where you can input the Base32 key to create a scannable QR code for the app.

Security Considerations

  • TOTP Secret Management: Ensure that the secrets_file_path is secure and not accessible via the web server. This file contains sensitive user secrets and should be protected from unauthorized access.

  • Inactivity Timeout: Choose an appropriate session_inactivity_timeout that balances usability and security. Shorter timeouts enhance security but may inconvenience users by requiring frequent re-authentication.

  • Session Renewal Optimization: To optimize performance, sessions are only extended when less than 50% of the inactivity timeout remains. This approach reduces the frequency of session updates and improves handling of concurrent access.

  • IP Binding: Sessions are automatically bound to the client’s IP address, providing an additional layer of security against session hijacking. This setting cannot be disabled. By default, the session is tied to the client’s IP address, meaning that if a user’s IP address changes (e.g., due to network switching), they will be required to re-authenticate with a TOTP code. This feature enhances security by ensuring that each session is restricted to a specific client IP.

  • Cookie Security: The session cookie is set with HttpOnly, Secure, and SameSite=Lax attributes. These settings help prevent attacks, but SameSite is not currently configurable.

  • Brute-Force Attack Prevention and Logging: To help prevent brute-force attempts on TOTP codes, the plugin logs each invalid TOTP attempt with the username and client IP, such as:

    2024/11/01 08:08:36.099 WARN http.handlers.basicauthtotp Invalid TOTP attempt {"username": "user1", "client_ip": "4.8.15.16"}

    This log entry provides crucial information for security monitoring and can be used with fail2ban or similar tools to block repeated failed attempts.

  • TOTP Validation Settings: The plugin uses TOTP validation settings compatible with Google Authenticator, including:

    • 6-digit codes by default, or 8-digit codes if configured globally or per user,
    • A 30-second code validity period,
    • A skew allowance of one period (±30 seconds) for clock drift,
    • SHA-1 as the HMAC algorithm.

    These settings are applied by default in the Validate function to maintain compatibility with most authenticator apps while ensuring secure TOTP verification.

License

This project is licensed under the Apache License, Version 2.0. See the LICENSE file for details.

Acknowledgements

  • Caddy for providing a powerful and extensible web server.
  • pquerna/otp for TOTP functionality, used under the Apache License 2.0.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type BasicAuthTOTP

type BasicAuthTOTP struct {
	// SessionInactivityTimeout defines the maximum allowed period of inactivity before
	// a 2FA session expires and requires re-authentication. Default is 60 minutes.
	SessionInactivityTimeout time.Duration `json:"session_inactivity_timeout,omitempty"`

	// SecretsFilePath specifies the path to the JSON file containing TOTP secrets for each user.
	// This file should contain usernames and their corresponding TOTP secrets.
	SecretsFilePath string `json:"secrets_file_path,omitempty"`

	// CookieName defines the name of the cookie used to store the session token for 2FA.
	// Default is `batotp_sess`.
	CookieName string `json:"cookie_name,omitempty"`

	// CookiePath specifies the path scope of the session cookie.
	// This restricts where the cookie is sent on the server. Default is `/`.
	CookiePath string `json:"cookie_path,omitempty"`

	// Filename of the custom template to use instead of the embedded default template.
	FormTemplateFile string `json:"form_template,omitempty"`

	// TOTPCodeLength defines the expected length of the TOTP code (default: 6).
	TOTPCodeLength int `json:"totp_code_length,omitempty"`

	// SignKey is the base64 encoded secret key used to sign the JWTs.
	SignKey string `json:"sign_key,omitempty"`
	// contains filtered or unexported fields
}

BasicAuthTOTP is a Caddy module that enhances Caddy's `basic_auth` directive by adding Time-based One-Time Password (TOTP) two-factor authentication (2FA). This module supplements `basic_auth` and does not replace it; therefore, `basic_auth` must be configured and active for BasicAuthTOTP to function correctly. Together, these two directives provide an additional security layer for sensitive routes by requiring both standard credentials and a valid TOTP code from a compatible authenticator app.

This module is suitable for scenarios where extra security is necessary but may not be intended for production environments without additional testing, as it is in an experimental phase.

Key features include:

  • JWT(JSON Web Token)-session-based TOTP authentication with configurable inactivity timeouts.
  • IP binding for session validation, requiring re-authentication if the user's IP changes.
  • Customizable session cookie options, including name and path scope.

Instead of server-side session management, this module uses JWTs stored in cookies to manage sessions. This approach simplifies session handling and no sessions are lost when Caddy is reloaded or restarted. However, this approach is less secure than server-side session management, as JWTs are not invalidated or blacklisted and no logout is provided. To mitigate risks, the module uses IP binding to ensure that the JWT is only valid for the client IP address that created it. If the client IP changes, the JWT cookie is removed and the user must re-authenticate.

Configuration options in BasicAuthTOTP provide flexibility in securing routes, and managing session inactivity timeout. Secrets are loaded from a specified JSON file that maps usernames to TOTP secrets.

Example use case: BasicAuthTOTP is ideal for protecting sensitive or restricted resources by requiring an additional TOTP code, making it a good fit for applications where higher assurance of identity is required.

func (BasicAuthTOTP) CaddyModule

func (BasicAuthTOTP) CaddyModule() caddy.ModuleInfo

CaddyModule returns the Caddy module information.

func (*BasicAuthTOTP) Provision

func (m *BasicAuthTOTP) Provision(ctx caddy.Context) error

Provision sets up the module, initializes the logger, and applies default values.

func (*BasicAuthTOTP) ServeHTTP

func (m *BasicAuthTOTP) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error

ServeHTTP handles incoming HTTP requests and checks for IP changes.

func (*BasicAuthTOTP) UnmarshalCaddyfile

func (m *BasicAuthTOTP) UnmarshalCaddyfile(d *caddyfile.Dispenser) error

UnmarshalCaddyfile parses the configuration from the Caddyfile.

func (*BasicAuthTOTP) Validate added in v0.2.1

func (m *BasicAuthTOTP) Validate() error

Validate ensures the configuration is correct.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL