One Time Passwords (OTPs) are an mechanism to improve security over passwords alone.

otp: One Time Password utilities Go / Golang

PkgGoDev Build Status

Why One Time Passwords?

One Time Passwords (OTPs) are an mechanism to improve security over passwords alone. When a Time-based OTP (TOTP) is stored on a user's phone, and combined with something the user knows (Password), you have an easy on-ramp to Multi-factor authentication without adding a dependency on a SMS provider. This Password and TOTP combination is used by many popular websites including Google, Github, Facebook, Salesforce and many others.

The otp library enables you to easily add TOTPs to your own application, increasing your user's security against mass-password breaches and malware.

Because TOTP is standardized and widely deployed, there are many mobile clients and software implementations.

otp Supports:

  • Generating QR Code images for easy user enrollment.
  • Time-based One-time Password Algorithm (TOTP) (RFC 6238): Time based OTP, the most commonly used method.
  • HMAC-based One-time Password Algorithm (HOTP) (RFC 4226): Counter based OTP, which TOTP is based upon.
  • Generation and Validation of codes for either algorithm.

Implementing TOTP in your application:

User Enrollment

For an example of a working enrollment work flow, Github has documented theirs, but the basics are:

  1. Generate new TOTP Key for a User. key,_ := totp.Generate(...).
  2. Display the Key's Secret and QR-Code for the User. key.Secret() and key.Image(...).
  3. Test that the user can successfully use their TOTP. totp.Validate(...).
  4. Store TOTP Secret for the User in your backend. key.Secret()
  5. Provide the user with "recovery codes". (See Recovery Codes bellow)

Code Generation

  • In either TOTP or HOTP cases, use the GenerateCode function and a counter or time.Time struct to generate a valid code compatible with most implementations.
  • For uncommon or custom settings, or to catch unlikely errors, use GenerateCodeCustom in either module.

Validation

  1. Prompt and validate User's password as normal.
  2. If the user has TOTP enabled, prompt for TOTP passcode.
  3. Retrieve the User's TOTP Secret from your backend.
  4. Validate the user's passcode. totp.Validate(...)

Recovery Codes

When a user loses access to their TOTP device, they would no longer have access to their account. Because TOTPs are often configured on mobile devices that can be lost, stolen or damaged, this is a common problem. For this reason many providers give their users "backup codes" or "recovery codes". These are a set of one time use codes that can be used instead of the TOTP. These can simply be randomly generated strings that you store in your backend. Github's documentation provides an overview of the user experience.

Improvements, bugs, adding feature, etc:

Please open issues in Github for ideas, bugs, and general thoughts. Pull requests are of course preferred :)

License

otp is licensed under the Apache License, Version 2.0

