Skip to main content
Any Framework

A command-line tool to create and manage one-time passwords (TOTP and HOTP).

Published
Jul 5, 2026
3mo ago
Total Downloads
261
261

Install

dotnet add package Mjcheetham.Otp.Tool --version 0.2.0

No framework information available.

README

otp

build Mjcheetham.Otp.Tool Mjcheetham.Otp

Create and manage one-time passwords (TOTP and HOTP) from the command line β€” plus a small .NET library to do the same in your own apps.

otp generates the same time-based (TOTP) and counter-based (HOTP) one-time passwords used by authenticator apps. It stores your accounts locally, prints current codes, and imports/exports the standard otpauth:// format β€” including scannable QR codes.

Features

  • TOTP & HOTP β€” RFC 6238 time-based and RFC 4226 counter-based codes.
  • Hash-agile β€” SHA-1, SHA-256, and SHA-512, with configurable digit count and time period.
  • Import & export β€” read and write otpauth:// URIs and render QR codes.
  • Interactive or scriptable β€” guided prompts on a terminal; --format json or -z (NUL-delimited) for scripts.
  • Secure storage β€” accounts kept in your OS keychain by default (macOS Keychain, Windows Credential Manager, or Linux Secret Service), or a plaintext file; selectable with otp config.
  • Two distribution channels β€” a cross-platform dotnet tool and self-contained native binaries.
  • Reusable library β€” the Mjcheetham.Otp package exposes the same engine.

Install

As a .NET tool

Requires the .NET SDK:

dotnet tool install --global Mjcheetham.Otp.Tool

Invoke it as otp, and update with dotnet tool update --global Mjcheetham.Otp.Tool.

As a native binary (no .NET required)

Download the archive for your platform from the latest release, extract it, and put otp on your PATH. Binaries are published for:

OS Architectures
Linux x64, arm64, arm
macOS x64 (Intel), arm64 (Apple silicon)
Windows x64, arm64

Quick start

# Add a time-based (TOTP) account from its Base32 secret
otp add github --secret JBSWY3DPEHPK3PXP --issuer GitHub

# ...or import an otpauth:// URI (e.g. decoded from a QR code)
otp add --uri "otpauth://totp/GitHub:[email protected]?secret=JBSWY3DPEHPK3PXP&issuer=GitHub"

# ...or just run `add` on a terminal for guided prompts
otp add

# Generate the current code ('code' is an alias for 'get')
otp get github
otp code github

# List, inspect (secret masked by default), and remove
otp list
otp show github
otp remove github

Usage

Run otp --help or otp <command> --help for full details; otp --version prints the version.

Command Aliases Description
add Add an account from options, an otpauth:// URI, or interactively.
get code Generate the current code for a stored account.
list ls List stored accounts.
show Show an account's details, otpauth:// URI, or QR code.
remove rm Remove a stored account.
config View and edit configuration (e.g. the storage backend).

add

otp add <name> [options]
otp add --uri <otpauth://...>
otp add --interactive
Option Description Default
<name> Label to store the account under (unless --uri).
--secret, -s Shared secret, Base32-encoded (unless --uri).
--type, -t totp (time-based) or hotp (counter-based). totp
--issuer Issuer / provider name.
--digits, -d Number of digits in the code. 6
--period, -p Time step in seconds (TOTP only). 30
--counter, -c Initial counter value (HOTP only). 0
--algorithm, -a sha1, sha256, or sha512. sha1
--uri Import from an otpauth:// URI (excludes the options above).
--interactive, -i Prompt for each field.

Running otp add with no arguments on an interactive terminal starts the guided prompts automatically.

get (alias code)

otp get <name> [--counter <n>] [--format text|json|nul] [-z]

Prints the current code. For TOTP accounts the human view also shows how long the code stays valid. --counter generates a single HOTP code at a specific counter without advancing the stored value.

list (alias ls)

otp list [--type totp|hotp] [--format text|json|nul] [-z]

show

otp show <name> [--show-secret] [--uri | --qr] [--format text|json|nul] [-z]

The secret is masked (β€’β€’β€’β€’β€’β€’β€’β€’) by default.

Option Description
--show-secret Reveal the secret (and the secret embedded in the URI).
--uri Print only the otpauth:// URI (contains the secret β€” for backup).
--qr Print the otpauth:// URI as a QR code to scan into another app.

