otp

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Jul 18, 2026 License: Unlicense Imports: 15 Imported by: 0

README

go-otp

Yet another Go one-time password package. It implements the TOTP (RFC 6238) and HOTP (RFC 4226) algorithms used for two-factor authentication (2FA), along with helpers for generating shared secrets, provisioning URIs, and QR codes for authenticator apps.

Install

go get github.com/erancihan/go-otp
import otp "github.com/erancihan/go-otp"

Quick start (TOTP)

// 1. On enrolment, generate a cryptographically secure secret and store it
//    against the user.
secret, err := otp.NewSecret()
if err != nil {
    // handle error
}

twoFA := otp.OTP{
    Issuer:  "Example Inc",
    Account: "jane@example.com",
    Secret:  secret,
    Window:  1, // tolerate +/- one time step of clock drift
}

// 2. Show the user a QR code to scan with their authenticator app.
uri := twoFA.CreateURI()
png, err := otp.NewQR(uri)
if err != nil {
    // handle error
}
// serve `png` (image/png) to the client

// 3. Later, verify a code the user submits.
ok, err := twoFA.VerifyCode("123456")
if err != nil {
    // handle error (e.g. malformed input)
}
if ok {
    // code accepted
}

HOTP (counter-based)

Set a non-zero Counter to switch to HOTP. This is handy for codes delivered out of band, e.g. by email or SMS.

twoFA := otp.OTP{
    Issuer:  "Example Inc",
    Account: "jane@example.com",
    Secret:  secret,
    Counter: 1,
}

code, err := twoFA.CreateHOTPCode(twoFA.Counter)
// deliver `code` to the user, persist the incremented counter

ok, err := twoFA.VerifyCode(code)

On successful verification the server-side Counter is advanced; persist it so the next verification starts from the right value.

Configuration

All options live on the OTP struct. The zero value matches what authenticator apps expect (6 digits, 30-second period, HMAC-SHA1), so you only set what you need to change.

Field Type Default Description
Issuer string Service/provider name shown in the app.
Account string User identifier (e.g. username or email).
Secret string Base32-encoded shared secret (see NewSecret).
Counter int 0 0 selects TOTP; any non-zero value selects HOTP.
Window int 0 Drift tolerance. 0 disables resync; 1 is the recommended value.
Digits int 6 Number of digits in a code (typically 6 or 8).
Period int 30 TOTP time step in seconds (ignored for HOTP).
Algorithm Algorithm SHA1 Hash function: AlgorithmSHA1, AlgorithmSHA256, AlgorithmSHA512.
twoFA := otp.OTP{
    Issuer:    "Example Inc",
    Account:   "jane@example.com",
    Secret:    secret,
    Digits:    8,
    Period:    60,
    Algorithm: otp.AlgorithmSHA256,
    Window:    1,
}

Note on Window: larger values widen the acceptance window and, per the RFCs, increase exposure to brute-force/DoS. 1 is the recommended balance.

Security notes

  • Secrets are generated with crypto/rand (128 bits of entropy) and returned as a 26-character Base32 string.
  • Submitted codes are compared in constant time to avoid timing side-channels.
  • HMAC-SHA1 is the default because it is universally supported; SHA256/SHA512 are available but not every authenticator app supports them.

Credits

The original implementation was adapted from this article by inanzzz.

License

Released into the public domain under the Unlicense.

Documentation

Overview

Package otp implements one-time passwords following the TOTP (RFC 6238) and HOTP (RFC 4226) standards, together with helpers for generating shared secrets, provisioning URIs, and QR codes for authenticator apps.

The default configuration matches what authenticator apps expect: 6-digit codes, a 30-second TOTP period, and HMAC-SHA1. These can be overridden per OTP value via the Digits, Period, and Algorithm fields.

Original implementation adapted from: http://www.inanzzz.com/index.php/post/y5nu/creating-a-one-time-password-otp-library-for-two-factor-authentication-2fa-with-golang

Index

Constants

View Source
const (
	// OTPLength is the default number of digits in a generated code.
	OTPLength = 6
	// OTPPeriod is the default TTL of a TOTP code in seconds.
	OTPPeriod = 30
)

