Two Factor Authentication

Structr supports the TOTP (Time-Based One-Time Password) flavor of two-factor authentication and supports multiple configuration options to enable two-factor-authentication. They can be configured via structr.conf or the configuration servlet (http://<your-structr>/structr/config).

Note: Because the TOTP algorithm is used, it is important that the clocks of both factors (server and mobile device) are synced to a NTP server so they are as close as possible.

Configuration Options

security.twofactorauthentication.level
  • 0 = off
    Two-Factor Authentication is turned off completely
  • 1 = optional (Default)
    Two-Factor Authentication can be turned on on a per-user basis.
  • 2 = forced
    Every user is forced to use Two-Factor Authentication
security.twofactorauthentication.issuer

The issuer parameter is a string value indicating the provider or service this account is associated with, URL-encoded according to RFC 3986. If the issuer parameter is absent, issuer information may be taken from the issuer prefix of the label. If both issuer parameter and issuer label prefix are present, they should be equal.

Valid values corresponding to the label prefix examples above would be: issuer=Example, issuer=Provider1, and issuer=Big%20Corporation.

Older Google Authenticator implementations ignore the issuer parameter and rely upon the issuer label prefix to disambiguate accounts. Newer implementations will use the issuer parameter for internal disambiguation, it will not be displayed to the user. We recommend using both issuer label prefix and issuer parameter together to safely support both old and new Google Authenticator versions.

security.twofactorauthentication.algorithm

The algorithm may have the values:

  • SHA1 (Default)
  • SHA256
  • SHA512

Warning: Changing this setting after users are already confirmed will effectively lock them out. Set <User>.twoFactorConfirmed to false to show them a new QR code.

security.twofactorauthentication.digits

OPTIONAL: The digits parameter may have the values 6 or 8, and determines how long of a one-time passcode to display to the user. The default is 6.

Warning: Changing this setting after users are already confirmed may lock them out. Set <User>.twoFactorConfirmed to false to show them a new QR code.

security.twofactorauthentication.period

OPTIONAL only if type is totp: The period parameter defines a period that a TOTP code will be valid for, in seconds. The default value is 30.

Warning: Changing this setting after users are already confirmed may lock them out. Set <User>.twoFactorConfirmed to false to show them a new QR code.

security.twofactorauthentication.logintimeout

Defines how long the two-factor login time window in seconds is. After entering the username and password the user has this amount of time to enter a two factor token before he has to re-authenticate via password. Default is 30.

security.twofactorauthentication.loginpage

The application page where the user enters the current two factor token. Until the user has verified his two factor token (by logging in once), the user is shown a QR code after every login attempt. Default is /twofactor

Note: To allow maximum flexibility, this page is part of the web-application and not part of Structr.

security.twofactorauthentication.whitelistedIPs

A comma-separated (,) list of IPs for which two factor authentication is disabled.

User configuration

There are three main properties you can change to control the two factor authentication behaviour for a specific user node.

  • User.twoFactorConfirmed
    This is automatically set to true after a user authenticates via two-factor authentication. If this is set to false the user will always be shown the QR code for him to scan.
  • User.isTwoFactorUser
    Controls if the user wants to authenticate via two factor authentication. This only works if the setting TwoFactor.level is set to 1. If the setting is set to 2, the flag will automatically be set to true after a user logs in.
  • User.twoFactorSecret
    This is the secret which is used to generate tokens. It is automatically generated for every user.

Example implementation

  1. Create the basic login page as per usual
    • If this is done using Edit Mode Binding no changes are necessary
    • If the login is done with custom JavaScript we need to react to status code 202 like so:
    202: function(resp, txt, xhr) {
      var redirectUrl = xhr.getResponseHeader('twoFactorLoginPage') + '?token=' + xhr.getResponseHeader('token');
    
      var qrdata = xhr.getResponseHeader('qrdata');
      if (qrdata) {
        redirectUrl += '&qrdata=' + qrdata;
      }
    
      window.location.href = redirectUrl;
    }
    

    Login Page

  2. Create the TwoFactor.loginpage with the following HTML nodes with the given Edit Mode Binding configuration. (since the qrdata was transferred as URL-safe base64 and img tags only support regular base64 data URIs we need to convert it).
    Note: Since this form uses Edit Mode Binding it is highly advised to create real HTML nodes in structr for the below HTML.
    <div data-structr-meta-hide-conditions="empty(request.qrdata)">
      <img id="qrimage" src="data:image/png;base64, ${str_replace(str_replace(request.qrdata, '_', '/'), '-', '+')}" style="margin-left: calc(50% - 100px);">
      <div>Scan this QR code to use two factor authentication</div>
    </div>
    
    <form action="#" id="loginForm">
      <input name="twoFactorToken" type="hidden" value="${request.token}" data-structr-name="twoFactorToken">
      <div class="form-group">
        <label class="control-label" for="password">Two Factor Code</label>
        <input class="form-control" name="twoFactorCode" required="" type="text" data-structr-name="twoFactorCode">
      </div>
      <button data-structr-action="login" data-structr-attributes="twoFactorToken, twoFactorCode" data-structr-return="/dashboard">Login</button>
    </form>
    

    Example Two Factor Login Page

  3. After a successful password-login, the user is redirected to the two-factor authentication page where he has to enter a one-time-password (OTP)
  4. If the OTP was correct, the user is allowed to continue (and will not be shown the QR code the next time he logs in)

Graph-Browser