remove (alias rm)

otp remove <name> [--yes]

Prompts for confirmation on a terminal; pass --yes/-y to skip (required when input is not a terminal).

Output formats

Commands that emit data (get, list, show) accept --format/-f:

  • text β€” human-readable (default), coloured when the terminal supports it.
  • json β€” a single compact JSON value, ideal for jq and friends.
  • nul β€” NUL-delimited records in the style of git … -z; -z is shorthand.
otp show github --format json | jq .type
otp list -z | xargs -0 -n1 otp get

Storage

otp keeps your accounts in one of several backends:

Backend Where
auto (default) The current OS's native store below, otherwise plaintext.
keychain macOS Keychain.
wincred Windows Credential Manager.
secretservice Linux Secret Service (GNOME Keyring, KWallet, …) via libsecret.
plaintext A single JSON file (see below).

Choose one with otp config:

otp config set store.backend keychain    # auto | plaintext | keychain | wincred | secretservice

The plaintext backend keeps accounts in a single JSON file:

  • Default: ~/.otp/store.json β€” the directory is created 0700, the file 0600.
  • Override the location with the OTP_STORE environment variable.

The plaintext backend stores secrets unencrypted. Rely on filesystem permissions (as otp does) and/or full-disk encryption, or use one of the native keychain backends.

Switching backends does not move existing accounts between them.

Configuration

Configuration lives in ~/.otp/config.json (override with OTP_CONFIG). Manage it with otp config:

otp config list                        # show configured values
otp config get store.backend           # print a value (defaults to 'auto')
otp config set store.backend keychain  # set a value
otp config unset store.backend         # revert to the default
otp config edit                        # open the file in $VISUAL / $EDITOR
Key Values Default
store.backend auto, plaintext, keychain, wincred, secretservice auto

Environment variables

Variable Effect
OTP_STORE_BACKEND Storage backend override (takes precedence over the config).
OTP_CONFIG Path to the config file (default ~/.otp/config.json).
OTP_STORE Path to the plaintext store file (default ~/.otp/store.json).
NO_COLOR Disable coloured output.
NO_ANSI Disable ANSI escape sequences entirely.

Library

Install the Mjcheetham.Otp package to generate codes in your own .NET app:

dotnet add package Mjcheetham.Otp
using Mjcheetham.Otp;

// Build a TOTP from a Base32 secret and generate the current code.
byte[] secret = Base32.Decode("JBSWY3DPEHPK3PXP");
var totp = new TimeBasedOtp("GitHub", secret, period: 30, digits: 6, algorithm: OtpAlgorithm.Sha1);
string code = totp.GetCode();

// Counter-based (HOTP): generate the code for a specific counter.
var hotp = new HmacOtp("Backup", secret);
string next = hotp.GetCode(counter: 42);

// Parse and format the standard otpauth:// URI.
IOneTimePassword imported = OtpAuthUri.Parse(
    "otpauth://totp/GitHub:[email protected]?secret=JBSWY3DPEHPK3PXP&issuer=GitHub");
string uri = OtpAuthUri.Format(imported);

// Persist accounts in the same file store the CLI uses.
IOtpStore store = new FileOtpStore(FileOtpStore.GetDefaultPath());
await store.AddAsync(totp);

The library targets .NET 10, is trim-/AOT-compatible, and ships a .snupkg symbol package.

Building from source

Requires the .NET SDK pinned in global.json.

dotnet build                              # build the solution
dotnet run --project src/otp -- --help    # run the CLI
dotnet publish src/otp -c Release -r <rid>  # native AOT binary for a runtime

The root VERSION file is the single source of truth for the major.minor.patch number: local builds report <VERSION>-dev+<sha>, and a release is cut by pushing a tag that matches VERSION.

Standards

License

MIT Β© Matthew John Cheetham

Changes from Previous Version

No structural changes between v0.1.0 and v0.2.0.

Adoption Assessment

Assess this package against its supported frameworks, license, maintenance signals and dependency graph before making it a project standard.

No target framework metadata is available. Confirm compatibility in a representative project before standardising on this package.

Related Guides & Workflows

Learn how to evaluate, integrate, or audit this package in your .NET project.