Quick start
Use raw bytes when you already own the secret material. Direct class API string secrets are Base64.
import { TOTP } from "@gottheflag/otp";
const secret = new TextEncoder().encode("development-secret");
const otp = new TOTP({
secret,
account: "alice@example.com",
issuer: "Example",
});
try {
const code = otp.generate();
} finally {
otp.destroy();
secret.fill(0);
}
HOTP
import { HOTP } from "@gottheflag/otp";
const otp = new HOTP({
secret,
account: "alice@example.com",
counter: 0n,
});
const code = otp.generate();
otp.counter += 1n;
Secret formats and ownership are explicit
Canonical Base64. It is decoded into bytes owned by the OTP instance because JavaScript strings cannot be securely borrowed or wiped.
Raw secret bytes are borrowed by reference with no persistent copy. The caller owns and wipes the buffer.
Standard Base32. A valid parsed instance owns the single decoded byte buffer and can wipe it with destroy().
Wipes owned secret bytes, releases borrowed references without modifying them, and permanently disables secret-dependent operations.
Parse authenticator URIs
OTP.parse() reports URI problems as diagnostics instead of turning ordinary malformed input into exceptions.
import { OTP } from "@gottheflag/otp";
const parsed = OTP.parse(uri);
if (parsed.valid) {
try {
console.log(parsed.generate());
console.log(String(parsed));
} finally {
parsed.destroy();
}
} else {
console.log(parsed.diagnostics);
}
Strict mode
Normal parsing keeps recoverable non-standard fields as warnings. Strict mode promotes those conditions to errors.
const parsed = OTP.parse(uri, { strict: true });
console.log(parsed.valid);
console.log(parsed.diagnostics);
Object state is the source of truth
Parsed instances are normal mutable HOTP or TOTP objects. Serialization reflects the current values, not a stale copy of the original URI.
const parsed = OTP.parse(uri);
if (parsed.valid) {
parsed.account = "bob@example.com";
parsed.issuer = "New Example";
parsed.digits = 8;
const updatedURI = String(parsed);
}
Supported settings
| Setting | Support / default |
|---|---|
| Algorithms | SHA1, SHA256, SHA512 |
| Digits | 6, 7, 8 · default 6 |
| TOTP period | Positive integer seconds · default 30 |
| HOTP counter | Unsigned 64-bit bigint · required |
| TOTP timestamp | Milliseconds since Unix epoch |
The implementation is tested against RFC 4226, RFC 6238, RFC 4648 Base32 vectors, and HMAC reference vectors.
Security
- Treat OTP secrets and complete secret-bearing
otpauth://URIs as credentials. - Do not log, paste into bug reports, or commit real secrets.
- Prefer
Uint8Arraywhen your application should control the secret buffer lifetime explicitly. Uint8Arrayinputs are borrowed without a persistent copy. Callsecret.fill(0)yourself when finished.- Call
destroy()for OTP instances that own decoded secret material, including parsed URIs and Base64 string secrets. - JavaScript cannot guarantee perfect secure-memory erasure, but the package avoids unnecessary persistent byte copies and wipes owned buffers explicitly.
- The parser preserves diagnostics so applications can make their own acceptance decisions.
- Report vulnerabilities privately through SECURITY.md.