Need help with openvpn-otp?
Click the “chat” button below for chat support from the developer who created it, or find similar developers for support.

About the developer

238 Stars 70 Forks GNU General Public License v3.0 69 Commits 14 Opened issues


OpenVPN OTP token support plugin

Services available


Need anything else?

Contributors list

# 338,224
Amazon ...
31 commits
# 130,508
11 commits
# 542,052
4 commits
# 169,963
2 commits
# 659,155
1 commit
# 137,199
1 commit
# 1,083
1 commit
# 24,219
1 commit
# 619,352
1 commit
# 20,493
1 commit
# 189,560
1 commit

OpenVPN OTP Authentication support

This plug-in adds support for time based OTP (totp) and HMAC based OTP (hotp) tokens for OpenVPN. Compatible with Google Authenticator software token, other software and hardware based OTP tokens.

Compile and install
file to your OpenVPN plugins directory (usually

Be sure you've installed the following packages first: *

(Some distros have
file in a separate package) *

To bootstrap autotools (generate configure and Makefiles):


Build and install with:

./configure --prefix=/usr
make install

The default install location (PREFIX/LIB/openvpn) can be changed by passing the directory with

./configure --with-openvpn-plugin-dir=/plugin/dir

Add the following lines to your OpenVPN server configuration file to deploy OTP plugin with default settings. For OpenVPN <=2.3.x, use:

# use otp passwords with default settings (OpenVPN<=2.3.x syntax)
plugin /usr/lib64/openvpn/plugins/

For OpenVPN 2.4, use double quotes:

# use otp passwords with default settings (OpenVPN>=2.4 syntax)
plugin "/usr/lib64/openvpn/plugins/"

By default the following settings are applied:

otp_secrets=/etc/ppp/otp-secrets      # OTP secret file
otp_slop=180                          # Maximum allowed clock slop (seconds)
totp_t0=0                             # T0 value for TOTP (time drift in seconds)
totp_step=30                          # Step value for TOTP (seconds), should be 30 seconds for soft tokens and 60 seconds for hardware tokens
totp_digits=6                         # Number of digits to use from TOTP hash
motp_step=10                          # Step value for MOTP
hotp_syncwindow=2                     # Maximum drifts allowed for clients to resynchronise their tokens' counters (see rfc4226#section-7.4)
hotp_counters=/var/spool/openvpn/hotp-counters/      # HOTP counters directory
password_is_cr=0                      # If set to 1, openvtp-otp will expect password as result of a challenge/response protocol  
debug=0                               # Debug mode: 0=disabled, 1=enabled

Add these variables on the same line as

plugin /.../
line if you want different values. If you skip one of the variables, the default value will be applied. For OpenvVPN <=2.3.x, the configuration item should look like this:
# use otp passwords with custom settings (OpenVPN<=2.3.x syntax)
plugin /usr/lib64/openvpn/plugins/ otp_secrets=/etc/my_otp_secret_file otp_slop=300 totp_t0=2 totp_step=30 totp_digits=8 motp_step=10

OpenVPN 2.4 requires plugin parameters to be put in double quotes:

# use otp passwords with custom settings (OpenVPN>=2.4 syntax)
plugin "/usr/lib64/openvpn/plugins/" "otp_secrets=/etc/my_otp_secret_file otp_slop=300 totp_t0=2 totp_step=30 totp_digits=8 motp_step=10"

It is important to mention that totp_step has to be same on both, the client and server, because it is used for calculation of current token value.

Add the following lines to your OpenVPN clients' configuration files:

# use username/password authentication
# do not cache auth info

OpenVPN will re-negotiate username/password details every 3600 seconds by default. To disable that behaviour, add the following line to both client and server configs:

# disable username/password renegotiation
reneg-sec 0


file format is exactly the same as for ppp-otp plugin, which makes it very convenient to have PPP and OpenVPN running on the same machine and using the same secrets file. The secrets file has the following layout:
# user server type:hash:encoding:key:pin:udid client
# where type is totp, totp-60-6 or motp
#       hash should be sha1 in most cases
#       encoding is base32, hex or text
#       key is your key in encoding format
#       pin may be a number or a string (may be empty)
#       udid is used only in motp mode and ignored in totp mode
# use sha1/base32 for Google Authenticator with a simple pin
bob otp totp:sha1:base32:K7BYLIU5D2V33X6S:1234:xxx *

use sha1/base32 for Google Authenticator with a strong pin

alice otp totp:sha1:base32:46HV5FIYE33TKWYP:5uP3rH4x0r:xxx *

use sha1/base32 for Google Authenticator without a pin

john otp totp:sha1:base32:LJYHR64TUI7IL3RD::xxx *

use sha1/base32 for HOTP without a pin

lucie otp hotp:sha1:base32::MT4GWEZTSRBV2QQC:xxx *

use totp-60-6 and sha1/hex for hardware based 60 seconds / 6 digits tokens

mike otp totp-60-6:sha1:hex:5c5a75a87ba1b48cb0b6adfd3b7a5a0e:6543:xxx *

use text encoding for clients supporting plain text keys

jane otp totp:sha1:text:1234567890:9876:xxx *

allow multiple tokens without a pin for a specific user

hobbes otp totp:sha1:base32:LJYHR64TUI7IL3RD::xxx * hobbes otp totp:sha1:base32:7VXNJAFPYYKO3ILO::xxx *

When users vpn in, they will need to provide their username and pin+current OTP number from the OTP token. Examples for users bob, alice and john:

username: bob
password: 1234920151

username: alice password: 5uP3rH4x0r797104

username: john password: 408923

Using OpenVPN OTP for Multi-Factor Authentication

You can use this plugin to do multi-factor authentication, by using the OpenVPN Challenge/Response feature. For the moment this is supported by two plugins: OpenVPN OTP and a fork of OpenVPN Auth-LDAP.

There are three side to this OpenVPN, the users and the plugins.


The feature needs to be activated in the client configuration file with the

# use Google Authenticator OTP
static-challenge "Enter Google Authenticator Token" 1

From the OpenVPN manual:

static-challenge t e
: Enable static challenge/response protocol using challenge text t, with echo flag given by e (0|1). The echo flag indicates whether or not the user's response to the challenge should be echoed.
Also, you need to add both plugins to your openvpn server configuration. Having the two auth plugins present, will require that both of them authenticate the user, ie it is not one of the two, it's both.
   #LDAP (Active Directory Authentication) PLUGIN
   plugin /usr/lib/openvpn/ /etc/openvpn/auth/auth-ldap.conf
   plugin /usr/local/lib/openvpn/ "password_is_cr=1 otp_secrets=/etc/openvpn/auth/otp-secrets"


If the

flag is set when the users vpn in, they will be asked for a username, a password and a pin+current OTP number from the OTP token. The prompt for the pin+current OTP number will be the first argument of the
option (the second argument controls if the input is masked or clear-type when the user enters it). The input for both fields is combined and passed to both plug-ins as a specially formatted password.


If the

flag is set, passwords that are passed to plugins, will have a special format. So plug-ins need to be signalled about this in their configuration: * In openvpn-otp this is controlled by the
flag and disabled by default. So to enable it, set
in your openvpn-otp configuration. * In openvpn-auth-ldap this is controlled by the
flag in the configuration file: ````

Uncomment and set to true to support OpenVPN Challenge/Response

PasswordIsCR true

The various settings will pass username, password and the response to the challenge to both plug-ins. The plug-ins will parse this response (triggered by the flags in their configuration) and each plugin will authenticate the user by looking at the field that's relevant. Examples for users bob, alice and john:

username: bob password: password1 # this is the LDAP password, verified by openvpn-auth-ldap response: 1234920151 # this is a (simple) pin plus a Google OTP, verified by openvpn-otp

username: alice password: password2 # this is the LDAP password, verified by openvpn-auth-ldap response: 5uP3rH4x0r797104 # this is a (strong) pin plus a Google OTP, verified by openvpn-otp

username: john password: password3 # this is the LDAP password, verified by openvpn-auth-ldap response: 408923 # this is the Google OTP, verified by openvpn-otp ``` The last example (user john) is probably the most typical use case: a first level of authentication of username and password against the LDAP and then a second level of authenitcation using an OTP, which doesn't require a pin, because the LDAP authentication already uses a password.

Please note: the various flags go together, i.e. making the changes only in the openvpn-otp or openvpn-auth-ldap config and not in the client config or vice versa will break the system. Also, please make sure that you're using a forked version of Auth-LDAP plugin.

HOTP counters initialisation

HOTP counters are stored in files, which reside under the

directory (
by default). OpenVPN server process should have enough permissions to read and modify files in that directory.

For each HOTP entry in the

files, we compute the SHA1 checksum of the secret key, and use the resulting lower case string as the filename.

For example, the following HOTP entry

lucie otp hotp:sha1:base32::MT4GWEZTSRBV2QQC:xxx *
has SHA1(MT4GWEZTSRBV2QQC) = a0b2e3795f7ca9e60183af274a004cdd0ac9276f and the HOTP counter file should be read and stored in

The administrator has to create and populate each HOTP counter file with initial value after adding new HOTP records to

file. The following command will do the job:
    echo -n 0 > /var/spool/openvpn/hotp-counters/"$(echo -n 'secretkey' | sha1sum | cut -c-40)"


The following exceptions are required for this plugin to work properly on a system with Security Enhanced Linux running in enforcing mode:

#============= openvpn_t ==============

allow openvpn_t auth_home_t:file { unlink open }; allow openvpn_t user_home_dir_t:dir { write remove_name add_name }; allow openvpn_t user_home_dir_t:file { rename write getattr read create unlink open }; allow openvpn_t pppd_etc_t:dir search; allow openvpn_t pppd_etc_t:file { read getattr open };

Alternative SELinux policy reported to work with CentOS: ``` $ yum install policycoreutils-python \ selinux-policy-devel $ cat - < openvpnotp.te module openvpnotp 1.0;

require { type openvpnt; type pppdetc_t; class dir { search getattr open }; class file { ioctl lock read getattr open }; }

============= openvpn_t ==============

readfilespattern(openvpnt, pppdetct, pppdetct) EOF $ make -f /usr/share/selinux/devel/Makefile openvpnotp.pp $ semodule --install openvpn_otp.pp ```

Using Google Authenticator on your server and mobile

  • install
    on your server
  • run
    google-authenticator --time-based --disallow-reuse --force --rate-limit=3 --rate-time=30 --window-size=17 --issuer=foocorp [email protected] --secret=/root/.user.google_authenticator > /root/user.auth
  • user.auth
    file will contain the key for entry into
    , and the Google URL containing the image to be scanned with the Google Authenticator mobile app

Supported Operating Systems

This plugin has been successfully compiled and tested with:

  • Ubuntu Linux 14.04 / 16.04 / 18.04
  • CentOS / RHEL 7
  • FreeBSD 11.2
  • Archlinux
  • OpenBSD 6.4
  • NetBSD 8.0
  • DragonFly BSD 5.4

In OpenBSD, please use autoconf 2.69 and automake 1.15.1. You might have to export version numbers before running

It should work in other *NIX environments, please raise an issue if it does not.


Make sure that time is in sync on the server and on your phone/tablet/other OTP client device. You may use

for token verification on your OpenVPN server:
# for TOTP, type:
$ oathtool --totp -b K7BYLIU5D2V33X6S

for HOTP, type:

$ oathtool -b -c 5 NFIJ5GSNU574OU6B 214648

The tokens should be identical on your OTP client and OpenVPN server. You may also enable debug mode to log user-provided and expected credentials (do not use in production environments):

# use otp passwords with custom settings
plugin /usr/lib64/openvpn/plugins/ debug=1 [...other settings...]

Also check that

/etc/ppp/otp-secrets file
: - is accessible by OpenVPN - has spaces as field separators - has UNIX style line separator (new line only without CR)

Make sure that OpenVPN server process can read and modify files in


Inspired by ppp-otp plugin written by GitHub user kolbyjack. This plugin written by Evgeny Gridasov ([email protected])

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.