daku 0.0.5 → 0.1.0
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 +273 -177
- package/example/authentication.js +160 -0
- package/example/group-chat.js +97 -0
- package/example/one-on-one-chat.js +70 -0
- package/index.js +98 -10
- package/package.json +7 -1
- package/test.js +205 -0
- package/username.js +7 -2687
package/README.md
CHANGED
|
@@ -1,274 +1,370 @@
|
|
|
1
1
|
# DAKU
|
|
2
2
|
|
|
3
|
-
> **Anonymous authentication. Zero personal data.**
|
|
3
|
+
> **Anonymous authentication & encryption. Zero personal data. One library.**
|
|
4
4
|
|
|
5
|
-
**DAKU** (
|
|
5
|
+
**DAKU** (Punjabi for "bandits") is a minimal cryptographic toolkit for building passwordless, privacy-first applications. No emails, no passwords, no databases of credentials to breach.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install daku
|
|
9
|
+
```
|
|
6
10
|
|
|
7
11
|
---
|
|
8
12
|
|
|
9
13
|
## Why DAKU?
|
|
10
14
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
15
|
+
| Traditional Auth | DAKU |
|
|
16
|
+
|------------------|------|
|
|
17
|
+
| Store emails & passwords | Just verify signatures |
|
|
18
|
+
| Hash passwords, manage resets | No passwords exist |
|
|
19
|
+
| GDPR compliance headaches | No PII collected |
|
|
20
|
+
| Database = honeypot for hackers | Nothing sensitive to steal |
|
|
21
|
+
| OAuth complexity | 3 functions to authenticate |
|
|
14
22
|
|
|
15
23
|
```javascript
|
|
16
|
-
|
|
17
|
-
// DAKU: Just verify cryptographic signatures ✨
|
|
18
|
-
const publicKey = await verifyAuth(token);
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
### The Problem with Traditional Auth
|
|
22
|
-
|
|
23
|
-
Every traditional authentication system carries risk:
|
|
24
|
-
|
|
25
|
-
- **Passwords**: Users reuse them, forget them, get them stolen
|
|
26
|
-
- **Email/Phone**: Requires collecting personal data (GDPR, privacy laws)
|
|
27
|
-
- **Databases**: Honeypots for hackers; one breach exposes everything
|
|
28
|
-
- **Identity**: Your users leave traces everywhere they sign up
|
|
24
|
+
import { generateKeyPair, createAuth, verifyAuth } from "daku";
|
|
29
25
|
|
|
30
|
-
|
|
26
|
+
// User creates identity (client-side, once)
|
|
27
|
+
const { privateKey, publicKey } = generateKeyPair();
|
|
31
28
|
|
|
32
|
-
|
|
29
|
+
// User logs in (client-side)
|
|
30
|
+
const token = await createAuth(privateKey);
|
|
33
31
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
- **Built-in spam protection**: Proof-of-work prevents abuse
|
|
38
|
-
- **You stay clean**: Nothing sensitive to store, nothing to breach
|
|
32
|
+
// Server verifies (server-side)
|
|
33
|
+
const userId = await verifyAuth(token); // Returns publicKey or null
|
|
34
|
+
```
|
|
39
35
|
|
|
40
|
-
|
|
36
|
+
**That's it.** No signup forms, no email verification, no password resets.
|
|
41
37
|
|
|
42
38
|
---
|
|
43
39
|
|
|
44
|
-
##
|
|
40
|
+
## What DAKU Offers
|
|
45
41
|
|
|
46
|
-
|
|
47
|
-
|
|
42
|
+
### 🔑 Identity
|
|
43
|
+
```javascript
|
|
44
|
+
generateKeyPair() // Create new keypair identity
|
|
45
|
+
getPublicKey(privateKey) // Derive public key from private
|
|
46
|
+
getUsername(publicKey) // Human-readable name like "oceanrunning4523"
|
|
48
47
|
```
|
|
49
48
|
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
### 🎫 Authentication
|
|
52
50
|
```javascript
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const { privateKey, publicKey } = generateKeyPair();
|
|
51
|
+
createAuth(privateKey, pow?) // Create login token (with spam protection)
|
|
52
|
+
verifyAuth(token, pow?) // Verify token, returns publicKey or null
|
|
53
|
+
```
|
|
57
54
|
|
|
58
|
-
|
|
59
|
-
|
|
55
|
+
### ✍️ Signatures
|
|
56
|
+
```javascript
|
|
57
|
+
sign(message, privateKey, pow?) // Sign any data
|
|
58
|
+
verify(message, sig, publicKey, pow?) // Verify signature
|
|
59
|
+
sha256(message) // SHA-256 hash
|
|
60
|
+
```
|
|
60
61
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
//
|
|
62
|
+
### 🔐 E2E Encryption
|
|
63
|
+
```javascript
|
|
64
|
+
deriveSharedSecret(myPrivate, theirPublic) // ECDH key agreement
|
|
65
|
+
encrypt(plaintext, key) // AES-256-GCM encrypt
|
|
66
|
+
decrypt(ciphertext, key) // AES-256-GCM decrypt
|
|
64
67
|
```
|
|
65
68
|
|
|
66
69
|
---
|
|
67
70
|
|
|
68
|
-
##
|
|
71
|
+
## 20+ Use Cases
|
|
72
|
+
|
|
73
|
+
| # | Use Case |
|
|
74
|
+
|---|----------|
|
|
75
|
+
| 1 | **Anonymous chat apps** — Users communicate without revealing identity or phone numbers |
|
|
76
|
+
| 2 | **Passwordless API authentication** — Clients sign requests instead of using API keys |
|
|
77
|
+
| 3 | **End-to-end encrypted messaging** — Private conversations only sender and receiver can read |
|
|
78
|
+
| 4 | **Anonymous feedback systems** — Collect honest feedback without identifying who submitted it |
|
|
79
|
+
| 5 | **Whistleblower platforms** — Secure, anonymous submission of sensitive information to journalists |
|
|
80
|
+
| 6 | **Decentralized identity** — Users own their identity, no central authority controls access |
|
|
81
|
+
| 7 | **IoT device authentication** — Devices authenticate without passwords or certificate authorities |
|
|
82
|
+
| 8 | **Wallet-based login** — Same keys work with Bitcoin/Ethereum ecosystems (secp256k1) |
|
|
83
|
+
| 9 | **Document signing** — Cryptographically sign contracts, agreements, or any digital document |
|
|
84
|
+
| 10 | **Anonymous voting systems** — Verify votes are legitimate without revealing who voted |
|
|
85
|
+
| 11 | **Encrypted file sharing** — Share files that only intended recipients can decrypt |
|
|
86
|
+
| 12 | **Private note-taking apps** — Notes encrypted locally, unreadable even if server breached |
|
|
87
|
+
| 13 | **Spam-resistant forms** — Proof-of-work prevents bots from mass-submitting without CAPTCHAs |
|
|
88
|
+
| 14 | **Multiplayer game authentication** — Players authenticate without creating accounts or emails |
|
|
89
|
+
| 15 | **Anonymous support tickets** — Users get help without revealing personal information |
|
|
90
|
+
| 16 | **Secure configuration sharing** — Share secrets between team members with E2E encryption |
|
|
91
|
+
| 17 | **Timestamped proof of existence** — Sign documents to prove they existed at specific time |
|
|
92
|
+
| 18 | **Private health apps** — Health data stays encrypted, only user can access it |
|
|
93
|
+
| 19 | **Anonymous marketplace** — Buy/sell without linking transactions to real identity |
|
|
94
|
+
| 20 | **Encrypted backups** — Backup data that only you can restore, even on untrusted storage |
|
|
95
|
+
| 21 | **CLI tool authentication** — Command-line tools authenticate without browser OAuth flows |
|
|
96
|
+
| 22 | **Peer-to-peer apps** — Direct encrypted communication between users without servers |
|
|
97
|
+
| 23 | **Private analytics** — Collect anonymous usage data without tracking individuals |
|
|
98
|
+
| 24 | **Secure team collaboration** — Group encryption for team channels and shared documents |
|
|
69
99
|
|
|
70
|
-
|
|
100
|
+
---
|
|
71
101
|
|
|
72
|
-
|
|
102
|
+
## How It Works
|
|
73
103
|
|
|
74
|
-
|
|
75
|
-
|
|
104
|
+
### Authentication Flow
|
|
105
|
+
```
|
|
106
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
107
|
+
│ CLIENT │
|
|
108
|
+
│ │
|
|
109
|
+
│ 1. First visit: generateKeyPair() → save privateKey │
|
|
110
|
+
│ 2. Login: createAuth(privateKey) → token │
|
|
111
|
+
│ 3. Send token to server │
|
|
112
|
+
└─────────────────────────────────────────────────────────────┘
|
|
113
|
+
│
|
|
114
|
+
▼
|
|
115
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
116
|
+
│ SERVER │
|
|
117
|
+
│ │
|
|
118
|
+
│ 1. verifyAuth(token) → publicKey (user ID) │
|
|
119
|
+
│ 2. publicKey is the unique, permanent user identifier │
|
|
120
|
+
│ 3. No passwords, no emails, no database of credentials │
|
|
121
|
+
└─────────────────────────────────────────────────────────────┘
|
|
76
122
|
```
|
|
77
123
|
|
|
78
|
-
|
|
124
|
+
### E2E Encryption Flow
|
|
125
|
+
```
|
|
126
|
+
Alice Bob
|
|
127
|
+
│ │
|
|
128
|
+
│ 1. deriveSharedSecret(alice.priv, bob.pub) │
|
|
129
|
+
│ ═══════════════════════════════════ │
|
|
130
|
+
│ (Both derive SAME secret) │
|
|
131
|
+
│ ═══════════════════════════════════ │
|
|
132
|
+
│ 2. deriveSharedSecret(bob.priv, alice.pub) │
|
|
133
|
+
│ │
|
|
134
|
+
│ 3. encrypt("Hello", secret) ──────────────►│
|
|
135
|
+
│ ◄──────────────│ 4. decrypt(cipher, secret)
|
|
136
|
+
│ │
|
|
137
|
+
└─────────────────────────────────────────────┘
|
|
138
|
+
Only Alice & Bob can read messages
|
|
139
|
+
```
|
|
79
140
|
|
|
80
|
-
|
|
81
|
-
|
|
141
|
+
### Group Encryption
|
|
142
|
+
```javascript
|
|
143
|
+
import { deriveSharedSecret, encrypt, decrypt } from "daku";
|
|
144
|
+
import crypto from "node:crypto";
|
|
82
145
|
|
|
83
|
-
|
|
146
|
+
// Admin creates group key (just random 32 bytes)
|
|
147
|
+
const groupKey = crypto.randomBytes(32).toString("hex");
|
|
84
148
|
|
|
85
|
-
|
|
149
|
+
// Distribute to each member securely
|
|
150
|
+
for (const member of members) {
|
|
151
|
+
const secret = deriveSharedSecret(admin.privateKey, member.publicKey);
|
|
152
|
+
const encryptedKey = await encrypt(groupKey, secret);
|
|
153
|
+
// Send encryptedKey to member
|
|
154
|
+
}
|
|
86
155
|
|
|
87
|
-
|
|
156
|
+
// Member decrypts their copy
|
|
157
|
+
const memberSecret = deriveSharedSecret(member.privateKey, admin.publicKey);
|
|
158
|
+
const groupKey = await decrypt(encryptedKey, memberSecret);
|
|
88
159
|
|
|
89
|
-
|
|
90
|
-
const
|
|
160
|
+
// Everyone encrypts/decrypts with the shared group key
|
|
161
|
+
const message = await encrypt("Hello group!", groupKey);
|
|
91
162
|
```
|
|
92
163
|
|
|
93
|
-
|
|
164
|
+
---
|
|
94
165
|
|
|
95
|
-
|
|
96
|
-
|
|
166
|
+
## Security
|
|
167
|
+
|
|
168
|
+
| Feature | Implementation |
|
|
169
|
+
|---------|----------------|
|
|
170
|
+
| **Signatures** | secp256k1 ECDSA (same as Bitcoin/Ethereum) |
|
|
171
|
+
| **Encryption** | AES-256-GCM with random 96-bit IV |
|
|
172
|
+
| **Key Exchange** | ECDH (Elliptic Curve Diffie-Hellman) |
|
|
173
|
+
| **Hashing** | SHA-256 |
|
|
174
|
+
| **Spam Protection** | Proof-of-work (configurable difficulty) |
|
|
175
|
+
| **Token Expiry** | Auth tokens valid for 1 minute only |
|
|
176
|
+
|
|
177
|
+
### What DAKU Protects Against
|
|
178
|
+
- ✅ Password breaches (no passwords exist)
|
|
179
|
+
- ✅ Credential stuffing (nothing to stuff)
|
|
180
|
+
- ✅ Phishing (no credentials to phish)
|
|
181
|
+
- ✅ Database leaks (no PII stored)
|
|
182
|
+
- ✅ Replay attacks (1-minute token expiry)
|
|
183
|
+
- ✅ Spam/bots (proof-of-work)
|
|
184
|
+
- ✅ Man-in-the-middle (E2E encryption)
|
|
185
|
+
|
|
186
|
+
### User Responsibilities
|
|
187
|
+
- 🔑 Users must securely store their private key
|
|
188
|
+
- 🔑 Lost private key = lost identity (no recovery)
|
|
189
|
+
- 🔑 Compromised private key = compromised identity
|
|
97
190
|
|
|
98
191
|
---
|
|
99
192
|
|
|
100
|
-
|
|
193
|
+
## Examples
|
|
101
194
|
|
|
102
|
-
|
|
195
|
+
### Express.js Middleware
|
|
196
|
+
```javascript
|
|
197
|
+
import { verifyAuth, getUsername } from "daku";
|
|
103
198
|
|
|
199
|
+
async function authMiddleware(req, res, next) {
|
|
200
|
+
const token = req.headers.authorization?.replace("Bearer ", "");
|
|
201
|
+
|
|
202
|
+
const publicKey = await verifyAuth(token);
|
|
203
|
+
if (!publicKey) {
|
|
204
|
+
return res.status(401).json({ error: "Unauthorized" });
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
req.userId = publicKey;
|
|
208
|
+
req.username = getUsername(publicKey);
|
|
209
|
+
next();
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### React Login
|
|
104
214
|
```javascript
|
|
105
|
-
|
|
106
|
-
|
|
215
|
+
import { generateKeyPair, createAuth } from "daku";
|
|
216
|
+
|
|
217
|
+
function useAuth() {
|
|
218
|
+
const login = async () => {
|
|
219
|
+
let privateKey = localStorage.getItem("privateKey");
|
|
220
|
+
|
|
221
|
+
if (!privateKey) {
|
|
222
|
+
const keys = generateKeyPair();
|
|
223
|
+
privateKey = keys.privateKey;
|
|
224
|
+
localStorage.setItem("privateKey", privateKey);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const token = await createAuth(privateKey);
|
|
228
|
+
return fetch("/api/login", {
|
|
229
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
230
|
+
});
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
return { login };
|
|
234
|
+
}
|
|
107
235
|
```
|
|
108
236
|
|
|
109
|
-
|
|
237
|
+
### Encrypted Chat
|
|
238
|
+
```javascript
|
|
239
|
+
import { deriveSharedSecret, encrypt, decrypt } from "daku";
|
|
110
240
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
- Format: `adjective-noun-verb-number`
|
|
241
|
+
// Both users derive the same shared secret
|
|
242
|
+
const secret = deriveSharedSecret(myPrivateKey, theirPublicKey);
|
|
114
243
|
|
|
115
|
-
|
|
116
|
-
|
|
244
|
+
// Send encrypted message
|
|
245
|
+
const encrypted = await encrypt("Hello!", secret);
|
|
246
|
+
ws.send(encrypted);
|
|
117
247
|
|
|
118
|
-
|
|
248
|
+
// Receive and decrypt
|
|
249
|
+
ws.onmessage = async (e) => {
|
|
250
|
+
const message = await decrypt(e.data, secret);
|
|
251
|
+
console.log(message);
|
|
252
|
+
};
|
|
253
|
+
```
|
|
119
254
|
|
|
120
|
-
|
|
255
|
+
---
|
|
121
256
|
|
|
122
|
-
|
|
257
|
+
## API Reference
|
|
123
258
|
|
|
259
|
+
### `generateKeyPair()`
|
|
260
|
+
Creates a new secp256k1 keypair.
|
|
124
261
|
```javascript
|
|
125
|
-
const
|
|
262
|
+
const { privateKey, publicKey } = generateKeyPair();
|
|
263
|
+
// privateKey: 64-char hex (keep secret!)
|
|
264
|
+
// publicKey: 66-char hex (share freely)
|
|
126
265
|
```
|
|
127
266
|
|
|
128
|
-
|
|
267
|
+
### `getPublicKey(privateKey)`
|
|
268
|
+
Derives public key from private key.
|
|
269
|
+
```javascript
|
|
270
|
+
const publicKey = getPublicKey(privateKey);
|
|
271
|
+
```
|
|
129
272
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
273
|
+
### `getUsername(publicKey)`
|
|
274
|
+
Generates a deterministic human-readable username.
|
|
275
|
+
```javascript
|
|
276
|
+
const name = getUsername(publicKey); // "oceanrunning4523"
|
|
277
|
+
```
|
|
133
278
|
|
|
134
|
-
|
|
279
|
+
### `createAuth(privateKey, pow?)`
|
|
280
|
+
Creates a signed authentication token. Default POW difficulty is 2.
|
|
281
|
+
```javascript
|
|
282
|
+
const token = await createAuth(privateKey);
|
|
283
|
+
const token = await createAuth(privateKey, 3); // Higher difficulty
|
|
284
|
+
```
|
|
135
285
|
|
|
136
286
|
### `verifyAuth(token, pow?)`
|
|
137
|
-
|
|
138
|
-
**Verify authentication token**
|
|
139
|
-
|
|
287
|
+
Verifies an auth token. Returns `publicKey` on success, `null` on failure.
|
|
140
288
|
```javascript
|
|
141
|
-
const publicKey = await verifyAuth(token
|
|
289
|
+
const publicKey = await verifyAuth(token);
|
|
142
290
|
if (publicKey) {
|
|
143
|
-
//
|
|
144
|
-
console.log(`User ${publicKey} logged in`);
|
|
145
|
-
} else {
|
|
146
|
-
// ❌ Invalid or expired
|
|
291
|
+
// Authenticated! publicKey is the user ID
|
|
147
292
|
}
|
|
148
293
|
```
|
|
149
294
|
|
|
150
|
-
Verifies the signature, proof-of-work, and timestamp (must be < 1 minute old). Returns the user's publicKey on success.
|
|
151
|
-
|
|
152
|
-
- Returns: `publicKey` string or `null`
|
|
153
|
-
- Checks: Signature validity, POW correctness, timestamp freshness
|
|
154
|
-
- Token lifetime: 1 minute
|
|
155
|
-
|
|
156
|
-
---
|
|
157
|
-
|
|
158
295
|
### `sign(message, privateKey, pow?)`
|
|
159
|
-
|
|
160
|
-
**Sign any message**
|
|
161
|
-
|
|
296
|
+
Signs a message with proof-of-work.
|
|
162
297
|
```javascript
|
|
163
|
-
const
|
|
298
|
+
const sig = await sign("Hello", privateKey);
|
|
299
|
+
// { signature: "...", pow: 123 }
|
|
164
300
|
```
|
|
165
301
|
|
|
166
|
-
Create a cryptographic signature for any message with proof-of-work. Lower-level function used by `createAuth()`.
|
|
167
|
-
|
|
168
|
-
- Returns: `{ signature: string, pow: number }`
|
|
169
|
-
- Use case: Custom message signing beyond authentication
|
|
170
|
-
|
|
171
|
-
---
|
|
172
|
-
|
|
173
302
|
### `verify(message, signatureData, publicKey, pow?)`
|
|
174
|
-
|
|
175
|
-
**Verify any signature**
|
|
176
|
-
|
|
303
|
+
Verifies a signature.
|
|
177
304
|
```javascript
|
|
178
|
-
const isValid = await verify("
|
|
305
|
+
const isValid = await verify("Hello", sig, publicKey);
|
|
179
306
|
```
|
|
180
307
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
- Returns: `boolean`
|
|
184
|
-
- Checks: Signature + POW validity
|
|
185
|
-
|
|
186
|
-
---
|
|
187
|
-
|
|
188
|
-
## Express.js Middleware
|
|
189
|
-
|
|
308
|
+
### `sha256(message)`
|
|
309
|
+
SHA-256 hash.
|
|
190
310
|
```javascript
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
const app = express();
|
|
195
|
-
|
|
196
|
-
// Middleware: Verify DAKU auth
|
|
197
|
-
const daku =
|
|
198
|
-
(powDifficulty = 2) =>
|
|
199
|
-
async (req, res, next) => {
|
|
200
|
-
const token = req.headers["daku"];
|
|
201
|
-
const publicKey = await verifyAuth(token, powDifficulty);
|
|
202
|
-
|
|
203
|
-
if (!publicKey) {
|
|
204
|
-
return res.status(401).json({ error: "Unauthorized" });
|
|
205
|
-
}
|
|
311
|
+
const hash = await sha256("Hello"); // Uint8Array(32)
|
|
312
|
+
```
|
|
206
313
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
314
|
+
### `deriveSharedSecret(myPrivateKey, theirPublicKey)`
|
|
315
|
+
ECDH key agreement. Both parties derive the same secret.
|
|
316
|
+
```javascript
|
|
317
|
+
const secret = deriveSharedSecret(alice.privateKey, bob.publicKey);
|
|
318
|
+
// Same as: deriveSharedSecret(bob.privateKey, alice.publicKey)
|
|
319
|
+
```
|
|
210
320
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
userId: req.userId,
|
|
217
|
-
});
|
|
218
|
-
});
|
|
321
|
+
### `encrypt(plaintext, key)`
|
|
322
|
+
AES-256-GCM encryption.
|
|
323
|
+
```javascript
|
|
324
|
+
const ciphertext = await encrypt("Secret message", sharedSecret);
|
|
325
|
+
```
|
|
219
326
|
|
|
220
|
-
|
|
327
|
+
### `decrypt(ciphertext, key)`
|
|
328
|
+
AES-256-GCM decryption. Returns `null` on failure.
|
|
329
|
+
```javascript
|
|
330
|
+
const plaintext = await decrypt(ciphertext, sharedSecret);
|
|
221
331
|
```
|
|
222
332
|
|
|
223
333
|
---
|
|
224
334
|
|
|
225
|
-
##
|
|
226
|
-
|
|
227
|
-
| Traditional Auth | DAKU |
|
|
228
|
-
| ----------------------------------- | -------------------------------------- |
|
|
229
|
-
| Manage passwords, hashes, resets | No passwords—just verify signatures |
|
|
230
|
-
| Store emails/phones (PII) | Zero personal data collected |
|
|
231
|
-
| User databases = security liability | Only store public keys (not sensitive) |
|
|
232
|
-
| Slow authentication flows | Instant cryptographic verification |
|
|
233
|
-
| GDPR compliance overhead | No PII = simpler compliance |
|
|
234
|
-
| Spam = manual moderation/CAPTCHAs | Built-in proof-of-work protection |
|
|
335
|
+
## Comparison
|
|
235
336
|
|
|
236
|
-
|
|
337
|
+
| Feature | DAKU | Passport.js | Auth0 | Firebase Auth |
|
|
338
|
+
|---------|------|-------------|-------|---------------|
|
|
339
|
+
| No passwords | ✅ | ❌ | ❌ | ❌ |
|
|
340
|
+
| No email required | ✅ | ❌ | ❌ | ❌ |
|
|
341
|
+
| No database needed | ✅ | ❌ | ❌ | ❌ |
|
|
342
|
+
| E2E encryption | ✅ | ❌ | ❌ | ❌ |
|
|
343
|
+
| Self-hosted | ✅ | ✅ | ❌ | ❌ |
|
|
344
|
+
| Zero dependencies* | ✅ | ❌ | ❌ | ❌ |
|
|
345
|
+
| Works offline | ✅ | ❌ | ❌ | ❌ |
|
|
346
|
+
| Bundle size | ~50KB | ~200KB | SDK required | SDK required |
|
|
237
347
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
- **🕵️ Anonymous**: No email, no phone, no personal data
|
|
241
|
-
- **🔐 Secure**: secp256k1 signatures (Bitcoin/Ethereum-grade)
|
|
242
|
-
- **🛡️ Spam-proof**: Configurable proof-of-work difficulty
|
|
243
|
-
- **⚡ Lightweight**: Minimal dependencies, works everywhere
|
|
244
|
-
- **🌐 Universal**: Node.js + Browser compatible
|
|
245
|
-
- **⏱️ Short-lived tokens**: 1-minute expiration (anti-replay)
|
|
246
|
-
- **🌍 Cross-project identity**: Reuse one keypair across apps
|
|
348
|
+
*Only 2 peer dependencies: `@noble/secp256k1` and `@noble/hashes`
|
|
247
349
|
|
|
248
350
|
---
|
|
249
351
|
|
|
250
|
-
##
|
|
251
|
-
|
|
252
|
-
Users can reuse **one private key** across multiple services. Same privateKey → same publicKey → same identity everywhere.
|
|
352
|
+
## Installation
|
|
253
353
|
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
const publicKey = getPublicKey(samePrivateKey);
|
|
257
|
-
// → Same publicKey = consistent cross-platform identity
|
|
354
|
+
```bash
|
|
355
|
+
npm install daku
|
|
258
356
|
```
|
|
259
357
|
|
|
260
|
-
|
|
261
|
-
> Reusing keypairs links user identity across services. This enables seamless cross-app experiences but reduces anonymity between services. For per-app isolation, derive or generate separate keys.
|
|
358
|
+
**Requirements:** Node.js 16+ or modern browser
|
|
262
359
|
|
|
263
360
|
---
|
|
264
361
|
|
|
265
|
-
##
|
|
362
|
+
## License
|
|
266
363
|
|
|
267
|
-
|
|
268
|
-
- **Token lifetime**: Hardcoded to 1 minute; prevent replay attacks.
|
|
269
|
-
- **POW difficulty**: Default = 2 leading zeros. Increase for high-traffic endpoints (trade-off: slower auth).
|
|
270
|
-
- **No server secrets**: DAKU has no shared secrets—everything is public-key cryptography.
|
|
364
|
+
ISC © [besoeasy](https://github.com/besoeasy)
|
|
271
365
|
|
|
272
366
|
---
|
|
273
367
|
|
|
274
|
-
|
|
368
|
+
<p align="center">
|
|
369
|
+
<b>Leave no trace. Just authenticate.</b>
|
|
370
|
+
</p>
|