npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@shworx/otpkit

v0.1.3

Published

A TypeScript toolkit for OTP credential import, export, and interoperability.

Readme

OTPKit

NPM Version NPM License

OTPKit is a TypeScript/JavaScript toolkit for working with One-Time Password (OTP) credentials.

It provides a common representation for OTP accounts and codecs for importing and exporting credentials between different OTP formats.

Currently supported formats include:

  • OTPAuth URIs
  • Google Authenticator migration payloads

Features

  • TOTP support
  • HOTP support
  • OTPAuth URI parsing and generation
  • Google Authenticator migration payload parsing
  • Google Authenticator migration payload generation
  • Support for multiple Google Authenticator migration batches
  • RFC 4648 Base32 encoding and decoding
  • SHA-1, SHA-256 and SHA-512 algorithms
  • 6, 7 and 8 digit OTP configurations
  • Strong TypeScript typing
  • Format-independent OTPAccount representation
  • High-level OTPKit API
  • Direct codec access for advanced use cases
  • ES module based

Supported OTP Configuration

OTPKit represents an OTP credential using a common OTPAccount structure.

interface OTPAccount {
    readonly label: string;
    readonly issuer?: string;
    readonly secret: string;
    readonly otp: OTPOptions;
}

OTP options contain the OTP type and algorithm as well as the required parameters for TOTP or HOTP.

TOTP

const account: OTPAccount = {
    label: "[email protected]",
    issuer: "Example",
    secret: "JBSWY3DPEHPK3PXP",
    otp: {
        type: OTPType.TOTP,
        algorithm: OTPAlgorithm.SHA1,
        digits: 6,
        period: 30
    }
};

HOTP

const account: OTPAccount = {
    label: "Administrator",
    issuer: "Example",
    secret: "JBSWY3DPEHPK3PXP",
    otp: {
        type: OTPType.HOTP,
        algorithm: OTPAlgorithm.SHA1,
        digits: 6,
        counter: 0
    }
};

Installation

OTPKit can be installed from npm:

npm install otpkit

After installation, import the public API from the package:

import { OTPKit } from "otpkit";

OTPKit can also be used directly from a cloned repository when developing the library itself:

git clone https://github.com/shworx/otpkit.git
cd otpkit
npm install
npm run build

The compiled library and TypeScript declaration files are generated in the dist/ directory.


High-Level API

For most applications, the recommended entry point is OTPKit.

OTPKit provides a format-independent interface for encoding and decoding OTP credentials without requiring application code to instantiate individual codecs.

import { OTPKit } from "otpkit";

Decode an OTP Credential

OTPKit.decode() automatically determines the supported format and returns the corresponding OTP accounts.

import { OTPKit } from "otpkit";

const input =
    "otpauth://totp/Example:[email protected]?secret=JBSWY3DPEHPK3PXP&issuer=Example";

const accounts = OTPKit.decode(input);

console.log(accounts);

The same method can be used with a Google Authenticator migration URI:

import { OTPKit } from "otpkit";

const input =
    "otpauth-migration://offline?data=...";

const accounts = OTPKit.decode(input);

for (const account of accounts) {
    console.log(account.label);
    console.log(account.issuer);
}

The application therefore does not need to know whether the input is an OTPAuth URI or a Google migration URI.

OTPKit.decode() also accepts percent-encoded migration URIs, which is useful when the complete URI has been obtained from another URL-encoded source.

Note: Check examples/google-export-qrcode.html for a full working example of reading and decoding a Google Authenticator Export QR code.


Encode an OTP Credential

OTPKit.encode() can encode OTP accounts into a specified format.

import {
    OTPAlgorithm,
    OTPFormat,
    OTPKit,
    OTPType
} from "otpkit";

const account = {
    label: "[email protected]",
    issuer: "Example",
    secret: "JBSWY3DPEHPK3PXP",
    otp: {
        type: OTPType.TOTP,
        algorithm: OTPAlgorithm.SHA1,
        digits: 6,
        period: 30
    }
};

const uri = OTPKit.encode(
    [account],
    OTPFormat.OTP_AUTH
);

