auth-events 0.0.10 → 1.0.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.
Files changed (3) hide show
  1. package/README.md +274 -103
  2. package/dist/index.d.ts +59 -5
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -2,166 +2,337 @@
2
2
 
3
3
  ![npm](https://img.shields.io/npm/v/auth-events)
4
4
 
5
+ # Auth Events
5
6
 
7
+ **`auth-events`** is a lightweight, powerful, and extensible Node.js library to handle authentication and user-related events in your application. It provides an **event-driven architecture** for login, logout, registration, password changes, role updates, device tracking, risk signals, and more.
6
8
 
7
- # auth-events Authentication Event Engine for Node.js
9
+ **`auth-events`** is a lightweight, powerful, and extensible Node.js library to handle authentication and user-related events in your application. It provides an **event-driven architecture** for login, logout, registration, password changes, role updates, device tracking, risk signals, and more.
8
10
 
9
- A lightweight, open-source Node.js library to **listen, track, and react to authentication events** in a clean, event-driven way.
11
+ Designed for **security, audit, and automation**, it works with any auth provider (custom, Google, Firebase, Auth0, etc.) and can power your **enterprise-grade authentication workflows**.
10
12
 
11
- Authentication providers like Auth0, Clerk, Firebase, or custom JWT systems handle authentication well — but they don’t give you enough control over what happens *after authentication.*
13
+ ---
14
+
15
+ ## Features
12
16
 
13
- That’s where **auth-events** fits in.
17
+ - 🔹 **Core Auth Events:** login, logout, register, password changes, role updates
18
+ - 🔹 **Security & Risk Events:** suspicious login, brute force detection, IP/device risk, geo-velocity
19
+ - 🔹 **Session & Token Lifecycle:** session creation, expiration, token issued/revoked/refresh
20
+ - 🔹 **Device & Trust Tracking:** new device detection, device trust/untrust
21
+ - 🔹 **Multi-Factor & Verification Events:** OTP, 2FA, email/phone verification
22
+ - 🔹 **Update/Change Tracking:** profile updates, email/phone changes, previous and new values
23
+ - 🔹 **Audit & Meta:** requestId, correlationId, custom metadata
24
+ - 🔹 **Developer-Friendly Context:** logger, db, cache, env injected into handlers
25
+ - 🔹 **Decision-Aware Handlers:** handlers can allow, block, or challenge actions
26
+ - 🔹 **Enterprise Ready:** support for admin actions, automation, security scoring
14
27
 
15
28
  ---
16
29
 
17
- ## 🚀 What Problem Does It Solve?
30
+ ## Installation
18
31
 
19
- Most applications need to react when authentication events occur.
32
+ ```bash
33
+ npm install auth-events
34
+ # or
35
+ yarn add auth-events
20
36
 
21
- | Event | Purpose |
22
- |------|--------|
23
- | User logs in | Track activity |
24
- | Password changes | Revoke sessions |
25
- | Role changes | Sync permissions |
26
- | Suspicious login | Trigger security flows |
37
+ auth-events
27
38
 
28
- Instead of scattering this logic across your backend, **auth-events centralizes it using events.**
39
+ A lightweight event layer for authentication flows.
29
40
 
30
- ---
41
+ 🧠 Mental Model (Read this first)
31
42
 
32
- ## Features
43
+ Think of authentication in two responsibilities:
33
44
 
34
- - Event-Driven Authentication Logic
35
- - Provider-Agnostic (Auth0, Clerk, Firebase, JWT, etc.)
36
- - Strong TypeScript Support
37
- - Full Post-Authentication Control
38
- - Minimal & Lightweight
39
- - No heavy dependencies
45
+ Auth Code → WHAT happened?
46
+ Auth Events WHAT should we do about it?
40
47
 
41
- ---
42
48
 
43
- ## ⚡ Installation
49
+ Examples:
44
50
 
45
- ```bash
46
- npm install auth-events
47
- ```
51
+ Login happened → emit event
48
52
 
49
- or
53
+ Password changed → emit event
50
54
 
51
- ```bash
52
- yarn add auth-events
53
- ```
55
+ New device detected → emit event
54
56
 
55
- ---
57
+ auth-events only broadcasts facts.
58
+ It does not decide business logic.
56
59
 
57
- ## 🧠 Core Concept
60
+ This keeps authentication clean and predictable.
58
61
 
59
- You **emit events when authentication happens**, and **subscribe to them anywhere in your app.**
62
+ Why auth-events?
60
63
 
61
- Supported event types:
64
+ Authentication logic often becomes bloated over time.
62
65
 
63
- ```ts
64
- export type AuthEventType =
65
- | "login"
66
- | "logout"
67
- | "password_changed"
68
- | "role_changed";
69
- ```
66
+ A simple login flow slowly accumulates responsibilities:
70
67
 
71
- ---
68
+ audit logging
72
69
 
73
- ## 📦 Basic Usage
70
+ security checks
74
71
 
75
- ### 1️⃣ Import the Library
72
+ analytics
76
73
 
77
- ```ts
78
- import { auth } from "auth-events";
79
- ```
74
+ notifications
80
75
 
81
- ---
76
+ Soon, your auth code becomes:
77
+
78
+ hard to read
79
+
80
+ hard to test
81
+
82
+ risky to change
83
+
84
+ auth-events solves this by introducing a small event layer after authentication.
85
+
86
+ Auth code emits events.
87
+ Side-effects live elsewhere.
88
+
89
+ 🧩 How it works
90
+
91
+ Your app emits an auth event (e.g. "login").
92
+
93
+ One or more listeners react to that event.
94
+
95
+ Authentication logic stays clean and focused.
96
+
97
+ There is no coupling between auth code and side-effects.
98
+
99
+ 📁 Recommended File Structure
100
+
101
+ This is where most projects go wrong — structure matters.
102
+
103
+ src/
104
+ ├─ auth/
105
+ │ ├─ auth.controller.ts # login, signup, logout
106
+ │ ├─ auth.service.ts # password verification, token logic
107
+
108
+ ├─ auth-events/
109
+ │ ├─ index.ts # single AuthEvents instance
110
+ │ ├─ listeners/
111
+ │ │ ├─ audit.listener.ts
112
+ │ │ ├─ security.listener.ts
113
+ │ │ ├─ analytics.listener.ts
114
+ │ │ └─ notification.listener.ts
115
+
116
+ ├─ app.ts
117
+ └─ server.ts
82
118
 
83
- ### 2️⃣ Listen to Authentication Events
119
+ 🧩 Step 1: Create one global AuthEvents instance
84
120
 
85
- #### Login Event
121
+ 📍 src/auth-events/index.ts
86
122
 
87
- ```ts
88
- auth.on("login", (event) => {
89
- console.log(`User ${event.userId} logged in at ${event.timestamp}`);
123
+ import { AuthEvents } from "auth-events";
124
+
125
+ export const authEvents = new AuthEvents();
126
+
127
+
128
+ ⚠️ Important
129
+
130
+ Your application should have only one AuthEvents instance.
131
+ All listeners and emitters must use this same instance.
132
+
133
+ 🧩 Step 2: Emit events inside existing auth code
134
+
135
+ 📍 src/auth/auth.controller.ts
136
+
137
+ import { authEvents } from "../auth-events";
138
+
139
+ export const login = async (req, res) => {
140
+ const user = await authService.login(req.body);
141
+
142
+ // Emit fact, not logic
143
+ await authEvents.emit("login", {
144
+ userId: user.id,
145
+ ip: req.ip,
146
+ userAgent: req.headers["user-agent"],
147
+ sessionId: req.sessionID
148
+ )});
149
+
150
+ res.json({ token: user.token });
151
+ };
152
+
153
+
154
+ ✅ Login responsibility = done
155
+ ❌ No logging
156
+ ❌ No analytics
157
+ ❌ No security rules
158
+
159
+ 🧩 Step 3: Attach operations using listeners
160
+
161
+ This is where auth-events shines.
162
+
163
+ 🔐 Security listener
164
+
165
+ 📍 auth-events/listeners/security.listener.ts
166
+
167
+ import { authEvents } from "../index";
168
+
169
+ authEvents.on("login", async (event) => {
170
+ if (isNewDevice(event)) {
171
+ await authEvents.emit("new_device_detected", event);
172
+ }
90
173
  });
91
- ```
92
174
 
93
- #### Password Change Event
175
+ 📜 Audit logging
94
176
 
95
- ```ts
96
- auth.on("password_changed", (event) => {
97
- console.log(`Password changed for user ${event.userId}`);
177
+ 📍 auth-events/listeners/audit.listener.ts
98
178
 
99
- // Example:
100
- // revokeAllSessions(event.userId);
179
+ authEvents.on("login", async (event) => {
180
+ await AuditLog.create({
181
+ userId: event.userId,
182
+ action: "LOGIN",
183
+ ip: event.ip,
184
+ userAgent: event.userAgent
185
+ });
101
186
  });
102
- ```
103
187
 
104
- ---
188
+ 📊 Analytics tracking
189
+
190
+ 📍 auth-events/listeners/analytics.listener.ts
191
+
192
+ authEvents.on("login", async (event) => {
193
+ analytics.track("user_login", {
194
+ userId: event.userId,
195
+ device: event.userAgent
196
+ )});
105
197
 
106
- ### 3️⃣ Emit Events from Your Auth Logic
198
+ 🔔 Notifications
107
199
 
108
- #### Example: Login Controller
200
+ 📍 auth-events/listeners/notification.listener.ts
109
201
 
110
- ```ts
111
- auth.emit("login", {
112
- userId: user.id,
113
- timestamp: Date.now(),
114
- ipAddress: req.ip,
202
+ authEvents.on("new_device_detected", async (event) => {
203
+ await sendEmail({
204
+ to: event.userId,
205
+ subject: "New device login detected"
206
+ });
115
207
  });
116
- ```
117
208
 
118
- #### Example: Password Update
119
209
 
120
- ```ts
121
- auth.emit("password_changed", {
122
- userId: user.id,
123
- timestamp: Date.now(),
210
+
211
+ // Emit a login event
212
+ await authEvents.login({
213
+ userId: "123",
214
+ email: "user@example.com",
215
+ ip: "192.168.1.1",
216
+ deviceId: "device_abc123",
217
+ deviceType: "desktop",
218
+ browser: "Chrome",
219
+ country: "IN",
220
+ riskScore: 25,
221
+ status: "success"
124
222
  });
125
- ```
223
+ AuthEvent Interface
224
+ Each event provides a rich set of fields for security, auditing, and automation:
225
+
226
+ export interface AuthEvent {
227
+ type: AuthEventType;
228
+ userId: string;
229
+ email?: string;
230
+ roles?: string[];
231
+
232
+ // Session & Token
233
+ sessionId?: string;
234
+ tokenId?: string;
235
+ tokenType?: "jwt" | "session";
236
+ tokenIssuedAt?: Date;
237
+ tokenExpiresAt?: Date;
238
+
239
+ // Network
240
+ ip?: string;
241
+ isp?: string;
242
+ country?: string;
243
+ region?: string;
244
+ city?: string;
245
+ timezone?: string;
246
+
247
+ // Device
248
+ deviceId?: string;
249
+ deviceType?: "mobile" | "desktop" | "tablet";
250
+ os?: string;
251
+ browser?: string;
252
+ userAgent?: string;
253
+
254
+ // Auth context
255
+ provider?: "google" | "firebase" | "auth0" | "custom";
256
+ origin?: "web" | "mobile" | "api";
257
+ referrer?: string;
258
+ status?: "success" | "failed";
259
+ failureReason?: string;
260
+ attemptCount?: number;
261
+ authMethod?: "password" | "oauth" | "magic_link" | "otp";
262
+
263
+ // Risk signals
264
+ riskScore?: number;
265
+ deviceRiskScore?: number;
266
+ geoVelocityRisk?: boolean;
267
+ isNewDevice?: boolean;
268
+ isNewIP?: boolean;
269
+ isProxy?: boolean;
270
+ isTor?: boolean;
271
+ isBot?: boolean;
272
+
273
+ // Update / Change tracking
274
+ changedFields?: string[];
275
+ previousValues?: Record<string, any>;
276
+ newValues?: Record<string, any>;
277
+ updatedBy?: string;
278
+ updatedVia?: "user" | "admin" | "api" | "system";
279
+ changeId?: string;
280
+ previousVersion?: number;
281
+ newVersion?: number;
282
+
283
+ // Meta & audit
284
+ metadata?: Record<string, any>;
285
+ requestId?: string;
286
+ correlationId?: string;
287
+
288
+ timestamp: Date;
289
+ }
290
+
291
+
292
+ AuthEventType
293
+ All supported events (enterprise-ready):
126
294
 
127
- ---
295
+ export type AuthEventType =
296
+ | "login" | "logout" | "register" | "login_failed"
297
+ | "suspicious_login" | "brute_force_detected"
298
+ | "account_locked" | "account_unlocked"
299
+ | "ip_blocked" | "device_blocked" | "location_changed"
300
+ | "otp_sent" | "otp_verified" | "otp_failed"
301
+ | "mfa_enabled" | "mfa_disabled" | "email_verified" | "phone_verified"
302
+ | "session_created" | "session_revoked" | "session_expired" | "session_refreshed"
303
+ | "token_issued" | "token_refreshed" | "token_revoked" | "token_expired"
304
+ | "new_device_detected" | "device_trusted" | "device_untrusted" | "device_removed"
305
+ | "password_changed" | "role_changed"
306
+ | "profile_updated" | "email_changed" | "phone_changed"
307
+ | "rate_limit_exceeded" | "policy_violation" | "security_rule_triggered" | "risk_score_updated"
308
+ | "provider_linked" | "provider_unlinked" | "provider_login" | "provider_error";
128
309
 
129
- Where Can You Use This?
130
310
 
131
- - Security monitoring
132
- - Session management
133
- - Audit logs
134
- - Analytics & tracking
135
- - Notifications
136
- - Role & permission syncing
137
- - Compliance logging
138
311
 
139
- ---
140
312
 
141
- Works With
313
+ Developer Tips
142
314
 
143
- - Auth0
144
- - Clerk
145
- - Firebase Auth
146
- - Custom JWT / Session Auth
147
- - Any Node.js backend
315
+ Use changedFields, previousValues, and newValues for auditing profile updates.
148
316
 
149
- ---
317
+ Use riskScore, isNewDevice, and geoVelocityRisk for security automation.
150
318
 
151
- Philosophy
319
+ Handlers can return actions: allow, block, or challenge (OTP, 2FA).
152
320
 
153
- **Authentication tells you who the user is.**
154
- **auth-events tells you what to do next.**
321
+ Inject logger, db, cache in context for advanced workflows.
155
322
 
156
- ---
323
+ Can be extended with plugins or middleware for notifications (email/SMS), dashboards, or analytics.
157
324
 
158
- Contributing
159
325
 
160
- Contributions and feedback are welcome.
161
- Open an issue or submit a pull request 🚀
162
326
 
163
- ---
327
+ Why use auth-events?
328
+ Single source of truth for all auth-related actions
329
+ Real-time risk analysis and automation
330
+ Easy to integrate with any auth provider (custom, Firebase, Auth0, etc.)
331
+ Enterprise-ready with audit trails, session management, MFA, and device trust
164
332
 
165
- License
166
333
 
167
- MIT License
334
+ Future Improvements
335
+ Webhooks / external notifications
336
+ Priority-based handler execution
337
+ Event persistence for audit / replay
338
+ Rule engine for automated security actions
package/dist/index.d.ts CHANGED
@@ -1,18 +1,72 @@
1
- type AuthEventType = "login" | "logout" | "register" | "password_changed" | "role_changed" | "session_revoked" | "suspicious_login" | "token_expired";
1
+ type AuthEventType = "login" | "logout" | "register" | "login_failed" | "suspicious_login" | "brute_force_detected" | "account_locked" | "account_unlocked" | "ip_blocked" | "device_blocked" | "location_changed" | "otp_sent" | "otp_verified" | "otp_failed" | "mfa_enabled" | "mfa_disabled" | "email_verified" | "phone_verified" | "session_created" | "session_revoked" | "session_expired" | "session_refreshed" | "token_issued" | "token_refreshed" | "token_revoked" | "token_expired" | "new_device_detected" | "device_trusted" | "device_untrusted" | "device_removed" | "password_changed" | "role_changed" | "profile_updated" | "email_changed" | "phone_changed" | "rate_limit_exceeded" | "policy_violation" | "security_rule_triggered" | "risk_score_updated" | "provider_linked" | "provider_unlinked" | "provider_login" | "provider_error";
2
2
  interface AuthEvent {
3
3
  type: AuthEventType;
4
4
  userId: string;
5
+ email?: string;
6
+ roles?: string[];
5
7
  sessionId?: string;
8
+ tokenId?: string;
9
+ tokenType?: "jwt" | "session";
10
+ tokenIssuedAt?: Date;
11
+ tokenExpiresAt?: Date;
6
12
  ip?: string;
13
+ isp?: string;
14
+ country?: string;
15
+ region?: string;
16
+ city?: string;
17
+ timezone?: string;
18
+ deviceId?: string;
19
+ deviceType?: "mobile" | "desktop" | "tablet";
20
+ os?: string;
21
+ browser?: string;
7
22
  userAgent?: string;
8
23
  provider?: "google" | "firebase" | "auth0" | "custom";
9
- email?: string;
10
- roles?: string[];
24
+ origin?: "web" | "mobile" | "api";
25
+ referrer?: string;
11
26
  status?: "success" | "failed";
27
+ failureReason?: string;
28
+ attemptCount?: number;
29
+ authMethod?: "password" | "oauth" | "magic_link" | "otp";
30
+ riskScore?: number;
31
+ deviceRiskScore?: number;
32
+ geoVelocityRisk?: boolean;
33
+ isNewDevice?: boolean;
34
+ isNewIP?: boolean;
35
+ isProxy?: boolean;
36
+ isTor?: boolean;
37
+ isBot?: boolean;
38
+ changedFields?: string[];
39
+ previousValues?: Record<string, any>;
40
+ newValues?: Record<string, any>;
41
+ updatedBy?: string;
42
+ updatedVia?: "user" | "admin" | "api" | "system";
43
+ changeId?: string;
44
+ previousVersion?: number;
45
+ newVersion?: number;
12
46
  metadata?: Record<string, any>;
47
+ requestId?: string;
48
+ correlationId?: string;
13
49
  timestamp: Date;
14
50
  }
15
- type AuthEventHandler = (event: AuthEvent, context: unknown) => void | Promise<void>;
51
+ interface AuthEventContext {
52
+ /** Unique request identifier for tracing */
53
+ requestId?: string;
54
+ /** Client network info */
55
+ ip?: string;
56
+ userAgent?: string;
57
+ /** Logger injected by host application */
58
+ logger?: {
59
+ info(message: string, meta?: Record<string, any>): void;
60
+ warn(message: string, meta?: Record<string, any>): void;
61
+ error(message: string, meta?: Record<string, any>): void;
62
+ };
63
+ /** Optional shared resources */
64
+ db?: unknown;
65
+ cache?: unknown;
66
+ /** Runtime environment */
67
+ env?: "development" | "staging" | "production";
68
+ }
69
+ type AuthEventHandler = (event: AuthEvent, context: AuthEventContext) => void | Promise<void>;
16
70
 
17
71
  declare class AuthEvents {
18
72
  private bus;
@@ -21,4 +75,4 @@ declare class AuthEvents {
21
75
  private createContext;
22
76
  }
23
77
 
24
- export { AuthEvent, AuthEventHandler, AuthEventType, AuthEvents };
78
+ export { AuthEvent, AuthEventContext, AuthEventHandler, AuthEventType, AuthEvents };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "auth-events",
3
- "version": "0.0.10",
3
+ "version": "1.0.0",
4
4
  "description": "A lightweight Node.js library to track and react to authentication events across any auth provider.",
5
5
  "type": "module",
6
6
  "license": "MIT",