
Company News
Socket Joins New OpenJS Program to Fund Node.js Security Work
Socket is joining the OpenJS Security Stewardship Program to fund Node.js vulnerability research, maintainer remediation, and security releases.
@otplib/uri
Advanced tools
Parse and generate otpauth:// URIs for OTP account provisioning.
npm install @otplib/uri
pnpm add @otplib/uri
yarn add @otplib/uri
The @otplib/uri package provides utilities for working with otpauth:// URIs - the standard format for sharing OTP account information. These URIs are commonly used in QR codes for authenticator app setup.
otpauth://TYPE/LABEL?PARAMETERS
totp or hotpissuer:account or just accountsecret, issuer, algorithm, digits, period/counterExample:
otpauth://totp/GitHub:user@example.com?secret=GEZDGNBVGY3TQOJQGEZDGNBVGY&issuer=GitHub
import { parse } from "@otplib/uri";
const uri =
"otpauth://totp/GitHub:user@example.com?secret=GEZDGNBVGY3TQOJQGEZDGNBVGY&issuer=GitHub";
const result = parse(uri);
console.log(result);
// {
// type: 'totp',
// label: 'GitHub:user@example.com',
// params: {
// secret: 'GEZDGNBVGY3TQOJQGEZDGNBVGY',
// issuer: 'GitHub'
// }
// }
When a query parameter is repeated, otplib parses and validates only its first
occurrence, matching URLSearchParams.get(). Later occurrences are ignored
without decoding their values. A bare parameter such as algorithm counts as
the first occurrence with an empty value. The OTPAuth URI format does not define
duplicate-parameter behavior, so avoid duplicates when interoperability matters.
Parsing preserves optionality rather than materializing defaults: an absent,
bare, or empty algorithm parameter leaves params.algorithm undefined. OTP
consumers apply the SHA-1 default when they use the parsed result.
import { parse } from "@otplib/uri";
const uri = "otpauth://totp/ACME%20Corp:john@example.com?secret=GEZDGNBVGY3TQOJQGEZDGNBVGY";
const { label, params } = parse(uri);
// Split label to get issuer and account
const [issuer, account] = label.includes(":") ? label.split(":") : [params.issuer, label];
console.log("Issuer:", issuer); // 'ACME Corp'
console.log("Account:", account); // 'john@example.com'
console.log("Secret:", params.secret);
import {
parse,
URIParseError,
InvalidURIError,
MissingParameterError,
InvalidParameterError,
} from "@otplib/uri";
try {
const result = parse("invalid-uri");
} catch (error) {
if (error instanceof InvalidURIError) {
console.error("Not a valid otpauth:// URI");
} else if (error instanceof MissingParameterError) {
console.error("Missing required parameter (e.g., secret)");
} else if (error instanceof InvalidParameterError) {
console.error("Invalid parameter value");
}
}
import { generateTOTP } from "@otplib/uri";
const uri = generateTOTP({
issuer: "ACME Corp",
label: "john@example.com",
secret: "GEZDGNBVGY3TQOJQGEZDGNBVGY",
});
console.log(uri);
// 'otpauth://totp/ACME%20Corp:john%40example.com?secret=GEZDGNBVGY3TQOJQGEZDGNBVGY&issuer=ACME%20Corp'
import { generateTOTP } from "@otplib/uri";
const uri = generateTOTP({
issuer: "GitHub",
label: "user@github.com",
secret: "GEZDGNBVGY3TQOJQGEZDGNBVGY",
algorithm: "sha256", // Non-default algorithm
digits: 8, // 8-digit tokens
period: 60, // 60-second period
});
import { generateHOTP } from "@otplib/uri";
const uri = generateHOTP({
issuer: "MyApp",
label: "user123",
secret: "GEZDGNBVGY3TQOJQGEZDGNBVGY",
counter: 0, // Starting counter
});
console.log(uri);
// 'otpauth://hotp/MyApp:user123?secret=GEZDGNBVGY3TQOJQGEZDGNBVGY&issuer=MyApp&counter=0'
For more control, use the generate function directly:
import { generate } from "@otplib/uri";
const uri = generate({
type: "totp",
label: "CustomApp:user@example.com",
params: {
secret: "GEZDGNBVGY3TQOJQGEZDGNBVGY",
issuer: "CustomApp",
algorithm: "sha1",
digits: 6,
period: 30,
},
});
[!WARNING] For the widest Google Authenticator interoperability, use the standard defaults:
sha1algorithm6digits30second period for TOTP- Issuer should be included in both label and parameter
Some authenticator versions ignore the algorithm, digits, or period parameter, so non-default values may not be honored.
import { generateTOTP } from "@otplib/uri";
// This URI uses the widely interoperable defaults
const uri = generateTOTP({
issuer: "MyService",
label: "user@example.com",
secret: "GEZDGNBVGY3TQOJQGEZDGNBVGY",
// algorithm: 'sha1', // Default, compatible
// digits: 6, // Default, compatible
// period: 30, // Default, compatible
});
Generate a QR code for the URI using any QR library:
import { generateTOTP } from "@otplib/uri";
import QRCode from "qrcode"; // Example library
const uri = generateTOTP({
issuer: "MyApp",
label: "user@example.com",
secret: "GEZDGNBVGY3TQOJQGEZDGNBVGY",
});
// Generate QR code as data URL
const qrDataUrl = await QRCode.toDataURL(uri);
// Or generate as SVG
const qrSvg = await QRCode.toString(uri, { type: "svg" });
Full documentation available at otplib.yeojz.dev:
FAQs
otpauth:// URI parsing and generation for otplib
The npm package @otplib/uri receives a total of 873,030 weekly downloads. As such, @otplib/uri popularity was classified as popular.
We found that @otplib/uri demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Company News
Socket is joining the OpenJS Security Stewardship Program to fund Node.js vulnerability research, maintainer remediation, and security releases.

Security News
Two compromised GitHub Actions were re-enabled with malicious tags intact, exposing thousands of downstream repositories to Mini Shai-Hulud.

Research
/Security News
A malicious Firefox extension fetches its payload after installation to evade detection, steal Google session cookies, and automate account takeover.