/** * otpauth:// URI parser — the inverse of `keyuri`. * * Reads the standard Key URI Format shared by Google Authenticator, Authy, * 1Password, etc., so you can import a secret a user pastes/scans back in. * Pure string work — no crypto, no network — so it runs anywhere `keyuri` does. */ interface ParsedOtpauthUri { /** `totp` (time-based) or `hotp` (counter-based). */ type: "totp" | "hotp"; /** Account label (issuer prefix stripped), e.g. the user's email. */ label: string; /** Issuer / app name, if present. */ issuer?: string; /** Base32 shared secret. */ secret: string; /** Normalised HMAC hash — always `SHA-1` | `SHA-256` | `SHA-512`. */ algorithm: OtpAlgorithm; /** Number of digits in the code. */ digits: number; /** Time step in seconds (totp only). */ period?: number; /** Moving counter (hotp only). */ counter?: number; } /** * Parse an `otpauth://` provisioning URI into its parts. Throws if the URI is * not a valid `otpauth://totp|hotp/...` string with a `secret`. Round-trips * with {@link keyuri}. */ declare function parseOtpauthUri(uri: string): ParsedOtpauthUri; /** * Recovery / backup codes — an options-object API on top of the same idea as * {@link generateBackupCodes}, with configurable count, length and format, and * a verify helper that reports the remaining (unused) hashes so callers can * persist single-use semantics in one step. * * Codes are cryptographically random (Web Crypto CSPRNG); only SHA-256 hashes * are ever stored. Self-contained — no crypto helpers leak into the public API. */ /** How the visible characters of a recovery code are drawn. */ type RecoveryCodeFormat = "alphanumeric" | "numeric" | "hex"; interface RecoveryCodesOptions { /** How many codes to generate (default 10). */ count?: number; /** Number of dash-separated groups per code (default 2). */ groups?: number; /** Characters per group (default 5). */ groupLength?: number; /** Character set — `alphanumeric` (default), `numeric` or `hex`. */ format?: RecoveryCodeFormat; /** Group separator (default `-`). */ separator?: string; } interface RecoveryCodesResult { /** Show these to the user ONCE. */ codes: string[]; /** Store THESE (SHA-256 hex hashes) — verify against them, mark used. */ hashes: string[]; } /** * Generate a set of single-use recovery codes. Returns the plaintext `codes` * (show the user once) and their SHA-256 `hashes` (persist these). Every call * yields fresh, cryptographically-random codes. */ declare function generateRecoveryCodes(opts?: RecoveryCodesOptions): Promise; interface RecoveryCodeVerification { /** Did the code match an unused hash? */ ok: boolean; /** Index of the matched hash in the supplied set, or -1. */ index: number; /** The stored set with the used hash removed — persist this. Unchanged on miss. */ remaining: string[]; } /** * Verify a recovery code against a stored set of SHA-256 hashes and consume it. * On a match returns `ok: true`, the matched `index`, and `remaining` (the set * minus the used hash) — persist `remaining` to enforce single use. On no match * returns `ok: false`, `index: -1`, and the original set untouched. */ declare function verifyRecoveryCode(code: string, hashedSet: string[]): Promise; /** * @lacspace/otp * TOTP & HOTP two-factor auth — Google Authenticator compatible. * * Generate secrets, compute and verify time-based (TOTP) and counter-based * (HOTP) one-time codes, and build the `otpauth://` URI you turn into a QR code. * Built on the Web Crypto API, so it runs on Node 18+, edge runtimes and the * browser alike. * * Zero dependencies · isomorphic · fully typed. */ type OtpAlgorithm = "SHA-1" | "SHA-256" | "SHA-512"; interface OtpOptions { /** Number of digits in the code (default 6). */ digits?: number; /** HMAC hash (default SHA-1 — what authenticator apps use). */ algorithm?: OtpAlgorithm; } interface TotpOptions extends OtpOptions { /** Time step in seconds (default 30). */ period?: number; /** Override "now" (ms since epoch) — for testing. */ timestamp?: number; } /** Encode bytes to RFC 4648 base32 (no padding). */ declare function base32Encode(bytes: Uint8Array): string; /** Decode an RFC 4648 base32 string (padding and spaces tolerated). */ declare function base32Decode(input: string): Uint8Array; /** Generate a random base32 secret (default 20 bytes / 160 bits). */ declare function generateSecret(bytes?: number): string; /** Compute an HOTP code for a given counter. */ declare function hotp(secret: string, counter: number, opts?: OtpOptions): Promise; /** Compute the current TOTP code. */ declare function totp(secret: string, opts?: TotpOptions): Promise; /** Seconds remaining before the current TOTP code rolls over. */ declare function timeRemaining(opts?: TotpOptions): number; /** * Verify a TOTP token, tolerating clock drift of ±`window` periods (default 1). * @returns the matched step offset (0 = current, ±1 = adjacent), or null if no match. */ declare function verifyTotp(token: string, secret: string, opts?: TotpOptions & { window?: number; }): Promise; /** * Verify an HOTP token, scanning forward up to `window` counters (default 0). * @returns the matched counter, or null if no match. */ declare function verifyHotp(token: string, secret: string, counter: number, opts?: OtpOptions & { window?: number; }): Promise; interface KeyUriInput extends OtpOptions { secret: string; /** Account label, e.g. the user's email. */ label: string; /** Issuer / app name shown in the authenticator. */ issuer?: string; period?: number; type?: "totp" | "hotp"; /** Required for hotp. */ counter?: number; } /** * Build an `otpauth://` URI — feed it to a QR code generator so users can scan * it into Google Authenticator, Authy, 1Password, etc. */ declare function keyuri(o: KeyUriInput): string; /** * Verify a TOTP token AND reject replays: pass the last accepted step * (`lastStep`); a code at or before it is refused even if otherwise valid. * @returns the matched step (persist it as the new `lastStep`), or null. */ declare function verifyTotpOnce(token: string, secret: string, lastStep: number | null | undefined, opts?: TotpOptions & { window?: number; }): Promise; interface SetupTotpInput { /** Account label, e.g. the user's email. */ account: string; /** Issuer / app name shown in the authenticator. */ issuer?: string; /** Secret length in bytes (default 20). */ bytes?: number; digits?: number; period?: number; algorithm?: OtpAlgorithm; } interface TotpSetup { /** Store this (encrypted) against the user. */ secret: string; /** `otpauth://…` — render as a QR code (any QR lib) for the user to scan. */ uri: string; } /** One-call TOTP enrollment: a fresh secret + the `otpauth://` URI to show as a QR. */ declare function setupTotp(input: SetupTotpInput): TotpSetup; interface BackupCodesResult { /** Show these to the user ONCE. */ codes: string[]; /** Store THESE (SHA-256 hashes) — verify against them, mark used. */ hashes: string[]; } /** Generate single-use recovery codes: show `codes` once, persist `hashes`. */ declare function generateBackupCodes(count?: number, opts?: { groups?: number; groupLength?: number; }): Promise; /** * Verify a backup code against stored hashes (single-use). Returns the index of * the matched hash (remove/mark it used), or -1 if none match. */ declare function verifyBackupCode(code: string, hashes: string[]): Promise; export { type BackupCodesResult, type KeyUriInput, type OtpAlgorithm, type OtpOptions, type ParsedOtpauthUri, type RecoveryCodeFormat, type RecoveryCodeVerification, type RecoveryCodesOptions, type RecoveryCodesResult, type SetupTotpInput, type TotpOptions, type TotpSetup, base32Decode, base32Encode, generateBackupCodes, generateRecoveryCodes, generateSecret, hotp, keyuri, parseOtpauthUri, setupTotp, timeRemaining, totp, verifyBackupCode, verifyHotp, verifyRecoveryCode, verifyTotp, verifyTotpOnce };