ace-auth 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.
Files changed (2) hide show
  1. package/README.md +206 -129
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # ๐Ÿ›ก๏ธ AceAuth
2
2
 
3
- > **Stateful Security, Stateless Speed.**
4
- > An enterprise-grade identity management library featuring "Graceful Token Rotation," Device Fingerprinting, and Sliding Window sessions.
3
+ > **Stateful security. Stateless speed.**
4
+ > A production-grade authentication engine that combines JWT performance with server-side control using a hybrid, cache-aware architecture.
5
5
 
6
6
  [![NPM Version](https://img.shields.io/npm/v/ace-auth?style=flat-square)](https://www.npmjs.com/package/ace-auth)
7
7
  ![TypeScript](https://img.shields.io/badge/Language-TypeScript-blue?style=flat-square)
@@ -12,22 +12,47 @@
12
12
 
13
13
  ## ๐Ÿ’ก Why AceAuth?
14
14
 
15
- In modern web development, you typically have to choose between **Security** (short-lived JWTs) and **User Experience** (long-lived sessions).
15
+ Most authentication systems force a trade-off:
16
16
 
17
- **AceAuth gives you both.** It uses a **Hybrid Architecture** to maintain security without forcing users to log in repeatedly.
17
+ - **Stateless JWTs** โ†’ Fast, scalable, but impossible to revoke
18
+ - **Server sessions** โ†’ Secure and controllable, but harder to scale
18
19
 
19
- | Feature | Standard JWT | AceAuth |
20
- |------------------|-------------------------------|-----------------------------|
21
- | **Revocation** | โŒ Impossible until expiry | โœ… **Instant** (DB Backed) |
22
- | **Performance** | โœ… High (Stateless) | โœ… **High** (Redis Caching) |
23
- | **UX** | โŒ Hard Logout on expiry | โœ… **Graceful Auto-Rotation** |
24
- | **Device Mgmt** | โŒ None | โœ… **Active Sessions View** |
20
+ **AceAuth removes this trade-off.**
21
+
22
+ AceAuth uses:
23
+ - **JWTs as identifiers (not authority)**
24
+ - **A database as the source of truth**
25
+ - **A two-tier cache (RAM + DB) for performance**
26
+
27
+ This allows AceAuth to provide:
28
+ - Immediate revocation
29
+ - Transparent token rotation
30
+ - High throughput on hot paths
31
+ - Explicit, documented trade-offs
25
32
 
26
33
  ---
27
34
 
28
- ## ๐Ÿ“ฆ Installation
35
+ ## ๐Ÿง  Architecture Overview
36
+
37
+ ```
38
+ Client
39
+ โ†“
40
+ JWT (sessionId only)
41
+ โ†“
42
+ L1 Cache (RAM, short TTL)
43
+ โ†“
44
+ L2 Store (Redis / SQL / Mongo)
45
+ ```
46
+
47
+ - **Hot path**: Served entirely from RAM
48
+ - **Cold path**: Falls back to database
49
+ - **Writes**: Throttled to avoid load amplification
50
+
51
+ Bounded inconsistency window: **โ‰ค cacheTTL (default: 2 seconds)**
29
52
 
30
- Install AceAuth via npm:
53
+ ---
54
+
55
+ ## ๐Ÿ“ฆ Installation
31
56
 
32
57
  ```bash
33
58
  npm install ace-auth
@@ -37,186 +62,238 @@ npm install ace-auth
37
62
 
38
63
  ## ๐Ÿš€ Quick Start
39
64
 
40
- ### 1. Initialize
41
-
42
- AceAuth is database-agnostic. Below is a standard production setup using Redis:
65
+ ### 1๏ธโƒฃ Initialize AceAuth
43
66
 
44
- ```typescript
45
- import { AceAuth, RedisStore } from 'ace-auth';
46
- import { createClient } from 'redis';
67
+ AceAuth is storage-agnostic. You can plug in any supported database adapter.
47
68
 
48
- // 1. Connect to Redis
49
- const redis = createClient();
50
- await redis.connect();
69
+ ```ts
70
+ import { AceAuth } from 'ace-auth';
51
71
 
52
- // 2. Initialize Auth Engine
53
72
  const auth = new AceAuth({
54
- secret: process.env.JWT_SECRET || 'super-secret',
55
- store: new RedisStore(redis),
56
- sessionDuration: 30 * 24 * 60 * 60, // 30 Days (Sliding Window)
57
- tokenDuration: '15m', // Rotate token every 15 mins
58
- smtp: { // Optional: For Email OTP
59
- host: 'smtp.example.com',
60
- auth: { user: '...', pass: '...' }
61
- }
73
+ secret: process.env.JWT_SECRET!,
74
+ store: yourStore,
75
+ sessionDuration: 30 * 24 * 60 * 60, // 30 days
76
+ tokenDuration: '15m',
77
+ cacheTTL: 2000
62
78
  });
63
79
  ```
64
80
 
65
- ### 2. Login (Capture Device Info)
66
-
67
- Pass the request object (`req`) so AceAuth can fingerprint the device (IP/User-Agent).
68
-
69
- ```typescript
70
- import express from 'express';
71
- const app = express();
81
+ ---
72
82
 
73
- app.post('/api/login', async (req, res) => {
74
- // ... validate user credentials first ...
75
- const userId = 'user_123';
83
+ ## ๐Ÿ” Authentication Flow
76
84
 
77
- // Create Session & Token
78
- const { token, sessionId } = await auth.login({ id: userId, role: 'admin' }, req);
85
+ ### Login
79
86
 
80
- res.json({ token });
81
- });
87
+ ```ts
88
+ const { token, sessionId } = await auth.login(
89
+ { id: user.id, role: 'user' },
90
+ req
91
+ );
82
92
  ```
83
93
 
84
- ### 3. Protect Routes (Middleware)
94
+ - Creates a session in the database
95
+ - Stores session in L1 cache
96
+ - Issues a short-lived JWT (identifier only)
97
+
98
+ ---
85
99
 
86
- Use the included gatekeeper middleware to secure endpoints. It automatically handles Graceful Expiration.
100
+ ### Protect Routes (Middleware)
87
101
 
88
- ```typescript
102
+ ```ts
89
103
  import { gatekeeper } from 'ace-auth/middleware';
90
104
 
91
- app.get('/api/profile', gatekeeper(auth), (req, res) => {
92
- // If token was rotated, the new one is in res.headers['x-ace-token']
93
- res.json({ message: `Hello User ${req.user.id}` });
105
+ app.get('/profile', gatekeeper(auth), (req, res) => {
106
+ res.json({ user: req.user });
94
107
  });
95
108
  ```
96
109
 
110
+ If a token expires but the session is valid, AceAuth **automatically rotates it** and returns a new token via:
111
+
112
+ ```
113
+ X-Ace-Token: <new-token>
114
+ ```
115
+
97
116
  ---
98
117
 
99
- ## ๐Ÿ”Œ Database Adapters
118
+ ## ๐Ÿ”Œ Database Adapters (Full Implementations)
119
+
120
+ AceAuth works with any persistent store implementing `IStore`.
121
+
122
+ ---
100
123
 
101
- AceAuth works with any database. Import the specific adapter you need.
124
+ ## ๐ŸŸฅ Redis Adapter (Recommended)
102
125
 
103
- ### Redis (Recommended for Speed)
126
+ ### When to use
127
+ - High traffic APIs
128
+ - Real-time systems
129
+ - Horizontally scaled services
104
130
 
105
- Uses Secondary Indexing (Sets) to map Users โ†” Sessions for O(1) lookups.
131
+ ### Setup
106
132
 
107
- ```typescript
133
+ ```ts
134
+ import { createClient } from 'redis';
108
135
  import { RedisStore } from 'ace-auth/adapters';
109
- // Requires 'redis' package installed
110
- const store = new RedisStore(redisClient);
136
+
137
+ const redis = createClient();
138
+ await redis.connect();
139
+
140
+ const store = new RedisStore(redis);
111
141
  ```
112
142
 
113
- ### PostgreSQL (Persistent)
143
+ ### How it works
144
+ - Sessions stored as `sessionId โ†’ payload`
145
+ - Secondary index: `userId โ†’ set(sessionIds)`
146
+ - TTL enforced by Redis
147
+ - O(1) lookup for session revocation
148
+
149
+ ---
114
150
 
115
- Requires a table with columns: `sid` (text), `sess` (json), `expired_at` (timestamp).
151
+ ## ๐ŸŸฆ PostgreSQL Adapter
116
152
 
117
- ```typescript
118
- import { PostgresStore } from 'ace-auth/adapters';
119
- // Requires 'pg' pool
120
- const store = new PostgresStore(pool, 'auth_sessions_table');
153
+ ### When to use
154
+ - Strong consistency requirements
155
+ - Existing SQL infrastructure
156
+ - Auditable session history
157
+
158
+ ### Schema
159
+
160
+ ```sql
161
+ CREATE TABLE auth_sessions (
162
+ sid TEXT PRIMARY KEY,
163
+ user_id TEXT NOT NULL,
164
+ sess JSONB NOT NULL,
165
+ expires_at TIMESTAMP NOT NULL
166
+ );
167
+
168
+ CREATE INDEX idx_auth_sessions_user
169
+ ON auth_sessions(user_id);
121
170
  ```
122
171
 
123
- ### MongoDB
172
+ ### Setup
173
+
174
+ ```ts
175
+ import { Pool } from 'pg';
176
+ import { PostgresStore } from 'ace-auth/adapters';
124
177
 
125
- Stores sessions as documents. Good for no-setup environments.
178
+ const pool = new Pool({ connectionString: process.env.DATABASE_URL });
126
179
 
127
- ```typescript
128
- import { MongoStore } from 'ace-auth/adapters';
129
- // Requires 'mongoose' connection
130
- const store = new MongoStore(mongoose.connection.collection('sessions'));
180
+ const store = new PostgresStore(pool, 'auth_sessions');
131
181
  ```
132
182
 
133
- ---
183
+ ### Notes
184
+ - Expired sessions are lazily cleaned
185
+ - Indexed by `user_id` for fast logout-all
186
+ - Suitable for compliance-heavy systems
134
187
 
135
- ## ๐Ÿง  Advanced Features
188
+ ---
136
189
 
137
- ### ๐Ÿ“ฑ Device Management Dashboard
190
+ ## ๐ŸŸฉ MongoDB Adapter
138
191
 
139
- Allow users to see all their logged-in devices and remotely log them out (like Netflix/Google).
192
+ ### When to use
193
+ - Document-based stacks
194
+ - Rapid prototyping
195
+ - Flexible schemas
140
196
 
141
- ```typescript
142
- // GET /api/devices
143
- app.get('/api/devices', gatekeeper(auth), async (req, res) => {
144
- const sessions = await auth.getActiveSessions(req.user.id);
145
- res.json(sessions);
146
- });
197
+ ### Schema (Example)
147
198
 
148
- // POST /api/devices/logout-all
149
- app.post('/api/devices/logout-all', gatekeeper(auth), async (req, res) => {
150
- await auth.logoutAll(req.user.id);
151
- res.json({ success: true, message: "Logged out of all other devices" });
152
- });
199
+ ```js
200
+ {
201
+ _id: sessionId,
202
+ userId: "user_123",
203
+ sess: { ... },
204
+ expiresAt: ISODate()
205
+ }
153
206
  ```
154
207
 
155
- ### ๐Ÿ“ง Passwordless Login (OTP)
208
+ ### Setup
156
209
 
157
- Built-in support for generating and verifying Email One-Time-Passwords.
210
+ ```ts
211
+ import mongoose from 'mongoose';
212
+ import { MongoStore } from 'ace-auth/adapters';
158
213
 
159
- ```typescript
160
- // 1. Send Code
161
- app.post('/auth/send-code', async (req, res) => {
162
- await auth.sendOTP(req.body.email);
163
- res.send('Code sent!');
164
- });
214
+ await mongoose.connect(process.env.MONGO_URL);
165
215
 
166
- // 2. Verify & Login
167
- app.post('/auth/verify-code', async (req, res) => {
168
- const { valid } = await auth.verifyOTP(req.body.email, req.body.code);
169
-
170
- if (valid) {
171
- const { token } = await auth.login({ email: req.body.email }, req);
172
- res.json({ token });
173
- } else {
174
- res.status(401).send('Invalid Code');
175
- }
176
- });
216
+ const store = new MongoStore(
217
+ mongoose.connection.collection('auth_sessions')
218
+ );
177
219
  ```
178
220
 
221
+ ### Notes
222
+ - TTL index recommended on `expiresAt`
223
+ - Simple setup, no migrations required
224
+
179
225
  ---
180
226
 
181
- ## ๐Ÿ—๏ธ Architecture: "Graceful Expiration"
227
+ ## ๐Ÿ“ฑ Device & Session Management
182
228
 
183
- This is the core problem AceAuth solves.
229
+ ```ts
230
+ // List active sessions
231
+ const sessions = await auth.getActiveSessions(userId);
232
+
233
+ // Logout everywhere
234
+ await auth.logoutAll(userId);
235
+ ```
184
236
 
185
- **Scenario:** User leaves a tab open for 20 minutes. The 15-minute JWT expires.
237
+ - Device info captured at login
238
+ - Bounded cache delay โ‰ค cacheTTL
239
+ - Redis/DB is always source of truth
186
240
 
187
- - **Standard Library:** Request fails (401). User is forced to log in again. ๐Ÿ˜ก
188
- - **AceAuth:** Middleware catches the expiry error, checks the database, and issues a new token if the session is still valid.
241
+ ---
189
242
 
190
- ```mermaid
191
- sequenceDiagram
192
- participant Client
193
- participant Middleware
194
- participant Database
243
+ ## ๐Ÿ“ง Passwordless OTP (Email)
195
244
 
196
- Client->>Middleware: Sends Request (Token Expired)
197
- Middleware->>Middleware: Signature Valid? โœ…
198
- Middleware->>Middleware: Time Check: Expired โŒ
199
-
200
- Note right of Middleware: "Graceful Rescue" Triggered
201
-
202
- Middleware->>Database: Check Session ID
203
- Database-->>Middleware: Session Active (30 Days left)
204
-
205
- Middleware->>Client: 200 OK + New Token (Header)
245
+ ```ts
246
+ await auth.sendOTP(email);
247
+ await auth.verifyOTP(email, code);
206
248
  ```
207
249
 
250
+ - OTPs are single-use
251
+ - Auto-expire (10 minutes)
252
+ - Stored server-side only
253
+
254
+ ---
255
+
256
+ ## ๐Ÿ“Š Benchmarks
257
+
258
+ AceAuth is benchmarked against:
259
+ - Raw JWT
260
+ - Passport.js
261
+ - express-session
262
+
263
+ Results show AceAuth:
264
+ - Outperforms Passport.js on hot paths
265
+ - Retains server-side revocation
266
+ - Trades minimal latency for correctness
267
+
268
+ See **BENCHMARKS.md** for full data.
269
+
270
+ ---
271
+
272
+ ## ๐Ÿ” Security Guarantees
273
+
274
+ - Server-side revocation
275
+ - Token rotation handled internally
276
+ - JWT payloads contain no user data
277
+ - Bounded cache staleness (explicit)
278
+ - Write throttling prevents DB overload
279
+
208
280
  ---
209
281
 
210
- ## ๐Ÿงช Security & Testing
282
+ ## โ“ When to Use AceAuth
211
283
 
212
- This library is 100% covered by tests using Vitest.
284
+ Use AceAuth if you need:
285
+ - JWT-like scalability
286
+ - Immediate logout across devices
287
+ - Transparent refresh UX
288
+ - Measured, explainable behavior
213
289
 
214
- - โœ… **Replay Protection:** OTPs are deleted immediately after use.
215
- - โœ… **Tamper Proofing:** Tokens signed with invalid secrets are rejected immediately.
216
- - โœ… **Lazy Cleanup:** Expired sessions are automatically cleaned up from the user index during read operations to prevent memory leaks.
290
+ Avoid if you want:
291
+ - Pure stateless JWT only
292
+ - Cookie-only sessions
293
+ - OAuth / SSO (out of scope)
217
294
 
218
295
  ---
219
296
 
220
297
  ## ๐Ÿ“„ License
221
298
 
222
- MIT
299
+ MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ace-auth",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "description": "Enterprise-grade identity management with graceful token rotation",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",