console.log(uri);

For formats that produce a single string, the result can be used directly.

Google Authenticator migration data may consist of multiple batches. For this reason, migration exports are represented separately when batch information is required.


Recommended Usage

For applications that primarily need OTP interoperability, the high-level API is generally the preferred approach:

import {
    OTPAlgorithm,
    OTPFormat,
    OTPKit,
    OTPType
} from "otpkit";

const account = {
    label: "[email protected]",
    issuer: "Example",
    secret: "JBSWY3DPEHPK3PXP",
    otp: {
        type: OTPType.TOTP,
        algorithm: OTPAlgorithm.SHA1,
        digits: 6,
        period: 30
    }
};

const otpAuthUri = OTPKit.encode(
    [account],
    OTPFormat.OTP_AUTH
);

const importedAccounts = OTPKit.decode(otpAuthUri);

console.log(importedAccounts);

Use the direct codecs when the application needs format-specific functionality or more control over the individual format.


JavaScript Usage

OTPKit is an ES module.

After installing the package:

import { OTPKit } from "otpkit";

For example:

import { OTPKit } from "otpkit";

const accounts = OTPKit.decode(
    "otpauth://totp/Example:[email protected]?secret=JBSWY3DPEHPK3PXP&issuer=Example"
);

console.log(accounts);

The individual codecs can also be imported directly:

import {
    GoogleMigrationCodec,
    OTPAuthCodec
} from "otpkit";

TypeScript Usage

OTPKit provides TypeScript declarations as part of the package.

Import the public API directly from the package:

import {
    OTPAccount,
    OTPAlgorithm,
    OTPFormat,
    OTPKit,
    OTPType
} from "otpkit";

Create an OTP Account

const account: OTPAccount = {
    label: "[email protected]",
    issuer: "Example",
    secret: "JBSWY3DPEHPK3PXP",
    otp: {
        type: OTPType.TOTP,
        algorithm: OTPAlgorithm.SHA1,
        digits: 6,
        period: 30
    }
};

Encode and Decode

const encoded = OTPKit.encode(
    [account],
    OTPFormat.OTP_AUTH
);

const decoded = OTPKit.decode(encoded);

console.log(decoded[0]);

Direct Codec Usage

OTPKit also exposes its codecs directly.

Direct codec access is useful when an application already knows which format it is working with or needs format-specific functionality.

The currently available codecs are:

  • OTPAuthCodec
  • GoogleMigrationCodec

OTPAuth Codec

OTPAuthCodec handles the standard otpauth:// URI format.

It supports both TOTP and HOTP credentials.

Decode

import { OTPAuthCodec } from "otpkit";

const codec = new OTPAuthCodec();

const accounts = codec.decode(
    "otpauth://totp/Example:[email protected]?secret=JBSWY3DPEHPK3PXP&issuer=Example"
);

const account = accounts[0]!;

console.log(account.label);
console.log(account.issuer);
console.log(account.secret);

Encode

const uri = codec.encode(account);

console.log(uri);

Google Authenticator Migration Codec

GoogleMigrationCodec handles Google Authenticator's migration format.

A migration payload is transported using the following URI scheme:

otpauth-migration://offline?data=<payload>

The payload contains a protobuf-encoded collection of OTP credentials.

Decode a Migration URI

import { GoogleMigrationCodec } from "otpkit";

const codec = new GoogleMigrationCodec();

const accounts = codec.decode(
    "otpauth-migration://offline?data=..."
);

for (const account of accounts) {
    console.log(account.label);
    console.log(account.issuer);
    console.log(account.secret);
}

The codec converts Google's migration representation into OTPKit's common OTPAccount representation.


Check Whether a Value Is Supported

Codecs expose a supports() method.

const codec = new GoogleMigrationCodec();

if (codec.supports(input)) {
    const accounts = codec.decode(input);

    console.log(accounts);
}

Invalid or unsupported migration data returns false from supports().


Google Migration Export

Google Authenticator migration data can also be generated from normal OTPAccount objects.

Export a Single Migration URI

