An open API service indexing awesome lists of open source software.

https://github.com/ja7ad/otp

A high-performance, zero-dependency Go package for generating and validating TOTP, HOTP and OCRA one-time passwords β€” RFC 4226, RFC 6238 and RFC 6287 compliant.
https://github.com/ja7ad/otp

2fa authentication go golang hotp mfa otp rfc4226 rfc6238 rfc6287 security totp

Last synced: about 1 month ago
JSON representation

A high-performance, zero-dependency Go package for generating and validating TOTP, HOTP and OCRA one-time passwords β€” RFC 4226, RFC 6238 and RFC 6287 compliant.

Awesome Lists containing this project

README

          

![otp](.github/otp.svg)
[![codecov](https://codecov.io/gh/Ja7ad/otp/branch/main/graph/badge.svg?token=8N6N60D5UI)](https://codecov.io/gh/Ja7ad/otp)
[![Go Report Card](https://goreportcard.com/badge/github.com/ja7ad/otp)](https://goreportcard.com/report/github.com/ja7ad/otp)
[![Go Reference](https://pkg.go.dev/badge/github.com/ja7ad/otp.svg)](https://pkg.go.dev/github.com/ja7ad/otp)

# πŸ” OTP

A high-performance, zero-dependency Go package for generating and validating TOTP, HOTP and OCRA one-time passwords β€” RFC [4226](https://datatracker.ietf.org/doc/html/rfc4226), RFC [6238](https://datatracker.ietf.org/doc/html/rfc6238) and RFC [6287](https://datatracker.ietf.org/doc/html/rfc6287) compliant.

- [Feature](#-features)
- [Installation](#-installation-go--124)
- [Library](#-using-go)
- [OTP-API](#-prebuilt-binary)
- [Docker](#-docker-image)
- [Comparison](#-comparison)
- [Performance](#-performance-comparison)
- [Features](#-feature-comparison)
- [Proof algorithm](#-algorithm-rfc)
- [Usage](#-usage)
- [Contributing](#-contributing)
- [Reference](#-references)

## ✨ Features

- Zero dependencies – fully self-contained, no external packages
- High performance with low allocations
- Supports HOTP (RFC [4226](https://datatracker.ietf.org/doc/html/rfc4226)), TOTP (RFC [6238](https://datatracker.ietf.org/doc/html/rfc6238)) and OCRA (RFC [6287](https://datatracker.ietf.org/doc/html/rfc6287)) algorithms
- Configurable OTP digit lengths: 6, 8, or 10
- Supports SHA1, SHA256, and SHA512 HMAC algorithms
- Constant-time OTP validation to prevent timing attacks
- Clock skew tolerance for TOTP validation
- Generates `otpauth://` URLs for Google Authenticator and compatible apps
- Parses `otpauth://` URLs into configuration structs
- Secure random secret generation (base32 encoded)
- Thoroughly tested against official RFC test vectors
- Includes fuzz tests, benchmark coverage, and solid algorithm validation

Here’s your updated `README.md` **Installation** section with release and Docker image info:

## πŸ“¦ Installation (Go >= 1.24)

### πŸ› οΈ Using Go

```bash
go get -u github.com/ja7ad/otp
```

> Node.js bindings are available [here](./otp-js).

---

### πŸš€ Prebuilt Binary

Download the latest CLI/API binary for your platform from the [latest release page](https://github.com/ja7ad/otp/releases/latest).

> Online demo: https://otp-api.leapcell.app/docs

```shell
$ otp -serve localhost:8080
2025/04/06 10:41:48 INFO starting server address=:8080
2025/04/06 10:41:50 INFO request method=GET path=/docs/index.html status=200 duration=740.394Β΅s
2025/04/06 10:41:51 INFO request method=GET path=/docs/doc.json status=200 duration=803.67Β΅s
2025/04/06 10:41:53 INFO request method=GET path=/ status=200 duration=149.042Β΅s
2025/04/06 10:41:54 INFO request method=GET path=/docs status=302 duration=24.444Β΅s
```

| Method | Path | Description |
|--------|--------------------|----------------------------------|
| POST | `/totp/generate` | Generate a TOTP code |
| POST | `/totp/validate` | Validate a TOTP code |
| POST | `/hotp/generate` | Generate a HOTP code |
| POST | `/hotp/validate` | Validate a HOTP code |
| POST | `/ocra/generate` | Generate an OCRA code |
| POST | `/ocra/validate` | Validate an OCRA code |
| GET | `/otp/secret` | Generate a random base32 secret |
| POST | `/otp/url` | Generate otpauth URL |
| GET | `/ocra/suites` | List supported OCRA suites |
| POST | `/ocra/suite` | Parse and describe suite config |

---

### 🐳 Docker Image

You can also run the server using Docker:

```bash
docker pull ja7adr/otp
docker run -p 8080:8080 ja7adr/otp
```

> Image available at [Docker Hub](https://hub.docker.com/r/ja7adr/otp)

## πŸ”¬ Comparison

This comparison is performance and feature.

#### πŸš€ Performance Comparison

This comparison is for `Ja7ad/otp` vs `pquerna/otp`

| Algorithm | Suite | Digits | Library | `ns/op` | `B/op` | `allocs/op` | `N` (runs/sec) |
|-----------|----------------------------------------|--------|----------------|---------|--------|--------------|----------------|
| SHA1 | `OCRA-1:HOTP-SHA1-6:QN08` | 6 | **Ja7ad/otp** | **1134** | **552** | **9** | **881,058** |
| SHA1 | HOTP/TOTP (default) | 6 | pquerna/otp | 1420 | 592 | 13 | 704,225 |
| SHA256 | `OCRA-1:HOTP-SHA256-8:C-QN08-PSHA1` | 8 | **Ja7ad/otp** | **984.3** | **592** | **9** | **1,015,907** |
| SHA256 | HOTP/TOTP (default) | 8 | pquerna/otp | 1477 | 728 | 13 | 677,236 |
| SHA512 | `OCRA-1:HOTP-SHA512-8:QN08-T1M` | 8 | **Ja7ad/otp** | **1752** | **944** | **9** | **570,853** |
| SHA512 | HOTP/TOTP (default) | 8 | pquerna/otp | 2359 | 1224 | 13 | 423,778 |

| Metric | Ja7ad/otp | pquerna/otp | βœ… Winner |
|------------------|---------------------|---------------------|----------|
| **Execution time** (`ns/op`) | **~2x faster** across all algorithms and digit sizes | Slower in all cases | βœ… **Ja7ad/otp** |
| **Memory usage** (`B/op`) | **~30–50% less** memory allocated | Higher allocations | βœ… **Ja7ad/otp** |
| **Allocations** (`allocs/op`) | **7** allocations | **13** allocations | βœ… **Ja7ad/otp** |
| **Dependencies** | **Zero** external deps | Relies on stdlib + extras | βœ… **Ja7ad/otp** |

- `Ja7ad/otp`: **736 ns**, **520 B**, **7 allocs**
- `pquerna/otp`: **1495 ns**, **728 B**, **13 allocs**

#### βœ… Feature Comparison

| Feature | Ja7ad/otp | pquerna/otp |
|-----------------------------|-----------|-------------|
| RFC 4226 HOTP | βœ… | βœ… |
| RFC 6238 TOTP | βœ… | βœ… |
| RFC 6287 OCRA | βœ… | ❌ |
| Built-in OCRA Suite Configs | βœ… | ❌ |
| Full RFC Test Vector Suite | βœ… | ❌ |
| Constant-Time Validation | βœ… | βœ… |
| Cross-platform Friendly | βœ… | βœ… |
| Zero Dependency Core | βœ… | ❌ (uses crypto/rand + external parsing) |

## πŸ“‘ Algorithm (RFC)

- [RFC 4226 / 6238](docs/rfc4226.md) proof algorithm
- [RFC 6287](docs/rfc6287.md) proof algorithm

## πŸ“š Usage

TOTP example

```go
package main

import (
"fmt"
"github.com/ja7ad/otp"
"log"
"time"
)

func main() {
secret, err := otp.RandomSecret(otp.SHA1)
if err != nil {
log.Fatal(err)
}

t := time.Now()

code, err := otp.GenerateTOTP(secret, t, otp.DefaultTOTPParam)
if err != nil {
log.Fatal(err)
}

fmt.Println(code)

ok, err := otp.ValidateTOTP(secret, code, t, otp.DefaultTOTPParam)
if err != nil {
log.Fatal(err)
}

if !ok {
log.Fatal("Invalid OTP")
}

url, err := otp.GenerateTOTPURL(otp.URLParam{
Issuer: "https://example.com",
Secret: secret,
AccountName: "foobar",
Period: otp.DefaultTOTPParam.Period,
Digits: otp.DefaultTOTPParam.Digits,
Algorithm: otp.DefaultTOTPParam.Algorithm,
})
if err != nil {
log.Fatal(err)
}

fmt.Println(url.String())
}
```

HOTP example code

```go
package main

import (
"fmt"
"github.com/ja7ad/otp"
"log"
)

func main() {
secret, err := otp.RandomSecret(otp.SHA1)
if err != nil {
log.Fatal(err)
}

counter := uint64(1)

code, err := otp.GenerateHOTP(secret, counter, otp.DefaultHOTPParam)
if err != nil {
log.Fatal(err)
}

fmt.Println(code)

ok, err := otp.ValidateHOTP(secret, code, counter, otp.DefaultHOTPParam)
if err != nil {
log.Fatal(err)
}

if !ok {
log.Fatal("Invalid OTP")
}

url, err := otp.GenerateHOTPURL(otp.URLParam{
Issuer: "https://example.com",
Secret: secret,
AccountName: "foobar",
Period: otp.DefaultHOTPParam.Period,
Digits: otp.DefaultHOTPParam.Digits,
Algorithm: otp.DefaultHOTPParam.Algorithm,
})
if err != nil {
log.Fatal(err)
}

fmt.Println(url.String())
}
```

OCRA example code

```go
package main

import (
"fmt"
"github.com/ja7ad/otp"
)

func main() {
secret, err := otp.RandomSecret(otp.SHA1)
if err != nil {
panic(err)
}

suite := otp.MustRawSuite("OCRA-1:HOTP-SHA1-6:QN08")

code, err := otp.GenerateOCRA(secret, suite, otp.OCRAInput{
Challenge: []byte("12345678"),
})

if err != nil {
panic(err)
}

ok, err := otp.ValidateOCRA(secret, code, suite, otp.OCRAInput{
Challenge: []byte("12345678"),
})
if err != nil {
panic(err)
}

fmt.Println(ok)
}
```

## 🀝 Contributing

We welcome contributions of all kinds β€” from fixing bugs and improving documentation to implementing new RFCs.

Please read our [Contributing Guide](CONTRIBUTING.md) to get started. It includes setup instructions, coding standards, and development workflows.

Whether you're filing an issue, submitting a pull request, or suggesting an improvement β€” thank you for helping make this library better! πŸ™Œ

## πŸ“– References

- [RFC 6287 - OCRA](https://datatracker.ietf.org/doc/html/rfc6287)
- [RFC 4226 - HOTP](https://datatracker.ietf.org/doc/html/rfc4226)
- [RFC 6238 - TOTP](https://datatracker.ietf.org/doc/html/rfc6238)