@nowarajs/totp 1.2.0 β 1.2.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/README.md +61 -150
- package/package.json +9 -9
package/README.md
CHANGED
|
@@ -1,41 +1,32 @@
|
|
|
1
|
-
# π NowaraJS
|
|
1
|
+
# π NowaraJS TOTP
|
|
2
|
+
|
|
3
|
+
Let's be honest: there are already packages like `totp-generator` that do this. I built this one mostly for myselfβto learn how TOTP/HOTP actually works under the hood, and to have a lightweight alternative I fully understand.
|
|
4
|
+
|
|
5
|
+
## Why this package?
|
|
6
|
+
|
|
7
|
+
No grand mission here. I wanted:
|
|
8
|
+
1. **To learn** how RFC 6238/4226 work in practice
|
|
9
|
+
2. **A tiny footprint** without pulling half of npm
|
|
10
|
+
3. **Something I control** for my own projects
|
|
11
|
+
|
|
12
|
+
If you're looking for battle-tested libraries, check out the established ones. If you want something small and readable, this might be for you.
|
|
2
13
|
|
|
3
14
|
## π Table of Contents
|
|
4
15
|
|
|
5
|
-
- [
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
- [Basic TOTP Generation](#basic-totp-generation)
|
|
12
|
-
- [TOTP Verification](#totp-verification)
|
|
13
|
-
- [HOTP Support](#hotp-support)
|
|
14
|
-
- [OTPAuth URI Generation](#otpauth-uri-generation)
|
|
15
|
-
- [Secret Generation](#secret-generation)
|
|
16
|
-
- [π Advanced Configuration](#-advanced-configuration)
|
|
17
|
-
- [π οΈ Utilities](#-utilities)
|
|
18
|
-
- [π API Reference](#-api-reference)
|
|
19
|
-
- [βοΈ License](#-license)
|
|
20
|
-
- [π§ Contact](#-contact)
|
|
21
|
-
|
|
22
|
-
## π Description
|
|
23
|
-
|
|
24
|
-
> A comprehensive Time-based One-Time Password (TOTP) and HMAC-based One-Time Password (HOTP) implementation for TypeScript/JavaScript.
|
|
25
|
-
|
|
26
|
-
**NowaraJS TOTP** provides a secure and RFC-compliant implementation of TOTP and HOTP algorithms with full support for QR code generation, secret management, and various authentication configurations. Perfect for implementing two-factor authentication (2FA) in your applications.
|
|
16
|
+
- [Features](#-features)
|
|
17
|
+
- [Installation](#-installation)
|
|
18
|
+
- [Usage](#-usage)
|
|
19
|
+
- [API Reference](#-api-reference)
|
|
20
|
+
- [License](#-license)
|
|
21
|
+
- [Contact](#-contact)
|
|
27
22
|
|
|
28
23
|
## β¨ Features
|
|
29
24
|
|
|
30
|
-
- π **RFC 6238 TOTP
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
-
|
|
34
|
-
-
|
|
35
|
-
- π οΈ **Configurable**: Support for different algorithms (SHA-1, SHA-256, SHA-512)
|
|
36
|
-
- π **Flexible Digits**: Support for 6-8 digit codes
|
|
37
|
-
- β° **Time Window**: Configurable time periods and verification windows
|
|
38
|
-
- π― **Base32 Encoding**: Built-in Base32 encoding/decoding utilities
|
|
25
|
+
- π **RFC Compliant**: Full RFC 6238 (TOTP) and RFC 4226 (HOTP) implementation.
|
|
26
|
+
- π± **QR Code Ready**: Generate OTPAuth URIs compatible with Google Authenticator, Authy, etc.
|
|
27
|
+
- π **Crypto Secure**: Uses Web Crypto API for truly random secret generation.
|
|
28
|
+
- π οΈ **Flexible**: SHA-1, SHA-256, SHA-512 algorithms with 6-8 digit codes.
|
|
29
|
+
- π¦ **Zero Dependencies**: Pure TypeScript, tiny footprint.
|
|
39
30
|
|
|
40
31
|
## π§ Installation
|
|
41
32
|
|
|
@@ -45,168 +36,88 @@ bun add @nowarajs/totp @nowarajs/error
|
|
|
45
36
|
|
|
46
37
|
## βοΈ Usage
|
|
47
38
|
|
|
48
|
-
###
|
|
39
|
+
### Generate a TOTP Code
|
|
40
|
+
|
|
41
|
+
Use this when you need to generate a one-time password for the current time window.
|
|
49
42
|
|
|
50
43
|
```ts
|
|
51
44
|
import { totp, generateSecretBytes, base32Encode } from '@nowarajs/totp';
|
|
52
45
|
|
|
53
|
-
// Generate a secret
|
|
54
|
-
const secret = generateSecretBytes(20);
|
|
55
|
-
const secretBase32 = base32Encode(secret);
|
|
46
|
+
// Generate a cryptographically secure secret
|
|
47
|
+
const secret = generateSecretBytes(20);
|
|
56
48
|
|
|
57
|
-
// Generate TOTP code
|
|
49
|
+
// Generate the current TOTP code
|
|
58
50
|
const code = await totp(secret, {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
51
|
+
algorithm: 'SHA-1',
|
|
52
|
+
digits: 6,
|
|
53
|
+
period: 30
|
|
62
54
|
});
|
|
63
55
|
|
|
64
|
-
console.log('
|
|
56
|
+
console.log('Your code:', code); // e.g., "847263"
|
|
65
57
|
```
|
|
66
58
|
|
|
67
|
-
###
|
|
59
|
+
### Verify a User's Code
|
|
60
|
+
|
|
61
|
+
Use this to validate the code your user just entered. The `window` option handles clock drift gracefully.
|
|
68
62
|
|
|
69
63
|
```ts
|
|
70
64
|
import { verifyTotp } from '@nowarajs/totp';
|
|
71
65
|
|
|
72
|
-
// Verify a TOTP code
|
|
73
66
|
const isValid = await verifyTotp(secret, userInputCode, {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
67
|
+
algorithm: 'SHA-1',
|
|
68
|
+
digits: 6,
|
|
69
|
+
period: 30,
|
|
70
|
+
window: 1 // Accept codes from Β±30 seconds
|
|
78
71
|
});
|
|
79
72
|
|
|
80
|
-
if (isValid)
|
|
81
|
-
|
|
82
|
-
} else {
|
|
83
|
-
console.log('β Invalid code');
|
|
84
|
-
}
|
|
73
|
+
if (isValid) console.log('β
Access granted');
|
|
74
|
+
else console.log('β Invalid code');
|
|
85
75
|
```
|
|
86
76
|
|
|
87
|
-
###
|
|
77
|
+
### Generate a QR Code URI
|
|
88
78
|
|
|
89
|
-
|
|
90
|
-
import { hotp } from '@nowarajs/totp';
|
|
91
|
-
|
|
92
|
-
// Generate HOTP code with counter
|
|
93
|
-
const counter = 123;
|
|
94
|
-
const hotpCode = await hotp(secret, counter, {
|
|
95
|
-
algorithm: 'SHA-1',
|
|
96
|
-
digits: 6
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
console.log('HOTP Code:', hotpCode);
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
### OTPAuth URI Generation
|
|
79
|
+
Use this to let users scan a QR code with their authenticator app.
|
|
103
80
|
|
|
104
81
|
```ts
|
|
105
|
-
import { buildOtpAuthUri, base32Encode } from '@nowarajs/totp';
|
|
82
|
+
import { buildOtpAuthUri, generateSecretBytes, base32Encode } from '@nowarajs/totp';
|
|
106
83
|
|
|
107
84
|
const secret = generateSecretBytes(20);
|
|
108
85
|
const secretBase32 = base32Encode(secret);
|
|
109
86
|
|
|
110
|
-
// Create URI for QR code
|
|
111
87
|
const uri = buildOtpAuthUri({
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
88
|
+
secretBase32,
|
|
89
|
+
label: 'user@example.com',
|
|
90
|
+
issuer: 'MyApp',
|
|
91
|
+
algorithm: 'SHA-1',
|
|
92
|
+
digits: 6,
|
|
93
|
+
period: 30
|
|
118
94
|
});
|
|
119
95
|
|
|
120
|
-
|
|
96
|
+
// Feed this URI to any QR code library
|
|
97
|
+
console.log(uri);
|
|
121
98
|
// otpauth://totp/user@example.com?secret=JBSWY3DPEHPK3PXP&issuer=MyApp
|
|
122
99
|
```
|
|
123
100
|
|
|
124
|
-
###
|
|
101
|
+
### HOTP (Counter-Based)
|
|
125
102
|
|
|
126
|
-
|
|
127
|
-
import { generateSecretBytes, base32Encode, base32Decode } from '@nowarajs/totp/utils';
|
|
128
|
-
|
|
129
|
-
// Generate cryptographically secure secret
|
|
130
|
-
const secret = generateSecretBytes(32); // 256 bits for extra security
|
|
131
|
-
|
|
132
|
-
// Encode for storage/transmission
|
|
133
|
-
const encoded = base32Encode(secret);
|
|
134
|
-
console.log('Base32 Secret:', encoded);
|
|
135
|
-
|
|
136
|
-
// Decode when needed
|
|
137
|
-
const decoded = base32Decode(encoded);
|
|
138
|
-
console.log('Original bytes match:', secret.every((byte, i) => byte === decoded[i]));
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
## π Advanced Configuration
|
|
142
|
-
|
|
143
|
-
### Custom Algorithm and Settings
|
|
103
|
+
Use this when you need counter-based OTPs instead of time-based ones.
|
|
144
104
|
|
|
145
105
|
```ts
|
|
146
|
-
|
|
147
|
-
const advancedCode = await totp(secret, {
|
|
148
|
-
algorithm: 'SHA-256',
|
|
149
|
-
digits: 8,
|
|
150
|
-
period: 60
|
|
151
|
-
});
|
|
106
|
+
import { hotp } from '@nowarajs/totp';
|
|
152
107
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
digits: 8,
|
|
157
|
-
period: 60,
|
|
158
|
-
window: 2 // Allow Β±2 time steps (Β±2 minutes)
|
|
108
|
+
const code = await hotp(secret, 123, {
|
|
109
|
+
algorithm: 'SHA-1',
|
|
110
|
+
digits: 6
|
|
159
111
|
});
|
|
160
112
|
```
|
|
161
113
|
|
|
162
|
-
### Parse Existing OTPAuth URIs
|
|
163
|
-
|
|
164
|
-
```ts
|
|
165
|
-
import { parseOtpAuthUri } from '@nowarajs/totp';
|
|
166
|
-
|
|
167
|
-
const uri = 'otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example';
|
|
168
|
-
const parsed = parseOtpAuthUri(uri);
|
|
169
|
-
|
|
170
|
-
console.log(parsed);
|
|
171
|
-
// {
|
|
172
|
-
// type: 'totp',
|
|
173
|
-
// label: 'Example:alice@google.com',
|
|
174
|
-
// secret: 'JBSWY3DPEHPK3PXP',
|
|
175
|
-
// issuer: 'Example',
|
|
176
|
-
// algorithm: 'SHA-1',
|
|
177
|
-
// digits: 6,
|
|
178
|
-
// period: 30
|
|
179
|
-
// }
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
## π οΈ Utilities
|
|
183
|
-
|
|
184
|
-
The package includes several utility functions available through subpath imports:
|
|
185
|
-
|
|
186
|
-
```ts
|
|
187
|
-
// Base32 encoding/decoding
|
|
188
|
-
import { base32Encode, base32Decode } from '@nowarajs/totp/utils';
|
|
189
|
-
|
|
190
|
-
// Secret generation
|
|
191
|
-
import { generateSecretBytes } from '@nowarajs/totp/utils';
|
|
192
|
-
|
|
193
|
-
// Time utilities
|
|
194
|
-
import { timeRemaining } from '@nowarajs/totp/utils';
|
|
195
|
-
|
|
196
|
-
// Get seconds until next TOTP generation
|
|
197
|
-
const remaining = timeRemaining(30); // for 30-second period
|
|
198
|
-
console.log(`Next code in ${remaining} seconds`);
|
|
199
|
-
```
|
|
200
|
-
|
|
201
114
|
## π API Reference
|
|
202
115
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
- [Reference Documentation](https://nowarajs.github.io/totp/)
|
|
116
|
+
Full docs: [nowarajs.github.io/totp](https://nowarajs.github.io/totp/)
|
|
206
117
|
|
|
207
118
|
## βοΈ License
|
|
208
119
|
|
|
209
|
-
|
|
120
|
+
MIT - Feel free to use it.
|
|
210
121
|
|
|
211
122
|
## π§ Contact
|
|
212
123
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nowarajs/totp",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"author": "NowaraJS",
|
|
5
5
|
"description": "A comprehensive Time-based One-Time Password (TOTP) and HMAC-based One-Time Password (HOTP)",
|
|
6
6
|
"type": "module",
|
|
@@ -22,17 +22,17 @@
|
|
|
22
22
|
"test": "bun test --coverage"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"@eslint/js": "^9.39.
|
|
26
|
-
"@nowarajs/error": "^1.
|
|
27
|
-
"@stylistic/eslint-plugin": "^5.
|
|
28
|
-
"@types/bun": "^1.3.
|
|
29
|
-
"eslint": "^9.39.
|
|
30
|
-
"globals": "^
|
|
31
|
-
"typescript-eslint": "^8.
|
|
25
|
+
"@eslint/js": "^9.39.2",
|
|
26
|
+
"@nowarajs/error": "^1.4.0",
|
|
27
|
+
"@stylistic/eslint-plugin": "^5.7.0",
|
|
28
|
+
"@types/bun": "^1.3.5",
|
|
29
|
+
"eslint": "^9.39.2",
|
|
30
|
+
"globals": "^17.0.0",
|
|
31
|
+
"typescript-eslint": "^8.52.0",
|
|
32
32
|
"typescript": "^5.9.3"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
|
-
"@nowarajs/error": "^1.
|
|
35
|
+
"@nowarajs/error": "^1.4.0"
|
|
36
36
|
},
|
|
37
37
|
"exports": {
|
|
38
38
|
"./enums": "./dist/enums/index.js",
|