Variables

This section is empty.

Functions

func NewQR

func NewQR(uri string) ([]byte, error)

NewQR encodes the given otpauth URI as a PNG-formatted QR code. The URI is typically produced by (*OTP).CreateURI.

func NewSecret

func NewSecret() (string, error)

NewSecret generates a cryptographically secure, Base32-encoded shared secret suitable for OTP provisioning. It reads 16 random bytes (128 bits of entropy) from crypto/rand and encodes them without padding, yielding a 26-character string.

Types

type Algorithm added in v1.0.0

type Algorithm string

Algorithm identifies the HMAC hash function used to derive codes. The zero value is treated as AlgorithmSHA1, which is the default mandated by RFC 4226 and understood by virtually all authenticator apps.

const (
	AlgorithmSHA1   Algorithm = "SHA1"
	AlgorithmSHA256 Algorithm = "SHA256"
	AlgorithmSHA512 Algorithm = "SHA512"
)

type OTP

type OTP struct {
	// Issuer represents the service provider. It is you! e.g. your service,
	// your application, your organisation so on.
	Issuer string
	// Account represents the service user. It is the user! e.g. username, email
	// address so on.
	Account string
	// Secret is an arbitrary key value encoded in Base32 and belongs to the
	// service user.
	Secret string
	// Window is used for time (TOTP) and counter (HOTP) synchronization. Given
	// that the possible time and counter drifts between client and server, this
	// parameter helps overcome such issue. TOTP uses backward and forward time
	// window whereas HOTP uses look-ahead counter window that depends on the
	// Counter parameter.
	// Resynchronisation is an official recommended practise, however the
	// lower the better.
	// 0 = not recommended as synchronization is disabled
	//   TOTP: current time
	//   HOTP: current counter
	// 1 = recommended option
	//   TOTP: previous - current - next
	//   HOTP: current counter - next counter
	// 2 = being overcautious
	//   TOTP: previous,previous - current - next,next
	//   HOTP: current counter - next counter - next counter
	// * = Higher numbers may cause denial-of-service attacks.
	// https://datatracker.ietf.org/doc/html/rfc6238#page-7
	// https://datatracker.ietf.org/doc/html/rfc4226#page-11
	Window int
	// Counter is required for HOTP only and used for provisioning the code. Set
	// it to 0 if you with to use TOTP. Start from 1 for HOTP then fetch and use
	// the one in the persistent storage. The server counter is incremented only
	// after a successful code verification, however the counter on the code is
	// incremented every time a new code is requested by the user which causes
	// counters being out of sync. For that reason, time-synchronization should
	// be enabled.
	// https://datatracker.ietf.org/doc/html/rfc4226#page-11
	Counter int
	// Digits is the number of digits in a generated code. It defaults to
	// OTPLength (6) when zero. Authenticator apps typically support 6 or 8.
	Digits int
	// Period is the TOTP time step in seconds. It defaults to OTPPeriod (30)
	// when zero and is ignored for HOTP.
	Period int
	// Algorithm selects the HMAC hash function. The zero value defaults to
	// AlgorithmSHA1.
	Algorithm Algorithm
}

func (*OTP) CreateHOTPCode

func (o *OTP) CreateHOTPCode(counter int) (string, error)

CreateHOTPCode creates a new HOTP with a specific counter. This method is ideal if you are planning to send manually created code via email, SMS etc. The user should not be present a QR code for this option otherwise there is a high posibility that the client and server counters will be out of sync, unless the user will be forced to rescan a newly generaed QR with up to date counter value.

func (*OTP) CreateURI

func (o *OTP) CreateURI() string

CreateURI builds the authentication URI which is used to create a QR code. If the counter is set to 0, the algorithm is assumed to be TOTP, otherwise HOTP. https://github.com/google/google-authenticator/wiki/Key-Uri-Format

func (*OTP) VerifyCode

func (o *OTP) VerifyCode(code string) (bool, error)

VerifyCode talks to an algorithm specific validator to verify the integrity of the code. If the counter is set to 0, the algorithm is assumed to be TOTP, otherwise HOTP.

Jump to

Keyboard shortcuts

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