@authcraft/totp-js 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +329 -0
- package/dist/index.d.mts +140 -0
- package/dist/index.d.ts +140 -0
- package/dist/index.js +461 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +418 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +67 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Pratiyush Kumar Singh
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
<img src=".github/assets/logo.png" alt="totp-js logo" width="200">
|
|
4
|
+
|
|
5
|
+
# totp-js
|
|
6
|
+
|
|
7
|
+
**Security-hardened TOTP/2FA library for JavaScript and TypeScript**
|
|
8
|
+
|
|
9
|
+
[](https://www.npmjs.com/package/totp-js)
|
|
10
|
+
[](https://github.com/Pratiyush/totp-js/actions)
|
|
11
|
+
[](https://codecov.io/gh/Pratiyush/totp-js)
|
|
12
|
+
[](https://www.npmjs.com/package/totp-js)
|
|
13
|
+
[](LICENSE)
|
|
14
|
+
[](CONTRIBUTING.md)
|
|
15
|
+
|
|
16
|
+
RFC 6238 (TOTP) and RFC 4226 (HOTP) compliant. Zero runtime dependencies.
|
|
17
|
+
Built-in replay protection. Constant-time verification. Works with Node.js 18+.
|
|
18
|
+
|
|
19
|
+
[Documentation](https://pratiyush.github.io/totp-js/) | [npm](https://www.npmjs.com/package/totp-js) | [API Reference](#api-reference)
|
|
20
|
+
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Why totp-js?
|
|
26
|
+
|
|
27
|
+
Most TOTP libraries give you the basics — generate a code, verify it. But production 2FA needs more:
|
|
28
|
+
|
|
29
|
+
- **Replay protection** — prevent the same code from being used twice
|
|
30
|
+
- **Constant-time verification** — prevent timing attacks that leak information
|
|
31
|
+
- **Secure defaults** — preset configurations so you don't need to be a cryptography expert
|
|
32
|
+
- **Zero dependencies** — no supply chain risk for your authentication layer
|
|
33
|
+
|
|
34
|
+
totp-js is the TypeScript counterpart to [totp-impl](https://github.com/Pratiyush/totp-impl) (Java), sharing the same security-first API design.
|
|
35
|
+
|
|
36
|
+
## Install
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# npm
|
|
40
|
+
npm install totp-js
|
|
41
|
+
|
|
42
|
+
# yarn
|
|
43
|
+
yarn add totp-js
|
|
44
|
+
|
|
45
|
+
# pnpm
|
|
46
|
+
pnpm add totp-js
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Quick Start
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
import { TOTP, generateSecret } from 'totp-js';
|
|
53
|
+
|
|
54
|
+
// Generate a secret for the user
|
|
55
|
+
const secret = generateSecret();
|
|
56
|
+
|
|
57
|
+
// Create a TOTP instance
|
|
58
|
+
const totp = TOTP.defaultInstance();
|
|
59
|
+
|
|
60
|
+
// Generate a code
|
|
61
|
+
const code = totp.generate(secret);
|
|
62
|
+
console.log(code); // "482915"
|
|
63
|
+
|
|
64
|
+
// Verify a code
|
|
65
|
+
const isValid = totp.verify(secret, code);
|
|
66
|
+
console.log(isValid); // true
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Replay Protection
|
|
70
|
+
|
|
71
|
+
Prevent the same OTP from being used twice within its validity window:
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
import { TOTP, generateSecret, InMemoryReplayGuard } from 'totp-js';
|
|
75
|
+
|
|
76
|
+
const guard = InMemoryReplayGuard.withDefaultRetention();
|
|
77
|
+
const totp = TOTP.create({ replayGuard: guard });
|
|
78
|
+
const secret = generateSecret();
|
|
79
|
+
|
|
80
|
+
const code = totp.generate(secret);
|
|
81
|
+
|
|
82
|
+
// First verification — passes
|
|
83
|
+
totp.verify(secret, code, 'user-123'); // true
|
|
84
|
+
|
|
85
|
+
// Same code, same user — blocked!
|
|
86
|
+
totp.verify(secret, code, 'user-123'); // false (replay detected)
|
|
87
|
+
|
|
88
|
+
// Don't forget to clean up when done
|
|
89
|
+
guard.destroy();
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## QR Code URI
|
|
93
|
+
|
|
94
|
+
Generate `otpauth://` URIs for QR code scanning with Google Authenticator, Authy, etc.:
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
import { buildOtpauthUri, generateSecret } from 'totp-js';
|
|
98
|
+
|
|
99
|
+
const secret = generateSecret();
|
|
100
|
+
const uri = buildOtpauthUri(secret, 'user@example.com', 'MyApp');
|
|
101
|
+
// otpauth://totp/MyApp%3Auser%40example.com?secret=...&issuer=MyApp&algorithm=SHA1&digits=6&period=30
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Configuration
|
|
105
|
+
|
|
106
|
+
### Preset Configurations
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
import { TOTP, defaultConfig, sha256Config, highSecurityConfig } from 'totp-js';
|
|
110
|
+
|
|
111
|
+
// Default: SHA1, 6 digits, 30s period, drift ±1
|
|
112
|
+
const standard = TOTP.create({ ...defaultConfig() });
|
|
113
|
+
|
|
114
|
+
// SHA-256: recommended for new deployments
|
|
115
|
+
const sha256 = TOTP.create({ ...sha256Config() });
|
|
116
|
+
|
|
117
|
+
// High security: SHA-512, 8 digits
|
|
118
|
+
const highSec = TOTP.create({ ...highSecurityConfig() });
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Custom Configuration
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
import { TOTP, Algorithm } from 'totp-js';
|
|
125
|
+
|
|
126
|
+
const totp = TOTP.create({
|
|
127
|
+
algorithm: Algorithm.SHA256,
|
|
128
|
+
digits: 8,
|
|
129
|
+
period: 60, // 60-second window
|
|
130
|
+
allowedDrift: 2, // accept codes ±2 periods
|
|
131
|
+
});
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Configuration Constraints
|
|
135
|
+
|
|
136
|
+
| Parameter | Min | Max | Default |
|
|
137
|
+
|-----------|-----|-----|---------|
|
|
138
|
+
| `period` | 15s | 120s | 30s |
|
|
139
|
+
| `digits` | 6 | 8 | 6 |
|
|
140
|
+
| `allowedDrift` | 0 | 5 | 1 |
|
|
141
|
+
|
|
142
|
+
## Detailed Verification
|
|
143
|
+
|
|
144
|
+
Get more context about verification results:
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
const result = totp.verifyWithDetails(secret, code);
|
|
148
|
+
console.log(result);
|
|
149
|
+
// { valid: true, timeOffset: 0, message: 'Valid' }
|
|
150
|
+
// { valid: false, timeOffset: 0, message: 'Invalid code' }
|
|
151
|
+
// { valid: false, timeOffset: 1, message: 'Code already used' }
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Framework Integration
|
|
155
|
+
|
|
156
|
+
### Express.js
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
import express from 'express';
|
|
160
|
+
import { TOTP, generateSecret, InMemoryReplayGuard, buildOtpauthUri } from 'totp-js';
|
|
161
|
+
|
|
162
|
+
const app = express();
|
|
163
|
+
app.use(express.json());
|
|
164
|
+
|
|
165
|
+
const guard = InMemoryReplayGuard.withDefaultRetention();
|
|
166
|
+
const totp = TOTP.create({ replayGuard: guard });
|
|
167
|
+
|
|
168
|
+
// Setup 2FA for a user
|
|
169
|
+
app.post('/2fa/setup', (req, res) => {
|
|
170
|
+
const secret = generateSecret();
|
|
171
|
+
const uri = buildOtpauthUri(secret, req.body.email, 'MyApp');
|
|
172
|
+
// Store secret in your database
|
|
173
|
+
res.json({ secret, qrUri: uri });
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
// Verify 2FA code
|
|
177
|
+
app.post('/2fa/verify', (req, res) => {
|
|
178
|
+
const { userId, code, secret } = req.body;
|
|
179
|
+
const isValid = totp.verify(secret, code, userId);
|
|
180
|
+
res.json({ valid: isValid });
|
|
181
|
+
});
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Next.js API Route
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
// app/api/2fa/verify/route.ts
|
|
188
|
+
import { NextResponse } from 'next/server';
|
|
189
|
+
import { TOTP, InMemoryReplayGuard } from 'totp-js';
|
|
190
|
+
|
|
191
|
+
const guard = InMemoryReplayGuard.withDefaultRetention();
|
|
192
|
+
const totp = TOTP.create({ replayGuard: guard });
|
|
193
|
+
|
|
194
|
+
export async function POST(request: Request) {
|
|
195
|
+
const { secret, code, userId } = await request.json();
|
|
196
|
+
const isValid = totp.verify(secret, code, userId);
|
|
197
|
+
return NextResponse.json({ valid: isValid });
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### NestJS
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
import { Injectable } from '@nestjs/common';
|
|
205
|
+
import { TOTP, generateSecret, InMemoryReplayGuard, buildOtpauthUri } from 'totp-js';
|
|
206
|
+
|
|
207
|
+
@Injectable()
|
|
208
|
+
export class TwoFactorService {
|
|
209
|
+
private readonly totp: TOTP;
|
|
210
|
+
private readonly guard: InMemoryReplayGuard;
|
|
211
|
+
|
|
212
|
+
constructor() {
|
|
213
|
+
this.guard = InMemoryReplayGuard.withDefaultRetention();
|
|
214
|
+
this.totp = TOTP.create({ replayGuard: this.guard });
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
setup(email: string) {
|
|
218
|
+
const secret = generateSecret();
|
|
219
|
+
const uri = buildOtpauthUri(secret, email, 'MyApp');
|
|
220
|
+
return { secret, qrUri: uri };
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
verify(secret: string, code: string, userId: string): boolean {
|
|
224
|
+
return this.totp.verify(secret, code, userId);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Fastify
|
|
230
|
+
|
|
231
|
+
```typescript
|
|
232
|
+
import Fastify from 'fastify';
|
|
233
|
+
import { TOTP, generateSecret, InMemoryReplayGuard } from 'totp-js';
|
|
234
|
+
|
|
235
|
+
const app = Fastify();
|
|
236
|
+
const guard = InMemoryReplayGuard.withDefaultRetention();
|
|
237
|
+
const totp = TOTP.create({ replayGuard: guard });
|
|
238
|
+
|
|
239
|
+
app.post('/2fa/verify', async (request, reply) => {
|
|
240
|
+
const { secret, code, userId } = request.body as any;
|
|
241
|
+
const isValid = totp.verify(secret, code, userId);
|
|
242
|
+
return { valid: isValid };
|
|
243
|
+
});
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## Secret Generation
|
|
247
|
+
|
|
248
|
+
```typescript
|
|
249
|
+
import { generateSecret, generateRawSecret, isValidSecret, Algorithm } from 'totp-js';
|
|
250
|
+
|
|
251
|
+
// Default (SHA1, 20 bytes)
|
|
252
|
+
const secret = generateSecret();
|
|
253
|
+
|
|
254
|
+
// Algorithm-appropriate size
|
|
255
|
+
const sha256Secret = generateSecret(Algorithm.SHA256); // 32 bytes
|
|
256
|
+
const sha512Secret = generateSecret(Algorithm.SHA512); // 64 bytes
|
|
257
|
+
|
|
258
|
+
// Raw bytes for custom encoding
|
|
259
|
+
const rawBytes = generateRawSecret(32);
|
|
260
|
+
|
|
261
|
+
// Validate existing secrets
|
|
262
|
+
isValidSecret(secret); // true
|
|
263
|
+
isValidSecret('abc'); // false (too short)
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## API Reference
|
|
267
|
+
|
|
268
|
+
### TOTP
|
|
269
|
+
|
|
270
|
+
| Method | Description |
|
|
271
|
+
|--------|-------------|
|
|
272
|
+
| `TOTP.create(options?)` | Create with custom options |
|
|
273
|
+
| `TOTP.defaultInstance()` | Create with defaults (SHA1, 6 digits, 30s) |
|
|
274
|
+
| `generate(secret)` | Generate code for current time |
|
|
275
|
+
| `generateAt(secret, timestamp)` | Generate code for specific timestamp (ms) |
|
|
276
|
+
| `generateForCounter(secret, counter)` | Generate code for specific counter |
|
|
277
|
+
| `verify(secret, code, userId?)` | Verify code (with optional replay guard) |
|
|
278
|
+
| `verifyWithDetails(secret, code, userId?)` | Verify with detailed result |
|
|
279
|
+
| `getCurrentCounter()` | Get current time counter |
|
|
280
|
+
| `getSecondsRemaining()` | Seconds until next code |
|
|
281
|
+
|
|
282
|
+
### Configuration
|
|
283
|
+
|
|
284
|
+
| Preset | Algorithm | Digits | Period | Drift |
|
|
285
|
+
|--------|-----------|--------|--------|-------|
|
|
286
|
+
| `defaultConfig()` | SHA-1 | 6 | 30s | ±1 |
|
|
287
|
+
| `sha256Config()` | SHA-256 | 6 | 30s | ±1 |
|
|
288
|
+
| `highSecurityConfig()` | SHA-512 | 8 | 30s | ±1 |
|
|
289
|
+
|
|
290
|
+
### Algorithm Support
|
|
291
|
+
|
|
292
|
+
| Algorithm | Key Size | Recommended For |
|
|
293
|
+
|-----------|----------|-----------------|
|
|
294
|
+
| SHA-1 | 20 bytes | Legacy compatibility (Google Authenticator default) |
|
|
295
|
+
| SHA-256 | 32 bytes | New deployments (recommended) |
|
|
296
|
+
| SHA-512 | 64 bytes | Maximum security |
|
|
297
|
+
|
|
298
|
+
## Security Features
|
|
299
|
+
|
|
300
|
+
- **Constant-time comparison** using `crypto.timingSafeEqual()` — prevents timing attacks
|
|
301
|
+
- **Replay protection** via `InMemoryReplayGuard` — prevents code reuse
|
|
302
|
+
- **Secret validation** — enforces minimum 128-bit entropy (16 bytes)
|
|
303
|
+
- **No sensitive data in errors** — error messages never contain secrets or codes
|
|
304
|
+
- **Zero runtime dependencies** — minimized attack surface
|
|
305
|
+
|
|
306
|
+
## Building from Source
|
|
307
|
+
|
|
308
|
+
```bash
|
|
309
|
+
git clone https://github.com/Pratiyush/totp-js.git
|
|
310
|
+
cd totp-js
|
|
311
|
+
npm install
|
|
312
|
+
npm run build
|
|
313
|
+
npm test
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
## Links
|
|
317
|
+
|
|
318
|
+
- [Documentation](https://pratiyush.github.io/totp-js/) — GitHub Pages with interactive demo
|
|
319
|
+
- [npm](https://www.npmjs.com/package/totp-js) — `npm install totp-js`
|
|
320
|
+
- [GitHub](https://github.com/Pratiyush/totp-js) — Source code, issues, PRs
|
|
321
|
+
- [totp-impl](https://github.com/Pratiyush/totp-impl) — Java counterpart ([Maven Central](https://central.sonatype.com/artifact/io.github.pratiyush/totp-lib))
|
|
322
|
+
|
|
323
|
+
## Contributing
|
|
324
|
+
|
|
325
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
326
|
+
|
|
327
|
+
## License
|
|
328
|
+
|
|
329
|
+
[MIT](LICENSE) — Pratiyush Kumar Singh
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Supported HMAC algorithms for TOTP generation.
|
|
3
|
+
*/
|
|
4
|
+
interface AlgorithmDef {
|
|
5
|
+
readonly name: string;
|
|
6
|
+
readonly jcaName: string;
|
|
7
|
+
readonly recommendedKeyBytes: number;
|
|
8
|
+
readonly otpauthName: string;
|
|
9
|
+
}
|
|
10
|
+
declare const Algorithm: {
|
|
11
|
+
readonly SHA1: {
|
|
12
|
+
readonly name: "SHA1";
|
|
13
|
+
readonly jcaName: "HmacSHA1";
|
|
14
|
+
readonly recommendedKeyBytes: 20;
|
|
15
|
+
readonly otpauthName: "SHA1";
|
|
16
|
+
};
|
|
17
|
+
readonly SHA256: {
|
|
18
|
+
readonly name: "SHA256";
|
|
19
|
+
readonly jcaName: "HmacSHA256";
|
|
20
|
+
readonly recommendedKeyBytes: 32;
|
|
21
|
+
readonly otpauthName: "SHA256";
|
|
22
|
+
};
|
|
23
|
+
readonly SHA512: {
|
|
24
|
+
readonly name: "SHA512";
|
|
25
|
+
readonly jcaName: "HmacSHA512";
|
|
26
|
+
readonly recommendedKeyBytes: 64;
|
|
27
|
+
readonly otpauthName: "SHA512";
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
type AlgorithmKey = keyof typeof Algorithm;
|
|
31
|
+
type AlgorithmValue = (typeof Algorithm)[AlgorithmKey];
|
|
32
|
+
declare function algorithmFromName(name: string): AlgorithmValue;
|
|
33
|
+
declare function recommendedSecretLength(algo: AlgorithmValue): number;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Immutable TOTP configuration.
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
interface TOTPConfig {
|
|
40
|
+
readonly algorithm: AlgorithmValue;
|
|
41
|
+
readonly digits: number;
|
|
42
|
+
readonly period: number;
|
|
43
|
+
readonly allowedDrift: number;
|
|
44
|
+
}
|
|
45
|
+
declare function defaultConfig(): TOTPConfig;
|
|
46
|
+
declare function sha256Config(): TOTPConfig;
|
|
47
|
+
declare function highSecurityConfig(): TOTPConfig;
|
|
48
|
+
declare function createConfig(options?: Partial<TOTPConfig>): TOTPConfig;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Replay attack prevention for TOTP codes.
|
|
52
|
+
*/
|
|
53
|
+
interface ReplayGuard {
|
|
54
|
+
markUsed(key: string): boolean;
|
|
55
|
+
wasUsed(key: string): boolean;
|
|
56
|
+
clear(): void;
|
|
57
|
+
size(): number;
|
|
58
|
+
}
|
|
59
|
+
declare class InMemoryReplayGuard implements ReplayGuard {
|
|
60
|
+
private readonly usedCodes;
|
|
61
|
+
private readonly retentionMs;
|
|
62
|
+
private cleanupTimer;
|
|
63
|
+
constructor(retentionMs?: number);
|
|
64
|
+
static withDefaultRetention(): InMemoryReplayGuard;
|
|
65
|
+
static forConfig(config: {
|
|
66
|
+
period: number;
|
|
67
|
+
allowedDrift: number;
|
|
68
|
+
}): InMemoryReplayGuard;
|
|
69
|
+
markUsed(key: string): boolean;
|
|
70
|
+
wasUsed(key: string): boolean;
|
|
71
|
+
clear(): void;
|
|
72
|
+
size(): number;
|
|
73
|
+
destroy(): void;
|
|
74
|
+
private cleanup;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
interface VerificationResult {
|
|
78
|
+
readonly valid: boolean;
|
|
79
|
+
readonly timeOffset: number;
|
|
80
|
+
readonly message: string;
|
|
81
|
+
}
|
|
82
|
+
interface TOTPOptions {
|
|
83
|
+
algorithm?: AlgorithmValue;
|
|
84
|
+
digits?: number;
|
|
85
|
+
period?: number;
|
|
86
|
+
allowedDrift?: number;
|
|
87
|
+
replayGuard?: ReplayGuard;
|
|
88
|
+
clock?: () => number;
|
|
89
|
+
}
|
|
90
|
+
declare class TOTP {
|
|
91
|
+
readonly config: TOTPConfig;
|
|
92
|
+
private readonly replayGuard;
|
|
93
|
+
private readonly clock;
|
|
94
|
+
private constructor();
|
|
95
|
+
static create(options?: TOTPOptions): TOTP;
|
|
96
|
+
static defaultInstance(): TOTP;
|
|
97
|
+
generate(base32Secret: string): string;
|
|
98
|
+
generateAt(base32Secret: string, timestamp: number): string;
|
|
99
|
+
generateForCounter(base32Secret: string, counter: number): string;
|
|
100
|
+
verify(base32Secret: string, code: string, userId?: string): boolean;
|
|
101
|
+
verifyWithDetails(base32Secret: string, code: string, userId?: string): VerificationResult;
|
|
102
|
+
getCurrentCounter(): number;
|
|
103
|
+
getSecondsRemaining(): number;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
declare function generateSecret(algo?: AlgorithmValue): string;
|
|
107
|
+
declare function generateSecretBytes(lengthBytes?: number): string;
|
|
108
|
+
declare function generateRawSecret(lengthBytes?: number): Uint8Array;
|
|
109
|
+
declare function isValidSecret(base32Secret: string): boolean;
|
|
110
|
+
declare function entropyBits(base32Length: number): number;
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Structured error types for totp-js.
|
|
114
|
+
*/
|
|
115
|
+
declare enum ErrorCode {
|
|
116
|
+
INVALID_SECRET = "INVALID_SECRET",
|
|
117
|
+
INVALID_CODE = "INVALID_CODE",
|
|
118
|
+
INVALID_CONFIG = "INVALID_CONFIG",
|
|
119
|
+
HMAC_ERROR = "HMAC_ERROR",
|
|
120
|
+
QR_GENERATION_ERROR = "QR_GENERATION_ERROR",
|
|
121
|
+
INTERNAL_ERROR = "INTERNAL_ERROR"
|
|
122
|
+
}
|
|
123
|
+
declare class TOTPError extends Error {
|
|
124
|
+
readonly code: ErrorCode;
|
|
125
|
+
constructor(code: ErrorCode, message: string, cause?: Error);
|
|
126
|
+
static invalidSecret(reason: string): TOTPError;
|
|
127
|
+
static invalidCode(reason: string): TOTPError;
|
|
128
|
+
static invalidConfig(reason: string): TOTPError;
|
|
129
|
+
static hmacError(cause: Error): TOTPError;
|
|
130
|
+
static internalError(message: string, cause?: Error): TOTPError;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* OTPAuth URI builder for QR code generation.
|
|
135
|
+
* Follows the otpauth:// URI format used by Google Authenticator and other apps.
|
|
136
|
+
*/
|
|
137
|
+
|
|
138
|
+
declare function buildOtpauthUri(secret: string, account: string, issuer: string, config?: TOTPConfig): string;
|
|
139
|
+
|
|
140
|
+
export { Algorithm, type AlgorithmDef, type AlgorithmKey, type AlgorithmValue, ErrorCode, InMemoryReplayGuard, type ReplayGuard, TOTP, type TOTPConfig, TOTPError, type TOTPOptions, type VerificationResult, algorithmFromName, buildOtpauthUri, createConfig, defaultConfig, entropyBits, generateRawSecret, generateSecret, generateSecretBytes, highSecurityConfig, isValidSecret, recommendedSecretLength, sha256Config };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Supported HMAC algorithms for TOTP generation.
|
|
3
|
+
*/
|
|
4
|
+
interface AlgorithmDef {
|
|
5
|
+
readonly name: string;
|
|
6
|
+
readonly jcaName: string;
|
|
7
|
+
readonly recommendedKeyBytes: number;
|
|
8
|
+
readonly otpauthName: string;
|
|
9
|
+
}
|
|
10
|
+
declare const Algorithm: {
|
|
11
|
+
readonly SHA1: {
|
|
12
|
+
readonly name: "SHA1";
|
|
13
|
+
readonly jcaName: "HmacSHA1";
|
|
14
|
+
readonly recommendedKeyBytes: 20;
|
|
15
|
+
readonly otpauthName: "SHA1";
|
|
16
|
+
};
|
|
17
|
+
readonly SHA256: {
|
|
18
|
+
readonly name: "SHA256";
|
|
19
|
+
readonly jcaName: "HmacSHA256";
|
|
20
|
+
readonly recommendedKeyBytes: 32;
|
|
21
|
+
readonly otpauthName: "SHA256";
|
|
22
|
+
};
|
|
23
|
+
readonly SHA512: {
|
|
24
|
+
readonly name: "SHA512";
|
|
25
|
+
readonly jcaName: "HmacSHA512";
|
|
26
|
+
readonly recommendedKeyBytes: 64;
|
|
27
|
+
readonly otpauthName: "SHA512";
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
type AlgorithmKey = keyof typeof Algorithm;
|
|
31
|
+
type AlgorithmValue = (typeof Algorithm)[AlgorithmKey];
|
|
32
|
+
declare function algorithmFromName(name: string): AlgorithmValue;
|
|
33
|
+
declare function recommendedSecretLength(algo: AlgorithmValue): number;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Immutable TOTP configuration.
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
interface TOTPConfig {
|
|
40
|
+
readonly algorithm: AlgorithmValue;
|
|
41
|
+
readonly digits: number;
|
|
42
|
+
readonly period: number;
|
|
43
|
+
readonly allowedDrift: number;
|
|
44
|
+
}
|
|
45
|
+
declare function defaultConfig(): TOTPConfig;
|
|
46
|
+
declare function sha256Config(): TOTPConfig;
|
|
47
|
+
declare function highSecurityConfig(): TOTPConfig;
|
|
48
|
+
declare function createConfig(options?: Partial<TOTPConfig>): TOTPConfig;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Replay attack prevention for TOTP codes.
|
|
52
|
+
*/
|
|
53
|
+
interface ReplayGuard {
|
|
54
|
+
markUsed(key: string): boolean;
|
|
55
|
+
wasUsed(key: string): boolean;
|
|
56
|
+
clear(): void;
|
|
57
|
+
size(): number;
|
|
58
|
+
}
|
|
59
|
+
declare class InMemoryReplayGuard implements ReplayGuard {
|
|
60
|
+
private readonly usedCodes;
|
|
61
|
+
private readonly retentionMs;
|
|
62
|
+
private cleanupTimer;
|
|
63
|
+
constructor(retentionMs?: number);
|
|
64
|
+
static withDefaultRetention(): InMemoryReplayGuard;
|
|
65
|
+
static forConfig(config: {
|
|
66
|
+
period: number;
|
|
67
|
+
allowedDrift: number;
|
|
68
|
+
}): InMemoryReplayGuard;
|
|
69
|
+
markUsed(key: string): boolean;
|
|
70
|
+
wasUsed(key: string): boolean;
|
|
71
|
+
clear(): void;
|
|
72
|
+
size(): number;
|
|
73
|
+
destroy(): void;
|
|
74
|
+
private cleanup;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
interface VerificationResult {
|
|
78
|
+
readonly valid: boolean;
|
|
79
|
+
readonly timeOffset: number;
|
|
80
|
+
readonly message: string;
|
|
81
|
+
}
|
|
82
|
+
interface TOTPOptions {
|
|
83
|
+
algorithm?: AlgorithmValue;
|
|
84
|
+
digits?: number;
|
|
85
|
+
period?: number;
|
|
86
|
+
allowedDrift?: number;
|
|
87
|
+
replayGuard?: ReplayGuard;
|
|
88
|
+
clock?: () => number;
|
|
89
|
+
}
|
|
90
|
+
declare class TOTP {
|
|
91
|
+
readonly config: TOTPConfig;
|
|
92
|
+
private readonly replayGuard;
|
|
93
|
+
private readonly clock;
|
|
94
|
+
private constructor();
|
|
95
|
+
static create(options?: TOTPOptions): TOTP;
|
|
96
|
+
static defaultInstance(): TOTP;
|
|
97
|
+
generate(base32Secret: string): string;
|
|
98
|
+
generateAt(base32Secret: string, timestamp: number): string;
|
|
99
|
+
generateForCounter(base32Secret: string, counter: number): string;
|
|
100
|
+
verify(base32Secret: string, code: string, userId?: string): boolean;
|
|
101
|
+
verifyWithDetails(base32Secret: string, code: string, userId?: string): VerificationResult;
|
|
102
|
+
getCurrentCounter(): number;
|
|
103
|
+
getSecondsRemaining(): number;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
declare function generateSecret(algo?: AlgorithmValue): string;
|
|
107
|
+
declare function generateSecretBytes(lengthBytes?: number): string;
|
|
108
|
+
declare function generateRawSecret(lengthBytes?: number): Uint8Array;
|
|
109
|
+
declare function isValidSecret(base32Secret: string): boolean;
|
|
110
|
+
declare function entropyBits(base32Length: number): number;
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Structured error types for totp-js.
|
|
114
|
+
*/
|
|
115
|
+
declare enum ErrorCode {
|
|
116
|
+
INVALID_SECRET = "INVALID_SECRET",
|
|
117
|
+
INVALID_CODE = "INVALID_CODE",
|
|
118
|
+
INVALID_CONFIG = "INVALID_CONFIG",
|
|
119
|
+
HMAC_ERROR = "HMAC_ERROR",
|
|
120
|
+
QR_GENERATION_ERROR = "QR_GENERATION_ERROR",
|
|
121
|
+
INTERNAL_ERROR = "INTERNAL_ERROR"
|
|
122
|
+
}
|
|
123
|
+
declare class TOTPError extends Error {
|
|
124
|
+
readonly code: ErrorCode;
|
|
125
|
+
constructor(code: ErrorCode, message: string, cause?: Error);
|
|
126
|
+
static invalidSecret(reason: string): TOTPError;
|
|
127
|
+
static invalidCode(reason: string): TOTPError;
|
|
128
|
+
static invalidConfig(reason: string): TOTPError;
|
|
129
|
+
static hmacError(cause: Error): TOTPError;
|
|
130
|
+
static internalError(message: string, cause?: Error): TOTPError;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* OTPAuth URI builder for QR code generation.
|
|
135
|
+
* Follows the otpauth:// URI format used by Google Authenticator and other apps.
|
|
136
|
+
*/
|
|
137
|
+
|
|
138
|
+
declare function buildOtpauthUri(secret: string, account: string, issuer: string, config?: TOTPConfig): string;
|
|
139
|
+
|
|
140
|
+
export { Algorithm, type AlgorithmDef, type AlgorithmKey, type AlgorithmValue, ErrorCode, InMemoryReplayGuard, type ReplayGuard, TOTP, type TOTPConfig, TOTPError, type TOTPOptions, type VerificationResult, algorithmFromName, buildOtpauthUri, createConfig, defaultConfig, entropyBits, generateRawSecret, generateSecret, generateSecretBytes, highSecurityConfig, isValidSecret, recommendedSecretLength, sha256Config };
|