@alessiofrittoli/crypto-otp
Version:
Lightweight TypeScript HOTP/TOTP library
245 lines (242 loc) • 9 kB
text/typescript
import { Algo } from '@alessiofrittoli/crypto-algorithm/types';
/**
* One-Time Password (OTP) namespace.
*
* Includes types and interfaces for HOTP (RFC 4226) and TOTP (RFC 6238) authentication.
*
* [RFC 4226 - IETF](https://datatracker.ietf.org/doc/html/rfc4226)
*
* [RFC 6238 - IETF](https://datatracker.ietf.org/doc/html/rfc6238)
*/
declare namespace OTP {
/**
* The OTP type: either counter-based (HOTP) or time-based (TOTP).
*
*/
type Type = 'hotp' | 'totp';
/**
* The number of digits in a generated OTP token.
*
* Typical values are 6 (default), 7, or 8.
*/
type Digits = 6 | 7 | 8;
/**
* A one-time password (OTP) token string.
*
* Typically a numeric string of the specified length.
*/
type Token = string;
/**
* Supported encodings for the secret key.
*
* These define how the key is serialized before being decoded into bytes.
*/
type Encoding = 'ascii' | 'hex' | 'base64url' | 'base32';
/**
* Secret key configuration used in OTP generation.
*
*/
interface Secret {
/**
* The secret key as a string, encoded using the specified encoding.
*
*/
key: string;
/**
* The encoding used to interpret the secret key string.
*
* @default 'hex'
*/
encoding?: OTP.Encoding;
/**
* The hash algorithm used for HMAC generation.
*
* Defaults to SHA-1 for compatibility with
* [RFC 4226](https://datatracker.ietf.org/doc/html/rfc4226) and [RFC 6238](https://datatracker.ietf.org/doc/html/rfc6238),
* but SHA-256 and SHA-512 are also supported.
*
* @default 'SHA-1'
*/
algorithm?: Algo.Hash;
}
/**
* A mapping of secret keys in all supported encoding formats.
*
*/
type Secrets = Record<OTP.Encoding, string>;
/**
* Options for creating an OTP Auth URI (`otpauth://`) used in QR codes or OTP apps.
*
* Format reference:
*
* @link https://github.com/google/google-authenticator/wiki/Key-Uri-Format
* @link https://docs.yubico.com/yesdk/users-manual/application-oath/uri-string-format.html
*/
type AuthURLOptions<T extends Type = 'hotp'> = OTP.GenericOptions & ({
/**
* The label is used to identify which account a key is associated with.
*
* It contains an account name, which is automatically URI-encoded, optionally prefixed by an issuer string
* identifying the provider or service managing that account.
* This issuer prefix can be used to prevent collisions between different accounts with different providers that might be
* identified using the same account name, e.g. the user's email address.
*
* The issuer prefix and account name should be separated by a literal colon,
* and optional spaces may precede the account name.
* Neither issuer nor account name may themselves contain a colon.
* Represented in ABNF according to [RFC 5234](https://datatracker.ietf.org/doc/html/rfc5234).
*
* Valid values might include `Example:alice@gmail.com`, `Provider1:Alice%20Smith` or `Big%20Corporation%3A%20alice%40bigco.com`.
*
* ⚠️ The label is now automatically URI-encoded since version 3.0.0.
*/
label: string;
/**
* The OTP issuer.
*
* The issuer parameter is an optional but recommended string value indicating the provider or service the credential is associated with.
* It is URL-encoded according to [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986).
* If the issuer parameter is absent, issuer information may be taken from the issuer prefix of the label.
*
* Valid values corresponding to the label prefix would be: `issuer=Example`, `issuer=Provider1`, and `issuer=Big%20Corporation`.
*/
issuer?: string;
} & (T extends 'hotp' ? {
/** The OTP type needed to distinguish whether the key will be used for counter-based HOTP or for TOTP. */
type: 'hotp';
/** The HOTP counter. */
counter: number;
} : {
/** The OTP type needed to distinguish whether the key will be used for counter-based HOTP or for TOTP. */
type: 'totp';
} & Pick<TOTP.CounterOptions, 'period'>));
/**
* Base options shared across HOTP and TOTP configurations.
*
*/
interface GenericOptions {
/**
* The shared secret key and associated encoding/algorithm.
*
*/
secret: OTP.Secret;
/**
* Number of digits for the generated OTP token.
*
* @default 6
*/
digits?: OTP.Digits;
}
/**
* Options used to retrieve the secret in multiple encoding formats.
*
*/
type GetSecretsOptions = Pick<OTP.GenericOptions, 'secret'>;
/**
* HOTP (HMAC-based One-Time Password) specific types.
*
* [RFC 4226 - IETF](https://datatracker.ietf.org/doc/html/rfc4226).
*/
namespace HOTP {
/**
* Defines the options required to generate a HOTP token.
*
*/
interface GetTokenOptions extends GenericOptions {
/**
* The counter value used in HOTP generation.
*
*/
counter?: number;
}
/**
* Options for verifying a HOTP token and determining the delta from a given counter.
*
*/
interface GetDeltaOptions extends GetTokenOptions {
/**
* The HOTP token to verify.
*
*/
token: Token;
/**
* The number of counter values to check ahead of the expected counter during HOTP token verification.
*
* This accounts for possible counter desynchronization between the client and server, as described in
* [RFC 4226, section 7.2](https://datatracker.ietf.org/doc/html/rfc4226#section-7.2).
*
* For example, if the current counter is 100 and `window` is set to 10, the verification logic will check
* counters from 100 to 110 (inclusive).
*
* A larger window improves tolerance but increases the risk of token reuse and brute-force attacks.
*
* [RFC 4226 - IETF](https://datatracker.ietf.org/doc/html/rfc4226#section-7.2)
*
* @default 0
*/
window?: number;
}
}
/**
* TOTP (Time-based One-Time Password) specific types.
*
* [RFC 6238 - IETF](https://datatracker.ietf.org/doc/html/rfc6238).
*/
namespace TOTP {
/**
* Defines a period that a TOTP code will be valid for, in seconds.
*
*/
type Period = 15 | 30 | 60;
/**
* Options used to calculate the TOTP time-step counter.
*
*/
interface CounterOptions {
/**
* Defines a period that a TOTP code will be valid for, in seconds.
*
* @default 30
*/
period?: TOTP.Period;
/**
* Time in seconds used to calculate the counter value.
*
* @default Date.now() / 1000
*/
time?: number;
/**
* Initial time since the UNIX epoch from which to calculate the counter value.
*
* @default 0 // (no offset)
*/
epoch?: number;
}
/**
* Defines the options required to generate a TOTP token.
*
*/
type GetTokenOptions = Omit<HOTP.GetTokenOptions, 'counter'> & TOTP.CounterOptions;
/**
* Options for verifying a TOTP token and determining the time-step delta.
*
*/
interface GetDeltaOptions extends TOTP.GetTokenOptions, Omit<HOTP.GetDeltaOptions, 'counter'> {
/**
* The number of time-step counter values to check before and after the expected counter during TOTP token verification.
*
* This helps accommodate clock drift or time synchronization issues between client and server, as recommended in
* [RFC 6238, section 5.2](https://datatracker.ietf.org/doc/html/rfc6238#section-5.2).
*
* For example, if `window = 1`, the algorithm will check the passcode for the current time step, the previous one,
* and the next one (i.e. `counter - 1` to `counter + 1`).
*
* [RFC 6238 - IETF](https://datatracker.ietf.org/doc/html/rfc6238#section-5.2)
*
* @default 0
*/
window?: number;
}
}
}
export { OTP };