or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

authenticator.mdconfiguration.mdhotp.mdindex.mdpresets.mdtotp.md

hotp.mddocs/

0

# HOTP (HMAC-based One-Time Password)

1

2

HOTP implements RFC 4226 counter-based one-time passwords. Unlike time-based systems, HOTP uses an incrementing counter that must be synchronized between client and server.

3

4

## Capabilities

5

6

### Token Generation

7

8

Generates tokens based on a secret key and counter value.

9

10

```typescript { .api }

11

/**

12

* Generate an HOTP token using secret and counter

13

* @param secret - Secret key in the configured encoding

14

* @param counter - Counter value (must be synchronized)

15

* @returns Token string with configured digit length

16

*/

17

generate(secret: string, counter: number): string;

18

```

19

20

**Usage Example:**

21

22

```typescript

23

import { hotp } from "otplib";

24

25

const secret = "your-secret-key";

26

let counter = 0;

27

28

// Generate tokens with incrementing counter

29

const token1 = hotp.generate(secret, counter++);

30

const token2 = hotp.generate(secret, counter++);

31

const token3 = hotp.generate(secret, counter++);

32

33

console.log(token1); // "123456"

34

console.log(token2); // "789012"

35

console.log(token3); // "345678"

36

37

// Configure custom options

38

hotp.options = { digits: 8, algorithm: 'sha256' };

39

const longToken = hotp.generate(secret, counter++);

40

console.log(longToken); // "12345678"

41

```

42

43

### Token Verification

44

45

Verifies tokens against a specific counter value. The counter must match exactly.

46

47

```typescript { .api }

48

/**

49

* Verify an HOTP token against secret and counter

50

* @param token - Token to verify

51

* @param secret - Secret key

52

* @param counter - Expected counter value

53

* @returns true if token matches the generated token for this counter

54

*/

55

check(token: string, secret: string, counter: number): boolean;

56

57

/**

58

* Object-based token verification

59

* @param opts - Object containing token, secret, and counter

60

* @returns true if token is valid for the given counter

61

*/

62

verify(opts: { token: string; secret: string; counter: number }): boolean;

63

```

64

65

**Usage Examples:**

66

67

```typescript

68

import { hotp } from "otplib";

69

70

const secret = "your-secret-key";

71

const counter = 5;

72

const token = "123456";

73

74

// Method 1: Direct parameters

75

const isValid = hotp.check(token, secret, counter);

76

77

// Method 2: Object parameters

78

const isValid2 = hotp.verify({ token, secret, counter });

79

80

console.log(isValid); // true or false

81

82

// Counter synchronization example

83

let serverCounter = 0;

84

let maxLookAhead = 10;

85

86

function verifyHotpWithSync(token: string, secret: string): boolean {

87

// Try current counter and look ahead

88

for (let i = 0; i <= maxLookAhead; i++) {

89

if (hotp.check(token, secret, serverCounter + i)) {

90

serverCounter = serverCounter + i + 1; // Update for next token

91

return true;

92

}

93

}

94

return false;

95

}

96

```

97

98

### QR Code URI Generation

99

100

Generate otpauth:// URIs for HOTP setup with counter information.

101

102

```typescript { .api }

103

/**

104

* Generate an otpauth URI for HOTP setup

105

* @param accountName - User identifier

106

* @param issuer - Service name

107

* @param secret - Secret key

108

* @param counter - Initial counter value

109

* @returns otpauth://hotp/ URI string

110

*/

111

keyuri(accountName: string, issuer: string, secret: string, counter: number): string;

112

```

113

114

**Usage Example:**

115

116

```typescript

117

import { hotp } from "otplib";

118

119

const secret = "your-secret-key";

120

const user = "user@example.com";

121

const service = "My Service";

122

const initialCounter = 0;

123

124

const otpauth = hotp.keyuri(user, service, secret, initialCounter);

125

console.log(otpauth);

126

// "otpauth://hotp/My%20Service:user@example.com?secret=your-secret-key&counter=0&issuer=My%20Service"

127

```

128

129

### Configuration Management

130

131

Manage HOTP-specific configuration options.

132

133

```typescript { .api }

134

/**

135

* Get/set configuration options

136

*/

137

options: Partial<HOTPOptions>;

138

139

/**

140

* Reset options to default values

141

*/

142

resetOptions(): void;

143

144

/**

145

* Get all options with defaults applied

146

* @returns Complete options object

147

*/

148

allOptions(): Readonly<HOTPOptions>;

149

150

/**

151

* Create new instance with custom defaults

152

* @param defaultOptions - Custom default options

153

* @returns New HOTP instance

154

*/

155

create(defaultOptions?: Partial<HOTPOptions>): HOTP;

156

```