import {
    GoogleMigrationCodec,
    OTPAlgorithm,
    OTPType
} from "otpkit";

const codec = new GoogleMigrationCodec();

const account = {
    label: "[email protected]",
    issuer: "Example",
    secret: "JBSWY3DPEHPK3PXP",
    otp: {
        type: OTPType.TOTP,
        algorithm: OTPAlgorithm.SHA1,
        digits: 6,
        period: 30
    }
};

const migrationUri = codec.encode([account]);

console.log(migrationUri);

The returned value is a complete migration URI:

otpauth-migration://offline?data=...

It can therefore be passed directly to a QR-code generator.


Multiple Migration Batches

Google Authenticator migration payloads have a maximum payload size.

When multiple accounts cannot fit into a single migration payload, OTPKit splits them into multiple batches.

For this use case, use encodeMigration().

const migrations = codec.encodeMigration(accounts);

for (const migration of migrations) {
    console.log(migration.batchIndex);
    console.log(migration.batchSize);
    console.log(migration.batchId);
    console.log(migration.data);
}

Each result is a MigrationExport:

interface MigrationExport {
    readonly data: string;
    readonly batchIndex: number;
    readonly batchSize: number;
    readonly batchId: number;
}

data contains the Base64-encoded protobuf payload.

The migration URI can be constructed from the exported data:

const uris = migrations.map(
    migration =>
        `otpauth-migration://offline?data=${migration.data}`
);

Each URI represents one migration batch.

The batchIndex, batchSize and batchId values allow the batches to be associated with the same migration operation.


Encode → Decode Round Trip

OTPKit can convert an account into a Google migration URI and recover the same account again.

Using the high-level API:

import {
    OTPAlgorithm,
    OTPFormat,
    OTPKit,
    OTPType
} from "otpkit";

const original = {
    label: "[email protected]",
    issuer: "Example",
    secret: "JBSWY3DPEHPK3PXP",
    otp: {
        type: OTPType.TOTP,
        algorithm: OTPAlgorithm.SHA1,
        digits: 6,
        period: 30
    }
};

const migrationUri = OTPKit.encode(
    [original],
    OTPFormat.GOOGLE_MIGRATION
);

const accounts = OTPKit.decode(migrationUri);

console.log(accounts[0]);

This makes OTPKit useful for applications that need to move OTP credentials between different applications or storage formats.


Base32

OTPKit includes an RFC 4648 Base32 implementation.

import { Base32 } from "otpkit";

Encode

const encoded = Base32.encode(
    new Uint8Array([72, 101, 108, 108, 111])
);

console.log(encoded);

The encoder returns uppercase Base32 without padding.

Decode

const decoded = Base32.decode("JBSWY3DPEHPK3PXP");

console.log(decoded);

The decoder accepts:

  • uppercase characters
  • lowercase characters
  • whitespace
  • hyphen separators
  • optional Base32 padding

OTP Algorithms

OTPKit currently supports:

OTPAlgorithm.SHA1
OTPAlgorithm.SHA256
OTPAlgorithm.SHA512

Example:

const account = {
    label: "[email protected]",
    secret: "JBSWY3DPEHPK3PXP",
    otp: {
        type: OTPType.TOTP,
        algorithm: OTPAlgorithm.SHA256,
        digits: 8,
        period: 30
    }
};

OTP Types

Two OTP types are currently supported:

OTPType.TOTP
OTPType.HOTP

TOTP accounts use a time period:

otp: {
    type: OTPType.TOTP,
    algorithm: OTPAlgorithm.SHA1,
    digits: 6,
    period: 30
}

HOTP accounts use a counter:

otp: {
    type: OTPType.HOTP,
    algorithm: OTPAlgorithm.SHA1,
    digits: 6,
    counter: 0
}

Validation

OTPKit validates OTP accounts before they are exported.

Validation includes:

  • non-empty labels
  • valid Base32 secrets
  • supported OTP types
  • supported algorithms
  • valid digit counts
  • valid TOTP periods
  • required HOTP counters
  • prohibition of TOTP counters
  • prohibition of HOTP periods

Invalid accounts result in an appropriate OTPKit error.