Owner
Paul Querna
CTO at ConductorOne
Paul Querna
Comments
  • validate six digits one time password

    validate six digits one time password

    First of all thank you for this great library!

    I'm using otp for my web service and I'm currently trying to write some tests against my login process. Since otp uses six digits by default (same as google authenticator app) I have to create a valid otp with six digits.

    I looked at your tests for otp but they all use eight digits. How can I generate a valid six digit one time password?

    Thank you!

  • URL Encoding bug

    URL Encoding bug

    Hello

    if the issuer contains a space, the URL encoder will mix up the URL.

    key, err := totp.Generate(totp.GenerateOpts{
    	Issuer:      "Test Issuer",
    	AccountName: "[email protected]",
    })
    

    Actual result: otpauth://totp/Test%20Issuer:[email protected]?algorithm=SHA1&digits=6&issuer=Test+Issuer&period=30&secret=QE2C7JXZB3TY3FBKL6PB7PZXP7UCRPOA

    otp_issue

    Expected result: otpauth://totp/Test%20Issuer:[email protected]?algorithm=SHA1&digits=6&issuer=Test%20Issuer&period=30&secret=QE2C7JXZB3TY3FBKL6PB7PZXP7UCRPOA

    otp_issue_expected

  • Cannot reuse the secret

    Cannot reuse the secret

    in https://github.com/pquerna/otp/blob/master/totp/totp.go#L183 the secret should not be re-encoded since that is the final seed we will store in the DB. To be able to reuse the seed to generate a new key we need to add it as a final secret.

  • use options keeps users from choosing between Validate/ValidateCustom and Generate/GenerateCustom

    use options keeps users from choosing between Validate/ValidateCustom and Generate/GenerateCustom

    I've been using this package for quite a while and it has helped me thousands of times. However, sometimes I get confused in using custom validators/generators. I think we can make it better if you agree on using options in main functions, say, Validate and Generate funcs.

  • Problems with example code and google authenticator (android)

    Problems with example code and google authenticator (android)

    Hello, So I was trying out the library and using google authenticator to scan the QR codes. This is the code I'm using to do so.

    import (
    	"github.com/pquerna/otp"
    	"github.com/pquerna/otp/totp"
    
    	"bufio"
    	"bytes"
    	"fmt"
    	"image/png"
    	"io/ioutil"
    	"os"
    )
    
    func display(key *otp.Key, data []byte) {
    	fmt.Printf("Issuer:       %s\n", key.Issuer())
    	fmt.Printf("Account Name: %s\n", key.AccountName())
    	fmt.Printf("Secret:       %s\n", key.Secret())
    	fmt.Printf("URL:          %s\n", key.URL())
    	fmt.Println("Writing PNG to qr-code.png....")
    	ioutil.WriteFile("qr-code.png", data, 0644)
    	fmt.Println("")
    	fmt.Println("Please add your TOTP to your OTP Application now!")
    	fmt.Println("")
    }
    
    func promptForPasscode() string {
    	reader := bufio.NewReader(os.Stdin)
    	fmt.Print("Enter Passcode: ")
    	text, _ := reader.ReadString('\n')
    	return text
    }
    
    func main() {
    	key, err := totp.Generate(totp.GenerateOpts{
    		Issuer:      "Example.com",
    		AccountName: "[email protected]",
    		Algorithm:   otp.AlgorithmSHA1,
    	})
    	if err != nil {
    		panic(err)
    	}
    	// Convert TOTP key into a PNG
    	var buf bytes.Buffer
    	img, err := key.Image(200, 200)
    	if err != nil {
    		panic(err)
    	}
    	png.Encode(&buf, img)
    
    	// display the QR code to the user.
    	display(key, buf.Bytes())
    
    	// Now Validate that the user's successfully added the passcode.
    	fmt.Println("Validating TOTP...")
    	for {
    		passcode := promptForPasscode()
    		valid := totp.Validate(passcode, key.Secret())
    		if valid {
    			println("Valid passcode!")
    		} else {
    			println("Invalid passocde!")
    		}
    	}
    }
    

    This generates a QR code which I am able to scan with goole authenticator, but everytime i try the passcode it is invalid. Wanted to know if theres some issue with my code.

  • can I use a secret string containg specail characters?

    can I use a secret string containg specail characters?

    I want to generate a password so I used the function in totp package GenerateCodeCustom() as

       func getPassword(token_shared_secret string) string{
    	opts := totp.ValidateOpts{}
    	opts.Period = 30
    	opts.Skew = 1
    	opts.Digits = 10
    	opts.Algorithm = otp.AlgorithmSHA512
    	
    	var password string
    	t := time.Now()
    	password, err := totp.GenerateCodeCustom(token_shared_secret,t,opts)
    	if err != nil {
    		panic(err)
    	}
    	return password
    }
    
    var password string = getPassword(myID+subfix)
    

    I needed to change some options like that cuz the main purpose is to make a HTTP POST to some URL and they directed me to make the password as an 10-digit time-based one, time step X is 30secs ,T0 is 0 and use HMAC-SHA-512 for the hash function.

    the parameter I put as myID+subfix is a concatenated string with an email address and an English string.

    The problem is that email address contains special charters @ and . (at and dot). And I failed to get the password with the error sign

    panic: Decoding of secret as base32 failed.

    So I tried modifying the GenerateCodeCustom() function in hotp package I changed the line (line no.84)

    secretBytes, err := base32.StdEncoding.DecodeString(secret)

    as

    secretBytes := []byte(secret)

    At least I succeeded to get a ten-digit time-based password but I don't think it is correct one because the server keep sending me http 401 response. I think it's not a proper way, I may need to do something.

    Can you let me know how can I solve this ?

  • Problems with TOTP SHA512

    Problems with TOTP SHA512

    Hi, I use the following code (which is very similar to this example, if not for line 19 (which I added), line 38 (which I added), and the cycle (lines 56 and 64) which I added to simplify testing with multiple clients:

    package main
    
    import (
    	"github.com/pquerna/otp"
    	"github.com/pquerna/otp/totp"
    
    	"bufio"
    	"bytes"
    	"fmt"
    	"image/png"
    	"io/ioutil"
    	"os"
    )
    
    func display(key *otp.Key, data []byte) {
    	fmt.Printf("Issuer:       %s\n", key.Issuer())
    	fmt.Printf("Account Name: %s\n", key.AccountName())
    	fmt.Printf("Secret:       %s\n", key.Secret())
    	fmt.Printf("URL:          %s\n", key.URL())
    	fmt.Println("Writing PNG to qr-code.png....")
    	ioutil.WriteFile("qr-code.png", data, 0644)
    	fmt.Println("")
    	fmt.Println("Please add your TOTP to your OTP Application now!")
    	fmt.Println("")
    }
    
    func promptForPasscode() string {
    	reader := bufio.NewReader(os.Stdin)
    	fmt.Print("Enter Passcode: ")
    	text, _ := reader.ReadString('\n')
    	return text
    }
    
    func main() {
    	key, err := totp.Generate(totp.GenerateOpts{
    		Issuer:      "Example.com",
    		AccountName: "[email protected]",
    		Algorithm:   otp.AlgorithmSHA512,
    	})
    	if err != nil {
    		panic(err)
    	}
    	// Convert TOTP key into a PNG
    	var buf bytes.Buffer
    	img, err := key.Image(200, 200)
    	if err != nil {
    		panic(err)
    	}
    	png.Encode(&buf, img)
    
    	// display the QR code to the user.
    	display(key, buf.Bytes())
    
    	// Now Validate that the user's successfully added the passcode.
    	fmt.Println("Validating TOTP...")
    	for {
    		passcode := promptForPasscode()
    		valid := totp.Validate(passcode, key.Secret())
    		if valid {
    			println("Valid passcode!")
    		} else {
    			println("Invalid passocde!")
    		}
    	}
    }
    

    In a test run, this is what it outputs:

    Issuer:       Example.com
    Account Name: [email protected]
    Secret:       N3K5NHE26HHXP2CL
    URL:          otpauth://totp/Example.com:[email protected]?algorithm=SHA512&digits=6&issuer=Example.com&period=30&secret=N3K5NHE26HHXP2CL
    

    qr-code

    I tried to add the QRCode to Google Authenticator (on Android), FreeOTP (on Android), Google Authenticator (on iOS), FreeOTP (on iOS), gopass (on Linux).

    On multiple tests, FreeOTP (on both Android and iOS), Google Authenticator on iOS and gopass agree on the generated OTPs, while Google Authenticator on Android does not. Only the code from Google Authenticator on Android is recognised as right.

    Now, I'm not sure if this is a problem on the server side or on the client side, so I'm opening the ticket on both the clients (FreeOTP Android, gopass) and the server (github.com/pquerna/otp)

  • Google changed provisioning of totp-URLs to lowercase-base32 now, which fails to parse

    Google changed provisioning of totp-URLs to lowercase-base32 now, which fails to parse

    Google gave me a QR code with this content: otpauth://totp/Google%3Afoo%40example.com?secret=qlt6vmy6svfx4bt4rpmisaiyol6hihca&issuer=Google (don't worry, I haven't taken this secret into use).

    It yields this error: Decoding of secret as base32 failed

    If I uppercase the secret myself (=> otpauth://totp/Google%3Afoo%40example.com?secret=QLT6VMY6SVFX4BT4RPMISAIYOL6HIHCA&issuer=Google), it succeeds.

  • Fix URL query encoding

    Fix URL query encoding

    This pull request addresses https://github.com/pquerna/otp/issues/68. I have also encountered + signs instead of spaces in Google Authenticator when using https://github.com/ory/kratos (which uses this library).

    It seems to me that copy-pasting the URL-encoding function is the simplest and most robust solution here (instead of trying to do some clever replacing post-encoding). I also fixed some typos in the first commit.

  • Set default digit value for hotp.GenerateCodeCustom()

    Set default digit value for hotp.GenerateCodeCustom()

    Problem: If the validateOps.Digit parameter is not passed to the hotp.GenerateCodeCustom() function, the default value is not correctly assigned. By default, it should generate a 6-digit code, but it produces 0.

    Solution:

    • Add unit test for hotp.GenerateCodeCustom()
    • I set the otp.DigitSix value as the default.
  • Must use AlgorithmSHA1 with iOS version of Google Authenticator

    Must use AlgorithmSHA1 with iOS version of Google Authenticator

            key,_ := totp.Generate(totp.GenerateOpts{ 
                  AccountName: "XYZ Test", 
                  Issuer: "some.domain.com", 
                  Algorithm: otp.AlgorithmSHA512, 
            })
            
            var buff bytes.Buffer
    	img, _ := key.Image(256,256)
    	f, _ := os.Create("test.html")
    	png.Encode(&buff, img)
    	encodedString := base64.StdEncoding.EncodeToString(buff.Bytes())
    	htmlImage := "<img src=\"data:image/png;base64," + encodedString + "\" />"
    	l, err := f.WriteString(htmlImage)
    	if err != nil {
    		log.Println(err)
    	}
    

    The resultant test.html shows a QR code that provides correct codes when scanned with Google Authenticator on Android, but not on iPhone.

  • Feature/docker

    Feature/docker

    First of all, thank you for keeping things simple. It was very easy going over your code, great job!

    Motivation - I wanted to see how it works out-of-the-box, without installing/compiling anything.

    So I wrote a Dockerfile to build the application and test it easily, allowing users to test the app immediately.

    Build a Docker image

    DOCKER_ORG=unfor19
    $ docker build -t ${DOCKER_ORG}/totp -f Dockerfile.example .
    

    Run a container

    DOCKER_ORG=unfor19
    $ docker run --rm -it -e GENERATE_TEMP_PASSCODE="true" ${DOCKER_ORG}/totp:latest
    

    Example

    Issuer:       Example.com
    Account Name: [email protected]
    Secret:       PZLTOL3RPGS67EYXPYFLIBYEY5QMSJB5
    Writing PNG to qr-code.png....
    
    Please add your TOTP to your OTP Application now!
    
    Generating temporary passcode, valid for 30 seconds...
    Temp Passcode: 375146
    Validating TOTP...
    Enter Passcode: 375146
    Valid passcode!
    

    TODO

    • I've already pushed this image to my DockerHub repository unfor19/totp, so I recommend that you do the same, and then replace unfor19 in README.md

    Let me know if you want to migrate from Travis to GitHub Actions, your builds/tests will run much faster and it's free ๐Ÿ˜„

  • Example on how to handle recovery codes?

    Example on how to handle recovery codes?

    Forgive me if this is a stupid question, how exactly can I handle recovery codes for users?

    In README, you said "These can simply be randomly generated strings that you store in your backend" but I could not find the code that do this.

    Does that mean I need to handle recovery codes myself? I was thinking along the lines of

    1. Generate recovery codes in backend
    2. Give users recovery codes
    3. Compare passcode with recovery codes (pulled from backend storage). If not matched, then compare passcode with TOTP / HOTP as usual? If matched, remove recovery codes (one time use like Github)

    Let me know if you have plan to support this behavior natively in this package, or if you are interested in a Pull Request that does this (backend storage via an interface, of course)?

Related tags
QR secrets is a cryptographically secure mechanism to store secret data with the highest levels of security and store it on physical paper.
QR secrets is a cryptographically secure mechanism to store secret data with the highest levels of security and store it on physical paper.

QR Secrets QR secrets is a cryptographically secure mechanism to store secret data with the highest levels of security. Incorporating; AES256-GCM-HKDF

Jan 12, 2022
Web-Security-Academy - Web Security Academy, developed in GO

Web-Security-Academy - Web Security Academy, developed in GO

Feb 23, 2022
Create strong passwords using words that are easy for you to remember
Create strong passwords using words that are easy for you to remember

Grasp Create strong passwords using words that are easy for you to remember A way to circumvent password complexity rules and restrictions while only

Nov 3, 2022
Find secrets and passwords in container images and file systems
Find secrets and passwords in container images and file systems

Find secrets and passwords in container images and file systems

Jan 1, 2023
A Go Library For Generating Random, Rule Based Passwords. Many Random, Much Secure.
A Go Library For Generating Random, Rule Based Passwords. Many Random, Much Secure.

Can Haz Password? A Go library for generating random, rule based passwords. Many random, much secure. Features Randomized password length (bounded). T

Dec 6, 2021
linenoise is a library that generates strings of random characters that can be used as reasonably secure passwords.

linenoise linenoise is a library that generates strings of random characters (herein called a "noise") that can be used as reasonably secure passwords

Dec 7, 2022
Simple CLI to generate passwords

pwdrng Simple CLI to generate passwords $ pwdrng Copied password to clipboard: bfx861[X<26-b^UT Installation and Usage With Homebrew $ brew tap docto

Apr 8, 2022
Dec 28, 2022
HTTP middleware for Go that facilitates some quick security wins.

Secure Secure is an HTTP middleware for Go that facilitates some quick security wins. It's a standard net/http Handler, and can be used with many fram

Jan 3, 2023
Gryffin is a large scale web security scanning platform.

Gryffin (beta) Gryffin is a large scale web security scanning platform. It is not yet another scanner. It was written to solve two specific problems w

Dec 27, 2022
set of web security test cases and a toolkit to construct new ones

Webseclab Webseclab contains a sample set of web security test cases and a toolkit to construct new ones. It can be used for testing security scanners

Jan 7, 2023
PHP security vulnerabilities checker

Local PHP Security Checker The Local PHP Security Checker is a command line tool that checks if your PHP application depends on PHP packages with know

Jan 3, 2023
Tracee: Linux Runtime Security and Forensics using eBPF
Tracee: Linux Runtime Security and Forensics using eBPF

Tracee is a Runtime Security and forensics tool for Linux. It is using Linux eBPF technology to trace your system and applications at runtime, and analyze collected events to detect suspicious behavioral patterns.

Jan 5, 2023
Sqreen's Application Security Management for the Go language
Sqreen's Application Security Management for the Go language

Sqreen's Application Security Management for Go After performance monitoring (APM), error and log monitoring itโ€™s time to add a security component int

Dec 27, 2022
A scalable overlay networking tool with a focus on performance, simplicity and security

What is Nebula? Nebula is a scalable overlay networking tool with a focus on performance, simplicity and security. It lets you seamlessly connect comp

Dec 29, 2022
How to systematically secure anything: a repository about security engineering
How to systematically secure anything: a repository about security engineering

How to Secure Anything Security engineering is the discipline of building secure systems. Its lessons are not just applicable to computer security. In

Jan 5, 2023
Convenience of containers, security of virtual machines

Convenience of containers, security of virtual machines With firebuild, you can build and deploy secure VMs directly from Dockerfiles and Docker image

Dec 28, 2022
MQTTๅฎ‰ๅ…จๆต‹่ฏ•ๅทฅๅ…ท (MQTT Security Tools)
MQTTๅฎ‰ๅ…จๆต‹่ฏ•ๅทฅๅ…ท (MQTT Security Tools)

โ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ•โ–ˆโ–ˆโ•—โ•šโ•โ•โ–ˆโ–ˆโ•”โ•โ•โ•โ•šโ•โ•โ–ˆโ–ˆโ•”โ•โ•โ•โ–ˆโ–ˆโ•”โ•โ•โ•โ•โ• โ–ˆโ–ˆโ•”โ–ˆโ–ˆโ–ˆโ–ˆโ•”โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•‘โ•šโ–ˆโ–ˆโ•”โ•โ–ˆ

Dec 21, 2022