157

158

**Usage Examples:**

159

160

```typescript

161

import { hotp } from "otplib";

162

163

// Configure options

164

hotp.options = {

165

digits: 8, // 8-digit tokens

166

algorithm: 'sha256', // SHA-256 HMAC

167

encoding: 'hex' // Hex-encoded secrets

168

};

169

170

// Create instance with custom defaults

171

const customHotp = hotp.create({

172

digits: 6,

173

algorithm: 'sha1',

174

encoding: 'ascii'

175

});

176

177

// Reset to library defaults

178

hotp.resetOptions();

179

180

// View complete configuration

181

const config = hotp.allOptions();

182

console.log(config.digits); // 6

183

console.log(config.algorithm); // 'sha1'

184

```

185

186

## Counter Management Patterns

187

188

### Simple Counter Tracking

189

190

```typescript

191

import { hotp } from "otplib";

192

193

class HotpService {

194

private counters = new Map<string, number>();

195

196

generateToken(userId: string, secret: string): string {

197

const counter = this.getCounter(userId);

198

const token = hotp.generate(secret, counter);

199

this.incrementCounter(userId);

200

return token;

201

}

202

203

verifyToken(userId: string, secret: string, token: string): boolean {

204

const counter = this.getCounter(userId);

205

return hotp.check(token, secret, counter);

206

}

207

208

private getCounter(userId: string): number {

209

return this.counters.get(userId) || 0;

210

}

211

212

private incrementCounter(userId: string): void {

213

const current = this.getCounter(userId);

214

this.counters.set(userId, current + 1);

215

}

216

}

217

```

218

219

### Counter Synchronization with Look-ahead

220

221

```typescript

222

import { hotp } from "otplib";

223

224

class HotpSyncService {

225

private counters = new Map<string, number>();

226

private readonly LOOK_AHEAD_WINDOW = 10;

227

228

verifyTokenWithSync(userId: string, secret: string, token: string): boolean {

229

const baseCounter = this.getCounter(userId);

230

231

// Try current counter and look ahead

232

for (let i = 0; i <= this.LOOK_AHEAD_WINDOW; i++) {

233

const testCounter = baseCounter + i;

234

if (hotp.check(token, secret, testCounter)) {

235

// Update counter to one past the successful counter

236

this.setCounter(userId, testCounter + 1);

237

return true;

238

}

239

}

240

241

return false;

242

}

243

244

private getCounter(userId: string): number {

245

return this.counters.get(userId) || 0;

246

}

247

248

private setCounter(userId: string, counter: number): void {

249

this.counters.set(userId, counter);

250

}

251

}

252

```

253

254

### Hardware Token Simulation

255

256

```typescript

257

import { hotp } from "otplib";

258

259

class HardwareTokenSimulator {

260

private counter: number = 0;

261

262

constructor(private secret: string) {}

263

264

// Simulate pressing the button on a hardware token

265

pressButton(): string {

266

const token = hotp.generate(this.secret, this.counter);

267

this.counter++;

268

return token;

269

}

270

271

// Reset counter (usually requires physical reset)

272

resetCounter(newCounter: number = 0): void {

273

this.counter = newCounter;

274

}

275

276

getCurrentCounter(): number {

277

return this.counter;

278

}

279

}

280

281

// Usage

282

const token = new HardwareTokenSimulator("shared-secret");

283

const firstToken = token.pressButton(); // Uses counter 0

284

const secondToken = token.pressButton(); // Uses counter 1

285

```

286

287

## Types

288

289

```typescript { .api }

290

interface HOTPOptions {

291

/** HMAC algorithm to use */

292

algorithm: 'sha1' | 'sha256' | 'sha512';

293

/** Number of digits in generated token */

294

digits: number;

295

/** Encoding format of the secret key */

296

encoding: 'ascii' | 'base64' | 'hex' | 'latin1' | 'utf8';

297

/** Function to create HMAC digest */

298

createDigest: (algorithm: string, key: string, data: string) => string;

299

/** Function to create HMAC key from secret */

300

createHmacKey: (algorithm: string, secret: string, encoding: string) => string;

301

/** Pre-computed digest (advanced usage) */

302

digest?: string;

303

}

304

```