Error Handling

OTPKit provides dedicated error classes for common failure conditions.

Examples include:

InvalidBase32Error
InvalidOTPAccountError
InvalidOTPOptionsError
InvalidOTPURIError
OTPKitError
UnsupportedFormatError

Applications can catch specific errors when required:

try {
    const accounts = OTPKit.decode(input);
} catch (error) {
    if (error instanceof InvalidOTPURIError) {
        console.error("Invalid OTPAuth URI.");
    }
}

Public API

The package entry point exposes the public API:

import {
    OTPKit,
    OTPAccount,
    OTPAlgorithm,
    OTPFormat,
    OTPOptions,
    OTPType,
    OTPAuthCodec,
    GoogleMigrationCodec,
    Base32
} from "otpkit";

Migration-related public types include:

MigrationExport
MigrationOTPParameter
MigrationPayload

The high-level OTPKit API is intended for normal application usage.

Individual codecs are exposed for applications that need direct format-specific control.

Internal implementation classes such as migration parsers, migration writers and protobuf readers/writers are not required for normal library usage.


Building

When working from the source repository, build the library with:

npm run build

The generated files are placed in:

dist/

The build includes JavaScript modules and TypeScript declaration files.


Type Checking

Run TypeScript type checking without generating output:

npm run typecheck

Testing

OTPKit uses Vitest for its test suite.

Run all tests:

npm test

The test suite covers:

  • binary readers and writers
  • protobuf encoding and decoding
  • Base32 encoding and decoding
  • OTPAuth parsing and generation
  • Google migration parsing and generation
  • migration batching
  • OTP validation
  • error handling
  • public API behavior

Development

Clone the repository:

git clone https://github.com/shworx/otpkit.git
cd otpkit

Install dependencies:

npm install

Run the test suite:

npm test

Run type checking:

npm run typecheck

Build the library:

npm run build

Project Structure

The project is organized into functional modules:

src/
├── binary/
│   ├── BinaryReader.ts
│   ├── BinaryWriter.ts
│   └── Endianness.ts
├── codecs/
│   ├── Codec.ts
│   ├── GoogleMigrationCodec.ts
│   └── OTPAuthCodec.ts
├── core/
│   ├── OTPAccount.ts
│   ├── OTPAlgorithm.ts
│   ├── OTPFormat.ts
│   ├── OTPOptions.ts
│   └── OTPType.ts
├── errors/
├── migration/
│   ├── MigrationExport.ts
│   ├── MigrationOTPParameter.ts
│   ├── MigrationPayload.ts
│   ├── MigrationPayloadParser.ts
│   ├── MigrationPayloadWriter.ts
│   └── MigrationExporter.ts
├── protobuf/
├── utils/
│   └── Base32.ts
├── validation/
├── OTPKit.ts
└── index.ts

The architecture separates the common OTP model from individual credential formats.

This allows additional codecs to be added without changing the application's internal representation of an OTP account.


Design Goals

OTPKit is intended to provide a format-independent foundation for OTP credential interoperability.

The core concept is:

                         ┌─────────────────┐
                         │    OTPAccount   │
                         └────────┬────────┘
                                  │
                         ┌────────▼────────┐
                         │     OTPKit      │
                         └────────┬────────┘
                                  │
                    ┌─────────────┴─────────────┐
                    │                           │
             ┌──────▼──────┐            ┌──────▼────────────┐
             │ OTPAuthCodec│            │GoogleMigrationCodec│
             └──────┬──────┘            └──────┬────────────┘
                    │                           │
              otpauth://               otpauth-migration://

Applications can work with OTPAccount rather than directly with individual serialization formats.

This makes it possible to import an account from one format and export it into another format without coupling application code to either format.

For applications requiring format-specific functionality, the codecs remain directly accessible.


Current Limitations

OTPKit currently has the following limitations:

  • Google migration payloads may require multiple QR codes when many accounts are exported.
  • OTPKit handles credential representation and serialization; it does not generate OTP codes itself.

License

See LICENSE.md for license information.


Author

OTPKit is developed by SHWorX (Steffen Haase).