strapi-plugin-magic-sessionmanager 3.3.1 → 3.4.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 CHANGED
@@ -1,1298 +1,463 @@
1
1
  # Magic Session Manager 🔐
2
2
 
3
- **Advanced Session Management for Strapi v5** - Track user login/logout, monitor active sessions, and secure your application with IP geolocation, threat detection, and real-time analytics.
3
+ **See who's logged into your Strapi app - and control their sessions!**
4
4
 
5
- [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
6
- [![npm version](https://img.shields.io/npm/v/strapi-plugin-magic-sessionmanager.svg)](https://www.npmjs.com/package/strapi-plugin-magic-sessionmanager)
7
- [![GitHub release](https://img.shields.io/github/v/release/Schero94/Magic-Sessionmanager.svg)](https://github.com/Schero94/Magic-Sessionmanager/releases)
5
+ Track logins, monitor active users, and secure your app with one simple plugin. No complicated setup required.
8
6
 
9
- ---
10
-
11
- ## 📋 Table of Contents
12
-
13
- - [Features](#features)
14
- - [Quick Start](#quick-start)
15
- - [How It Works](#how-it-works)
16
- - [Strapi Integration](#strapi-integration)
17
- - [Admin Dashboard](#admin-dashboard)
18
- - [API Routes](#api-routes)
19
- - [Configuration](#configuration)
20
- - [Premium Features](#premium-features)
21
- - [Use Cases](#use-cases)
22
- - [Testing](#testing)
23
- - [Troubleshooting](#troubleshooting)
24
- - [Development](#development)
25
-
26
- ---
27
-
28
- ## ✨ Features
29
-
30
- ### Core Session Management
31
- ✅ **Automatic Session Tracking** - Sessions created on login, terminated on logout
32
- ✅ **Session History** - Complete record of all login/logout events with IP & browser
33
- ✅ **Activity Monitoring** - Track last seen time with rate limiting
34
- ✅ **Multi-Session Support** - Users can have multiple active sessions
35
- ✅ **Auto-Cleanup** - Inactive sessions automatically marked inactive
36
- ✅ **Real-time Dashboard** - View all active & historical sessions
37
-
38
- ### Security Features (Premium)
39
- 🔒 **IP Geolocation** - Get country, city, ISP from IP addresses
40
- 🔒 **Threat Detection** - Identify VPN, proxy, and threat IPs
41
- 🔒 **Geo-Fencing** - Block/allow logins by country
42
- 🔒 **Security Scoring** - Risk analysis for each login
43
- 🔒 **Auto-Blocking** - Prevent logins from high-risk locations
44
- 🔒 **Email Alerts** - Notify users of suspicious login attempts
45
- 🔒 **Webhook Notifications** - Send Discord/Slack alerts on key events
46
-
47
- ### Admin Dashboard
48
- 📊 **Active Sessions** - Real-time view of logged-in users
49
- 📊 **Analytics** - Session trends, concurrent users, geo-heatmap
50
- 📊 **Settings** - Configure timeouts, notifications, geo-restrictions
51
- 📊 **License Management** - Built-in license activation interface
52
-
53
- ### Non-Invasive Architecture
54
- ✅ **No Core Modifications** - Pure plugin, zero changes to Strapi core
55
- ✅ **Runtime Injection** - Middleware-based architecture
56
- ✅ **DB-Backed** - Uses `plugin::magic-sessionmanager.session` content type
57
- ✅ **License-Based** - Premium features via license key
7
+ [![NPM](https://img.shields.io/npm/v/strapi-plugin-magic-sessionmanager.svg)](https://www.npmjs.com/package/strapi-plugin-magic-sessionmanager)
8
+ [![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
58
9
 
59
10
  ---
60
11
 
61
- ## 🚀 Quick Start
62
-
63
- ### 1. Install Plugin
64
-
65
- ```bash
66
- npm install strapi-plugin-magic-sessionmanager
67
- # or
68
- yarn add strapi-plugin-magic-sessionmanager
69
- ```
70
-
71
- ### 2. Register in Config
72
-
73
- Add to `src/config/plugins.ts` (or `plugins.js`):
74
-
75
- ```typescript
76
- export default () => ({
77
- 'magic-sessionmanager': {
78
- enabled: true,
79
- resolve: './src/plugins/magic-sessionmanager',
80
- config: {
81
- // Optional: rate limit for lastSeen updates (ms)
82
- lastSeenRateLimit: 30000, // 30 seconds (default)
83
-
84
- // Optional: session inactivity timeout (ms)
85
- inactivityTimeout: 15 * 60 * 1000, // 15 minutes (default)
86
- },
87
- },
88
- });
89
- ```
90
-
91
- ### 3. Build & Run
92
-
93
- ```bash
94
- # Install dependencies
95
- npm install
96
-
97
- # Build the plugin (includes admin UI)
98
- npm run build
99
-
100
- # Start Strapi
101
- npm run develop
102
- ```
103
-
104
- ### 4. Configure Encryption (Important!) 🔐
12
+ ## 📸 What It Looks Like
105
13
 
106
- Generate a secure encryption key for JWT token storage:
14
+ ### Main Dashboard - See All Active Sessions
107
15
 
108
- ```bash
109
- # Option 1: Use Admin Panel
110
- # Go to Admin → Sessions → Settings → Security Settings
111
- # Click "Generate Key" and copy to .env
112
-
113
- # Option 2: Generate manually
114
- node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"
115
-
116
- # Add to .env file:
117
- SESSION_ENCRYPTION_KEY=your-generated-32-char-key-here
118
- ```
119
-
120
- **Why this is important:**
121
- - JWT tokens are encrypted before storing in database
122
- - Prevents token exposure if database is compromised
123
- - Uses AES-256-GCM encryption standard
16
+ ![Dashboard](pics/dashboard.png)
124
17
 
125
- ### 5. Access Admin Dashboard
126
-
127
- - Navigate to Strapi Admin: `http://localhost:1337/admin`
128
- - Find **Sessions** in the left sidebar under plugins
129
- - Start with the **License** tab to activate your license
130
- - Go to **Settings → Security** to generate your encryption key
18
+ **What you see:**
19
+ - Who is logged in right now (green = online)
20
+ - When they logged in
21
+ - What device they're using
22
+ - Their IP address and location
23
+ - One-click session termination
131
24
 
132
25
  ---
133
26
 
134
- ## 🔄 How It Works
135
-
136
- ### Architecture Overview
137
-
138
- Magic Session Manager works by **intercepting Strapi's native authentication routes** WITHOUT replacing them. It uses middleware to hook into the authentication flow:
139
-
140
- ```
141
- ┌─────────────────────────────────────────────────────────┐
142
- │ Client sends: │
143
- │ POST /api/auth/local │
144
- │ { identifier: "user@example.com", password: "pass123" }│
145
- └────────────────┬────────────────────────────────────────┘
146
-
147
-
148
- ┌─────────────────────────────────────────────────────────┐
149
- │ Strapi's Native Auth (users-permissions plugin) │
150
- │ - Validates credentials │
151
- │ - Creates JWT token │
152
- │ - Returns: { jwt: "...", user: {...} } │
153
- └────────────────┬────────────────────────────────────────┘
154
-
155
-
156
- ┌─────────────────────────────────────────────────────────┐
157
- │ Magic Session Manager Middleware (AFTER auth) │
158
- │ - Detects successful login (status 200 + user object) │
159
- │ - Extracts: IP, User Agent, JWT Token │
160
- │ - [PREMIUM] Checks IP geolocation & threat level │
161
- │ - [PREMIUM] Applies geo-fencing rules │
162
- │ - Creates session record in database │
163
- │ - [PREMIUM] Sends notifications (email/webhook) │
164
- └────────────────┬────────────────────────────────────────┘
165
-
166
-
167
- ┌─────────────────────────────────────────────────────────┐
168
- │ Response returned to client (unchanged) │
169
- │ { jwt: "...", user: {...} } │
170
- └─────────────────────────────────────────────────────────┘
171
- ```
172
-
173
- ### Login Flow (Detailed)
174
-
175
- ```
176
- User Login Request
177
-
178
- [POST /api/auth/local]
179
- Body: { identifier, password }
180
-
181
- Strapi Auth validates credentials
182
-
183
- ✅ Success → Strapi creates JWT token
184
-
185
- Strapi prepares response: { jwt, user }
186
-
187
- [Magic Session Manager Middleware INTERCEPTS]
188
-
189
- Extract from response:
190
- - user.id
191
- - ctx.body.jwt (Access Token)
192
- - IP address (from headers/proxies)
193
- - User Agent (browser info)
194
-
195
- [PREMIUM] Check IP Geolocation:
196
- - Get country, city, ISP
197
- - Detect VPN/Proxy/Threat
198
- - Calculate security score (0-100)
199
- - Apply geo-fencing rules
200
-
201
- [PREMIUM] Auto-blocking if:
202
- - Known threat IP (isThreat = true)
203
- - VPN detected (isVpn = true)
204
- - Country blocked (not in allowlist)
205
- - Security score < 50
206
-
207
- Block? NO → Continue ✅
208
- Block? YES → Return 403 Forbidden ❌
209
-
210
- Create plugin::magic-sessionmanager.session record:
211
- {
212
- user: userId,
213
- token: jwt, // Access Token
214
- ipAddress: "192.168.1.100",
215
- userAgent: "Mozilla/5.0...",
216
- loginTime: now,
217
- lastActive: now,
218
- isActive: true,
219
- geoLocation: {...}, // Premium
220
- securityScore: 95 // Premium
221
- }
222
-
223
- [PREMIUM] Send notifications:
224
- - Email alert (if suspicious)
225
- - Webhook (Discord/Slack)
226
-
227
- Return response to client (unchanged):
228
- { jwt: "...", user: {...} }
229
- ```
230
-
231
- ### Logout Flow
232
-
233
- Magic Session Manager **replaces** the default `/api/auth/logout` route:
234
-
235
- ```
236
- User Logout Request
237
-
238
- [POST /api/auth/logout]
239
- Headers: { Authorization: "Bearer <JWT>" }
240
-
241
- Magic Session Manager Handler (NOT Strapi's default)
242
-
243
- Extract JWT from Authorization header
244
-
245
- Find matching session:
246
- WHERE token = jwt AND isActive = true
247
-
248
- Found? YES → Update session:
249
- {
250
- isActive: false,
251
- logoutTime: now
252
- }
253
-
254
- Found? NO → Continue anyway (idempotent)
255
-
256
- Return: { message: "Logged out successfully" }
257
- ```
27
+ ### Session Details Modal
258
28
 
259
- ### Activity Tracking
29
+ ![Session Modal](pics/dashboardsessionmodal.png)
260
30
 
261
- Every authenticated request updates `lastActive`:
31
+ **Click any session to see:**
32
+ - Full device information
33
+ - Browser and operating system
34
+ - Complete session history
35
+ - IP geolocation (Premium)
36
+ - Security risk score (Premium)
262
37
 
263
- ```
264
- Authenticated API Request
265
- (Any route with valid JWT)
266
-
267
- [LastSeen Middleware - BEFORE request]
268
-
269
- Check: Does user have active session?
270
- WHERE user.id = X AND isActive = true
271
-
272
- NO active sessions?
273
- → Reject: 401 Unauthorized
274
- → Message: "All sessions terminated. Please login again."
275
-
276
- Has active session? Continue ✅
277
-
278
- [Process actual request]
279
-
280
- [LastSeen Middleware - AFTER request]
281
-
282
- Check: Was lastActive updated < 30s ago?
283
- (Rate limiting to prevent DB noise)
284
-
285
- YES (recently updated) → Skip ⏭️
286
- NO (old timestamp) → Update session:
287
- {
288
- lastActive: now
289
- }
290
-
291
- Request complete
292
- ```
38
+ ---
293
39
 
294
- ### Periodic Cleanup
40
+ ### Content Manager Integration
295
41
 
296
- Runs automatically every 30 minutes:
42
+ ![Session Info Panel](pics/sessioninfopanel.png)
297
43
 
298
- ```
299
- Cleanup Job (every 30 min)
300
-
301
- Find sessions where:
302
- lastActive < (now - inactivityTimeout)
303
- AND isActive = true
304
-
305
- For each inactive session:
306
- Update: isActive = false
307
-
308
- Log: "Cleaned up X inactive sessions"
309
- ```
44
+ **When viewing a user:**
45
+ - Sidebar shows their active sessions
46
+ - Quick actions (terminate, block)
47
+ - Offline/Online status indicator
48
+ - No need to leave the page!
310
49
 
311
50
  ---
312
51
 
313
- ## 🔌 Strapi Integration
314
-
315
- ### Routes Integration
52
+ ### Settings Page
316
53
 
317
- #### Native Strapi Routes (Intercepted)
54
+ ![Settings 1](pics/settings1.png)
318
55
 
319
- | Route | Method | Magic Session Manager Action |
320
- |-------|--------|------------------------------|
321
- | `/api/auth/local` | `POST` | **Intercepted** - Middleware runs AFTER Strapi auth creates JWT, then creates session |
322
- | `/api/auth/local/register` | `POST` | **Intercepted** - Same as login (auto-login after registration) |
56
+ **Easy configuration:**
57
+ - Session timeouts
58
+ - Rate limiting
59
+ - Email alerts
60
+ - Webhook notifications
61
+ - Geo-blocking rules
323
62
 
324
- #### Overridden Routes
63
+ ![Settings 2](pics/settings2.png)
325
64
 
326
- | Route | Method | Magic Session Manager Action |
327
- |-------|--------|------------------------------|
328
- | `/api/auth/logout` | `POST` | **Replaced** - Custom handler terminates session by JWT token |
329
-
330
- #### Plugin Routes
65
+ **Advanced security:**
66
+ - Encryption key generator (one click!)
67
+ - Country allow/block lists
68
+ - VPN detection
69
+ - Threat blocking
331
70
 
332
- | Route | Method | Purpose |
333
- |-------|--------|---------|
334
- | `/api/magic-sessionmanager/logout` | `POST` | Alternative logout endpoint |
335
- | `/api/magic-sessionmanager/logout-all` | `POST` | Logout from all devices |
336
- | `/api/magic-sessionmanager/sessions` | `GET` | Get user's sessions |
337
- | `/api/magic-sessionmanager/user/:id/sessions` | `GET` | Get sessions for specific user |
71
+ ---
338
72
 
339
- ### JWT Token Handling
73
+ ## What This Plugin Does
340
74
 
341
- #### Access Tokens (JWT)
342
- - **Stored:** YES - in `session.token` field
343
- - **Used for:** Matching sessions during logout
344
- - **Expiration:** Controlled by Strapi's JWT config
345
- - **Validation:** Done by Strapi's auth system (not the plugin)
75
+ ### Simple Version
346
76
 
347
- **Important:** When a JWT expires, the session becomes orphaned but remains `isActive = true` until:
348
- 1. User explicitly logs out
349
- 2. Inactivity timeout triggers cleanup
350
- 3. Admin terminates the session
77
+ **When users login:**
78
+ - Plugin saves who logged in, when, and from where
79
+ - You can see them in the dashboard (see screenshot above)
80
+ - You can force-logout anyone anytime
351
81
 
352
- #### Refresh Tokens ✅ **SOLVED!**
82
+ **When users logout:**
83
+ - Plugin marks their session as "logged out"
84
+ - They disappear from the active sessions list
353
85
 
354
- **What are Refresh Tokens?**
355
- Refresh tokens allow users to get new Access Tokens (JWTs) without re-entering credentials. This enables longer sessions:
86
+ **While users are active:**
87
+ - Plugin updates their "last seen" time
88
+ - You always know who's currently using your app
356
89
 
357
- ```
358
- Access Token expires after 30 min
359
-
360
- User still has Refresh Token
361
-
362
- User requests new Access Token:
363
- POST /api/auth/refresh
364
-
365
- Strapi issues new JWT
366
-
367
- User continues without re-login
368
- ```
90
+ ---
369
91
 
370
- **The Solution (v3.2+):**
371
- - **Stored:** YES - Refresh tokens are encrypted and stored with sessions ✅
372
- - **Tracked:** YES - Middleware intercepts `/api/auth/refresh` requests ✅
373
- - **Validated:** YES - Checks if session is still active before issuing new tokens ✅
92
+ ## 🚀 Quick Install
374
93
 
375
- **How It Works:**
94
+ ### Step 1: Install
376
95
 
96
+ ```bash
97
+ npm install strapi-plugin-magic-sessionmanager
377
98
  ```
378
- Login: User gets JWT + Refresh Token
379
-
380
- Both tokens encrypted and stored in session
381
-
382
- Admin terminates session
383
-
384
- Session: isActive = false ❌
385
-
386
- User tries to refresh token:
387
- POST /api/auth/refresh
388
- { refreshToken: "..." }
389
-
390
- [Refresh Token Middleware]
391
-
392
- Decrypt all active session refresh tokens
393
-
394
- Find matching session
395
-
396
- Session found but isActive = false?
397
- → BLOCK! Return 401 Unauthorized ❌
398
- → Message: "Session terminated. Please login again."
399
-
400
- Session found and isActive = true?
401
- → ALLOW! ✅
402
- → Strapi issues new tokens
403
- → Session updated with new encrypted tokens
404
- ```
405
-
406
- **Security Benefits:**
407
-
408
- ✅ **Session termination is FINAL** - User cannot get new tokens
409
- ✅ **Refresh tokens tracked** - Encrypted & stored securely
410
- ✅ **Token rotation** - New tokens automatically updated in session
411
- ✅ **Admin control** - Force logout works even with refresh tokens
412
99
 
413
- **Configuration:**
100
+ ### Step 2: Enable Plugin
414
101
 
415
- Enable refresh tokens in Strapi:
102
+ Add this to `config/plugins.ts`:
416
103
 
417
104
  ```typescript
418
- // src/config/plugins.ts
419
105
  export default () => ({
420
- 'users-permissions': {
421
- config: {
422
- jwtManagement: 'refresh', // Enable refresh tokens
423
- sessions: {
424
- accessTokenLifespan: 3600, // 1 hour (in seconds)
425
- maxRefreshTokenLifespan: 2592000, // 30 days
426
- idleRefreshTokenLifespan: 604800, // 7 days idle
427
- },
428
- },
429
- },
430
106
  'magic-sessionmanager': {
431
107
  enabled: true,
432
- config: {
433
- inactivityTimeout: 15 * 60 * 1000, // 15 minutes
434
- },
435
108
  },
436
109
  });
437
110
  ```
438
111
 
439
- **Testing Refresh Token Blocking:**
112
+ ### Step 3: Rebuild & Start
440
113
 
441
114
  ```bash
442
- # 1. Login and get tokens
443
- curl -X POST http://localhost:1337/api/auth/local \
444
- -H "Content-Type: application/json" \
445
- -d '{"identifier":"user@example.com","password":"pass"}'
446
-
447
- # Save both tokens:
448
- ACCESS_TOKEN="eyJhbGci..."
449
- REFRESH_TOKEN="abc123..."
450
-
451
- # 2. Admin terminates session
452
- # Go to Admin → Sessions → Find session → Terminate
453
-
454
- # 3. Try to refresh token
455
- curl -X POST http://localhost:1337/api/auth/refresh \
456
- -H "Content-Type: application/json" \
457
- -d "{\"refreshToken\":\"$REFRESH_TOKEN\"}"
458
-
459
- # Expected: 401 Unauthorized
460
- # "Session terminated. Please login again."
115
+ npm run build
116
+ npm run develop
461
117
  ```
462
118
 
463
- **This completely solves the refresh token security gap!** 🔒
464
-
465
- ### Without Refresh Tokens (Default Behavior)
466
-
467
- If you **don't enable** refresh tokens (`jwtManagement: 'refresh'`):
119
+ ### Step 4: Open Dashboard
468
120
 
469
- ```
470
- Login: User gets JWT (no refresh token)
471
-
472
- JWT stored in session (encrypted)
473
-
474
- JWT expires after 30 min (or configured time)
475
-
476
- User must re-login ❌
477
-
478
- No automatic token refresh
479
- ```
121
+ 1. Go to Strapi Admin: `http://localhost:1337/admin`
122
+ 2. Look in the left sidebar for **"Sessions"**
123
+ 3. Click it!
124
+ 4. You'll see the dashboard (like the screenshot above)
480
125
 
481
- **Behavior:**
482
- - ✅ Session Manager works normally
483
- - ✅ Sessions tracked, logout works
484
- - ✅ Force logout works (no refresh token bypass possible)
485
- - ⚠️ Users must re-login when JWT expires
486
- - ℹ️ No refresh token middleware runs (skipped)
126
+ **That's it! You're done!** 🎉
487
127
 
488
- **Logs when refresh tokens disabled:**
489
- ```
490
- [magic-sessionmanager] ✅ Session created for user 1 (IP: 192.168.1.1)
491
- [magic-sessionmanager] ℹ️ No refresh token in response (JWT management not enabled)
492
- [magic-sessionmanager] ✅ Refresh Token interceptor middleware mounted
493
- ```
494
-
495
- **If you try to call `/api/auth/refresh` without enabling it:**
496
- - Endpoint returns **404 Not Found** (Strapi doesn't create the route)
497
- - Or returns **401 Unauthorized** if route exists but tokens not configured
498
- - This is expected and correct behavior
128
+ ---
499
129
 
500
- **Trade-offs:**
130
+ ## 🔐 Security Features (Optional)
501
131
 
502
- | Feature | With Refresh Tokens | Without Refresh Tokens |
503
- |---------|---------------------|------------------------|
504
- | User Experience | ✅ Seamless (auto-refresh) | ⚠️ Must re-login |
505
- | Security | ✅ Tracked & blockable | ✅ No bypass risk |
506
- | Session Duration | Long (days/weeks) | Short (hours) |
507
- | Force Logout | ✅ Complete | ✅ Complete |
132
+ ### Encryption Key (Recommended)
508
133
 
509
- **Recommendation:**
134
+ Your JWT tokens are encrypted before saving to database. Generate a key:
510
135
 
511
- **Enable refresh tokens** for better UX + use this plugin to secure them! 🔒
136
+ **In Admin Panel:**
137
+ 1. Go to **Sessions → Settings**
138
+ 2. Scroll to **"JWT Encryption Key Generator"**
139
+ 3. Click **"Generate Key"**
140
+ 4. Click **"Copy for .env"**
141
+ 5. Paste into your `.env` file
142
+ 6. Restart Strapi
512
143
 
513
- **Testing in Postman:**
144
+ **Or generate manually:**
145
+ ```bash
146
+ node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"
147
+ ```
514
148
 
149
+ Then add to `.env`:
515
150
  ```
516
- 1. Login (get JWT + refreshToken)
517
- POST /api/auth/local
518
- → Save: jwt, refreshToken, session_id
519
-
520
- 2. Refresh Token (should work)
521
- POST /api/auth/refresh
522
- Body: { "refreshToken": "..." }
523
- → Returns: New jwt + refreshToken ✅
524
-
525
- 3. Admin terminates session
526
- POST /magic-sessionmanager/sessions/:id/terminate
527
-
528
- 4. Try refresh token again
529
- POST /api/auth/refresh
530
- Body: { "refreshToken": "..." }
531
- → Returns: 401 Unauthorized ✅
532
- → Message: "Session terminated. Please login again."
151
+ SESSION_ENCRYPTION_KEY=your-key-here
533
152
  ```
534
153
 
535
- **Run Automated Test:**
536
-
537
- ```bash
538
- cd /path/to/magic-sessionmanager
154
+ **Why?** If someone hacks your database, they can't steal user sessions! 🔒
539
155
 
540
- # Set environment variables
541
- export TEST_USER_EMAIL=user@example.com
542
- export TEST_USER_PASSWORD=password123
543
- export ADMIN_EMAIL=admin@example.com
544
- export ADMIN_PASSWORD=adminpass
156
+ ---
545
157
 
546
- # Run test suite
547
- node test-session-manager.js
158
+ ## 🎯 Main Features Explained Simply
548
159
 
549
- # Look for "USER TEST 5: Blocked Refresh Token Test"
550
- # Should show: ✅ Refresh token BLOCKED as expected!
551
- ```
160
+ ### 1. See Who's Logged In
552
161
 
553
- ### Multi-Login Behavior
162
+ **Dashboard Tab:**
163
+ - Shows all active users
164
+ - Green badge = currently online
165
+ - Gray badge = logged out
166
+ - Click to see details
554
167
 
555
- **Strapi Default:** Allows multiple simultaneous logins
556
- **Magic Session Manager:** Tracks each login as separate session
168
+ ### 2. Force Logout Anyone
557
169
 
558
- ```
559
- User logs in from:
560
- - Desktop (Chrome) → Session 1
561
- - Mobile (Safari) Session 2
562
- - Laptop (Firefox) → Session 3
170
+ **Need to kick someone out?**
171
+ 1. Find their session
172
+ 2. Click **"Terminate"**
173
+ 3. Done! They're logged out immediately
563
174
 
564
- All sessions are active simultaneously.
565
- User can logout from one device without affecting others.
566
- ```
175
+ **Even works if they have refresh tokens!** (See below)
567
176
 
568
- ### Magic Link Integration
177
+ ### 3. Session Details
569
178
 
570
- If you use `strapi-plugin-magic-link`, the session manager automatically detects Magic Link logins:
179
+ **Click any session to see:**
180
+ - When they logged in
181
+ - Last time they did something
182
+ - What browser/device they use
183
+ - Their IP address
184
+ - Location (if Premium)
571
185
 
572
- ```javascript
573
- // bootstrap.js line 140
574
- const isMagicLink = ctx.path.includes('/magic-link/login') && ctx.method === 'POST';
575
- ```
186
+ ### 4. Multiple Devices
576
187
 
577
- Sessions are created the same way for Magic Link logins.
188
+ **Users can login from:**
189
+ - Desktop computer
190
+ - Phone
191
+ - Tablet
192
+ - All at the same time!
578
193
 
579
- ---
194
+ Each login = separate session. You can see them all and logout each individually.
580
195
 
581
- ## 🎛️ Admin Dashboard
582
-
583
- Access at **Admin → Sessions** (sidebar plugin)
584
-
585
- ### Tabs Overview
586
-
587
- #### 1. 📊 **Active Sessions**
588
- - Real-time list of currently logged-in users
589
- - Shows: User, IP, Device, Login Time, Last Seen
590
- - Actions: Terminate session, View details
591
- - Live status indicators
592
-
593
- **Features:**
594
- - Filter by user, device, location
595
- - Sort by login time, last activity
596
- - Bulk actions (terminate multiple)
597
- - Export to CSV
598
-
599
- #### 2. 📈 **Analytics**
600
- - Total sessions today/this week/this month
601
- - Concurrent users graph (real-time)
602
- - Geo-heatmap (Premium - shows login locations)
603
- - Device/browser breakdown
604
- - Peak usage times
605
- - Average session duration
606
-
607
- #### 3. ⚙️ **Settings**
608
-
609
- **Basic Settings:**
610
- - Rate limits (lastSeen update frequency)
611
- - Inactivity timeout
612
- - Cleanup schedule
613
-
614
- **Premium Settings:**
615
- - License key activation
616
- - Geolocation enabled
617
- - Security scoring enabled
618
- - Auto-blocking suspicious logins
619
- - VPN/Proxy alerts
620
-
621
- **Notification Settings:**
622
- - Email alerts configuration
623
- - Suspicious login alerts
624
- - Discord webhook URL
625
- - Slack webhook URL
626
-
627
- **Geo-Fencing:**
628
- - Country allow/block lists
629
- - IP whitelist/blacklist
196
+ ### 5. Auto-Cleanup
630
197
 
631
- #### 4. 🔑 **License**
632
- - Activate license key
633
- - View license status & expiry
634
- - Offline mode information
635
- - License holder details
636
- - Auto-ping status (15-minute intervals)
198
+ **Inactive sessions are automatically cleaned up:**
199
+ - If user doesn't do anything for 15 minutes (configurable)
200
+ - Session is marked as "inactive"
201
+ - Keeps your database clean
637
202
 
638
203
  ---
639
204
 
640
- ## 📡 API Routes
205
+ ## 🔒 Refresh Token Protection (Advanced)
641
206
 
642
- ### Content API Routes
207
+ ### The Problem (Without This Plugin)
643
208
 
644
- All require valid JWT authentication (Bearer token).
645
-
646
- #### Get User Sessions
647
-
648
- ```bash
649
- GET /api/magic-sessionmanager/sessions
650
- Authorization: Bearer YOUR_JWT
651
-
652
- Response:
653
- {
654
- "data": [
655
- {
656
- "id": 1,
657
- "attributes": {
658
- "loginTime": "2024-01-15T10:30:00Z",
659
- "lastActive": "2024-01-15T10:35:45Z",
660
- "logoutTime": null,
661
- "isActive": true,
662
- "ipAddress": "192.168.1.100",
663
- "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)...",
664
- "token": "eyJhbGciOiJIUzI1NiIs...", // JWT Access Token
665
- "geoLocation": { // Premium
666
- "country": "Germany",
667
- "city": "Berlin",
668
- "country_code": "DE",
669
- "latitude": 52.52,
670
- "longitude": 13.41
671
- },
672
- "securityScore": 95 // Premium
673
- },
674
- "relationships": {
675
- "user": { "id": 1, "username": "john" }
676
- }
677
- }
678
- ],
679
- "meta": { "count": 3 }
680
- }
681
209
  ```
682
-
683
- #### Logout (Method 1 - Strapi Native)
684
-
685
- ```bash
686
- POST /api/auth/logout
687
- Authorization: Bearer YOUR_JWT
688
-
689
- Response:
690
- {
691
- "message": "Logged out successfully"
692
- }
693
-
694
- # This is the REPLACED Strapi route
695
- # Terminates session matching the JWT token
210
+ Admin kicks out a user
211
+
212
+ User has "refresh token"
213
+
214
+ User gets new login token automatically
215
+
216
+ User is back in! 😱
696
217
  ```
697
218
 
698
- #### Logout (Method 2 - Plugin Endpoint)
699
-
700
- ```bash
701
- POST /api/magic-sessionmanager/logout
702
- Authorization: Bearer YOUR_JWT
703
-
704
- Response:
705
- {
706
- "message": "Session terminated successfully"
707
- }
219
+ ### The Solution (With This Plugin)
708
220
 
709
- # Alternative endpoint with same behavior
710
221
  ```
711
-
712
- #### Logout All Devices
713
-
714
- ```bash
715
- POST /api/magic-sessionmanager/logout-all
716
- Authorization: Bearer YOUR_JWT
717
-
718
- Response:
719
- {
720
- "message": "All sessions terminated",
721
- "count": 3
722
- }
723
-
724
- # Terminates ALL active sessions for the user
725
- # Useful for "logout everywhere" feature
222
+ Admin kicks out a user
223
+
224
+ User tries to use refresh token
225
+
226
+ Plugin blocks it! 🚫
227
+
228
+ User MUST login again
726
229
  ```
727
230
 
728
- ---
729
-
730
- ### Admin API Routes
731
-
732
- All require **admin authentication**.
733
-
734
- | Method | Route | Purpose |
735
- |--------|-------|---------|
736
- | `GET` | `/magic-sessionmanager/admin/sessions` | Get all sessions (all users) |
737
- | `GET` | `/magic-sessionmanager/admin/sessions/active` | Get only active sessions |
738
- | `GET` | `/magic-sessionmanager/admin/user/:userId/sessions` | Get sessions for a user |
739
- | `POST` | `/magic-sessionmanager/admin/sessions/:sessionId/terminate` | Mark session inactive |
740
- | `DELETE` | `/magic-sessionmanager/admin/sessions/:sessionId` | Permanently delete session |
741
- | `POST` | `/magic-sessionmanager/admin/sessions/clean-inactive` | Delete all inactive sessions |
742
- | `POST` | `/magic-sessionmanager/admin/user/:userId/terminate-all` | Logout user everywhere |
743
- | `GET` | `/magic-sessionmanager/admin/geolocation/:ipAddress` | Get IP info (Premium) |
744
- | `GET` | `/magic-sessionmanager/admin/settings` | Get plugin settings |
745
- | `PUT` | `/magic-sessionmanager/admin/settings` | Update plugin settings |
746
- | `GET` | `/magic-sessionmanager/admin/license/status` | Get license status |
747
- | `POST` | `/magic-sessionmanager/admin/license/activate` | Activate license |
748
-
749
- ---
750
-
751
- ## ⚙️ Configuration
231
+ **How to enable:**
752
232
 
753
- ### Basic Config
233
+ Add to `config/plugins.ts`:
754
234
 
755
235
  ```typescript
756
- // src/config/plugins.ts
757
- export default () => ({
758
- 'magic-sessionmanager': {
759
- enabled: true,
760
- config: {
761
- // Rate limit for lastSeen updates (milliseconds)
762
- // Prevents excessive DB writes
763
- lastSeenRateLimit: 30000, // 30 seconds (default)
764
-
765
- // Session inactivity timeout (milliseconds)
766
- // Sessions inactive longer than this are marked inactive
767
- inactivityTimeout: 15 * 60 * 1000, // 15 minutes (default)
768
-
769
- // IMPORTANT: Set this LOWER than your JWT expiration
770
- // to prevent orphaned sessions
771
- },
772
- },
773
- });
774
- ```
775
-
776
- ### Relationship with JWT Config
777
-
778
- ```typescript
779
- // src/config/plugins.ts
780
- export default () => ({
781
- // Strapi JWT Configuration
782
- 'users-permissions': {
783
- config: {
784
- jwt: {
785
- expiresIn: '30m', // Access Token expires after 30 minutes
786
- },
236
+ 'users-permissions': {
237
+ config: {
238
+ jwtManagement: 'refresh', // Enable refresh tokens
239
+ sessions: {
240
+ accessTokenLifespan: 3600, // 1 hour
241
+ maxRefreshTokenLifespan: 2592000, // 30 days
787
242
  },
788
243
  },
789
-
790
- // Session Manager Configuration
791
- 'magic-sessionmanager': {
792
- enabled: true,
793
- config: {
794
- // Set inactivity timeout LOWER than JWT expiration
795
- // This prevents orphaned sessions when JWT expires
796
- inactivityTimeout: 15 * 60 * 1000, // 15 minutes < 30 minutes JWT
797
-
798
- // Or match JWT expiration exactly:
799
- // inactivityTimeout: 30 * 60 * 1000, // 30 minutes = JWT expiration
800
- },
801
- },
802
- });
803
- ```
804
-
805
- ### Premium Config
806
-
807
- Available through Admin UI **Settings → Sessions → Settings**:
808
-
809
- ```typescript
810
- // Settings stored in database via Admin UI
811
- {
812
- // Geolocation & Security
813
- enableGeolocation: true,
814
- enableSecurityScoring: true,
815
- blockSuspiciousSessions: true,
816
- alertOnVpnProxy: true,
817
-
818
- // Geo-Fencing
819
- enableGeofencing: true,
820
- allowedCountries: ["DE", "AT", "CH"], // Germany, Austria, Switzerland
821
- blockedCountries: ["RU", "CN"], // Russia, China
822
-
823
- // Notifications
824
- enableEmailAlerts: true,
825
- alertOnSuspiciousLogin: true,
826
- enableWebhooks: true,
827
- discordWebhookUrl: "https://discord.com/api/webhooks/...",
828
- slackWebhookUrl: "https://hooks.slack.com/services/...",
829
244
  }
830
245
  ```
831
246
 
832
- ---
833
-
834
- ## 🔐 JWT Token Security
835
-
836
- ### Encryption
837
-
838
- All JWT tokens are **encrypted before storing** in the database using **AES-256-GCM** encryption.
839
-
840
- #### Why Encrypt Tokens?
841
-
842
- ```
843
- ❌ Without Encryption:
844
- Database compromised → Attacker sees JWTs → Can impersonate users!
845
-
846
- ✅ With Encryption:
847
- Database compromised → Attacker sees encrypted data → Useless without key!
848
- ```
849
-
850
- #### How It Works
851
-
852
- ```
853
- Login: User gets JWT
854
-
855
- JWT: "eyJhbGciOiJIUzI1NiIs..."
856
-
857
- [Encrypt with AES-256-GCM]
858
-
859
- Encrypted: "a3f7b2c1:8c4d9e2a:f2a5b8c3d4e5f6a7..."
860
-
861
- Stored in Database (secure!)
862
-
863
- Logout: User sends JWT
864
-
865
- [Fetch all active sessions from DB]
866
-
867
- [Decrypt each token]
868
-
869
- [Compare with user's JWT]
870
-
871
- Match found → Terminate session ✅
872
- ```
873
-
874
- #### Configuration
875
-
876
- **Generate Encryption Key (Admin Panel):**
877
-
878
- 1. Go to **Admin → Sessions → Settings**
879
- 2. Open **Security Settings** accordion
880
- 3. Find **JWT Encryption Key Generator**
881
- 4. Click **"Generate Key"**
882
- 5. Copy key with **"Copy for .env"** button
883
- 6. Add to your `.env` file
884
-
885
- **Or generate manually:**
886
-
887
- ```bash
888
- # Generate secure 32-byte key
889
- node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"
247
+ **What this does:**
248
+ - Users stay logged in longer (better experience)
249
+ - But admins can still force-logout completely (better security)
250
+ - Best of both worlds! ✅
890
251
 
891
- # Add to .env
892
- SESSION_ENCRYPTION_KEY=aBc123XyZ...your-32-char-key
893
- ```
252
+ ---
894
253
 
895
- **Fallback Behavior:**
254
+ ## 🌍 Premium Features (Optional License)
896
255
 
897
- If `SESSION_ENCRYPTION_KEY` is not set:
898
- - Plugin uses `APP_KEYS` or `API_TOKEN_SALT` as fallback
899
- - ⚠️ Warning logged on startup
900
- - Still encrypted, but key is derived from Strapi's keys
256
+ ### IP Geolocation
901
257
 
902
- **Production Recommendation:**
903
- Always use a dedicated `SESSION_ENCRYPTION_KEY` for better security isolation.
258
+ **See where users login from:**
259
+ - Country (with flag! 🇩🇪🇺🇸🇬🇧)
260
+ - City
261
+ - ISP Provider
262
+ - Coordinates (for map)
904
263
 
905
- #### Security Details
264
+ ### Threat Detection
906
265
 
907
- | Feature | Value |
908
- |---------|-------|
909
- | Algorithm | AES-256-GCM |
910
- | Key Size | 256 bits (32 bytes) |
911
- | IV Length | 128 bits (16 bytes) |
912
- | Auth Tag | 128 bits (16 bytes) |
913
- | Format | `iv:authTag:encryptedData` (hex) |
266
+ **Automatically check if IP is:**
267
+ - VPN
268
+ - Proxy
269
+ - Known threat
270
+ - Security score (0-100)
914
271
 
915
- ### Unique Session IDs
272
+ ### Auto-Blocking
916
273
 
917
- Each session gets a cryptographically unique identifier:
274
+ **Block logins from:**
275
+ - Specific countries
276
+ - VPNs or proxies
277
+ - Low security score IPs
278
+ - Known threat IPs
918
279
 
919
- ```javascript
920
- sessionId: "sess_lx3k7_4f2a8b3c_a1b2c3d4e5f6"
921
- // prefix^ ^timestamp ^user-hash ^random-bytes
922
- ```
280
+ ### Notifications
923
281
 
924
- **Benefits:**
925
- - No collisions across sessions
926
- - Traceable session identifiers
927
- - Independent from database IDs
928
- - URL-safe for future features
282
+ **Get alerts when:**
283
+ - Suspicious login detected
284
+ - VPN used
285
+ - New location login
286
+ - Send to Discord or Slack!
929
287
 
930
288
  ---
931
289
 
932
- ## 🔒 Premium Features
933
-
934
- ### IP Geolocation & Threat Detection
935
-
936
- Uses **ipapi.co** API for accurate IP information:
937
-
938
- ```json
939
- {
940
- "country": "Germany",
941
- "country_code": "DE",
942
- "city": "Berlin",
943
- "latitude": 52.52,
944
- "longitude": 13.41,
945
- "isp": "Deutsche Telekom",
946
- "isVpn": false,
947
- "isProxy": false,
948
- "isThreat": false,
949
- "securityScore": 95,
950
- "threatType": null
951
- }
952
- ```
953
-
954
- ### Auto-Blocking Rules
955
-
956
- ```
957
- Login attempt from IP: 1.2.3.4
958
-
959
- [Geolocation Check]
960
-
961
- isThreat = true → BLOCK ❌
962
- isVpn = true (if alertOnVpnProxy) → BLOCK ❌
963
- country = "RU" (if in blockedCountries) → BLOCK ❌
964
- country ≠ ["DE","AT","CH"] (if allowedCountries set) → BLOCK ❌
965
- securityScore < 50 → BLOCK ❌
966
-
967
- None of above? → ALLOW ✅
968
- ```
969
-
970
- ### Email Alerts
971
-
972
- ```
973
- Subject: ⚠️ Unusual Login Activity
974
-
975
- Hi John,
976
-
977
- A login from a new location was detected:
290
+ ## 📋 Simple API Guide
978
291
 
979
- 📍 Location: Berlin, Germany
980
- 🌐 IP Address: 192.168.1.100
981
- 🔒 Risk Level: Medium (VPN detected)
982
- ⏰ Time: 2024-01-15 10:30:00 UTC
983
- 💻 Device: Chrome on Windows
292
+ ### Get Sessions
984
293
 
985
- If this wasn't you, secure your account immediately.
986
-
987
- Magic Session Manager
294
+ ```bash
295
+ # Get all active sessions
296
+ GET /magic-sessionmanager/sessions
988
297
  ```
989
298
 
990
- ### Webhook Notifications
299
+ ### Logout
991
300
 
992
- **Discord:**
993
- ```
994
- 🔓 NEW LOGIN
995
- ━━━━━━━━━━━━━━━━━━
996
- User: john@example.com
997
- IP: 192.168.1.100
998
- Location: Berlin, Germany
999
- Risk: ⚠️ Medium (VPN)
1000
- Browser: Chrome / Windows
1001
- Time: 2024-01-15 10:30:00
301
+ ```bash
302
+ # Logout current user
303
+ POST /api/auth/logout
1002
304
  ```
1003
305
 
1004
- ---
1005
-
1006
- ## 💡 Use Cases
1007
-
1008
306
  ### Force Logout
1009
307
 
1010
308
  ```bash
1011
- # Admin terminates specific session
1012
- POST /api/magic-sessionmanager/admin/sessions/123/terminate
1013
-
1014
- # Admin logs out user from all devices
1015
- POST /api/magic-sessionmanager/admin/user/5/terminate-all
1016
-
1017
- # Next API request from that user:
1018
- GET /api/some-endpoint
1019
- Authorization: Bearer <their JWT>
1020
-
1021
- # Response: 401 Unauthorized
1022
- # "All sessions have been terminated. Please login again."
1023
- ```
1024
-
1025
- ### Security Monitoring
1026
-
1027
- ```
1028
- Premium feature: VPN Detection
1029
-
1030
- User logs in from VPN
1031
-
1032
- isVpn = true detected
1033
-
1034
- Email sent: "Suspicious login from VPN"
1035
-
1036
- Webhook notification to Slack
1037
-
1038
- Admin reviews in dashboard
1039
-
1040
- Admin can terminate session if needed
309
+ # Admin force-logout a session
310
+ POST /magic-sessionmanager/sessions/:sessionId/terminate
1041
311
  ```
1042
312
 
1043
- ### Compliance Audit
1044
-
1045
- ```
1046
- Export all sessions to CSV:
1047
- - Who logged in
1048
- - When & where (IP, location)
1049
- - Device & browser used
1050
- - Session duration
1051
- - Logout time (if any)
1052
-
1053
- Perfect for compliance requirements!
1054
- ```
313
+ **That's all you need to know!**
1055
314
 
1056
315
  ---
1057
316
 
1058
- ## 🧪 Testing
317
+ ## ⚙️ Settings You Can Change
1059
318
 
1060
- ### 1. Test Login & Session Creation
319
+ **In `config/plugins.ts`:**
1061
320
 
1062
- ```bash
1063
- # Login via Strapi's native route
1064
- curl -X POST http://localhost:1337/api/auth/local \
1065
- -H "Content-Type: application/json" \
1066
- -d '{
1067
- "identifier": "test@example.com",
1068
- "password": "Test@123"
1069
- }'
1070
-
1071
- # Response:
1072
- {
1073
- "jwt": "eyJhbGciOiJIUzI1NiIs...",
1074
- "user": { "id": 1, "email": "test@example.com", ... }
321
+ ```typescript
322
+ 'magic-sessionmanager': {
323
+ config: {
324
+ // How often to update "last seen" (in milliseconds)
325
+ lastSeenRateLimit: 30000, // Default: 30 seconds
326
+
327
+ // When to mark sessions inactive (in milliseconds)
328
+ inactivityTimeout: 900000, // Default: 15 minutes
329
+ },
1075
330
  }
1076
-
1077
- # Save JWT
1078
- export JWT="eyJhbGciOiJIUzI1NiIs..."
1079
-
1080
- # Check session was created
1081
- curl http://localhost:1337/api/magic-sessionmanager/sessions \
1082
- -H "Authorization: Bearer $JWT"
1083
-
1084
- # Should show new session with:
1085
- # - loginTime
1086
- # - isActive: true
1087
- # - ipAddress
1088
- # - userAgent
1089
- # - token (matches JWT)
1090
331
  ```
1091
332
 
1092
- ### 2. Test Activity Tracking
1093
-
1094
- ```bash
1095
- # First request (updates lastActive)
1096
- curl http://localhost:1337/api/users \
1097
- -H "Authorization: Bearer $JWT"
1098
-
1099
- # Check lastActive timestamp
1100
- curl http://localhost:1337/api/magic-sessionmanager/sessions \
1101
- -H "Authorization: Bearer $JWT"
333
+ **In Admin Panel (Settings Tab):**
334
+ - Email alerts on/off
335
+ - Webhook URLs (Discord/Slack)
336
+ - Countries to block/allow
337
+ - VPN detection on/off
338
+ - Generate encryption key
1102
339
 
1103
- # Wait 35 seconds (> 30s rate limit)
1104
- sleep 35
1105
-
1106
- # Second request (should update lastActive)
1107
- curl http://localhost:1337/api/users \
1108
- -H "Authorization: Bearer $JWT"
1109
-
1110
- # Check lastActive changed
1111
- curl http://localhost:1337/api/magic-sessionmanager/sessions \
1112
- -H "Authorization: Bearer $JWT"
1113
- ```
340
+ ---
1114
341
 
1115
- ### 3. Test Logout
342
+ ## 🐛 Common Problems & Fixes
1116
343
 
1117
- ```bash
1118
- # Logout via Strapi's route (replaced by plugin)
1119
- curl -X POST http://localhost:1337/api/auth/logout \
1120
- -H "Authorization: Bearer $JWT"
344
+ ### I don't see the Sessions menu
1121
345
 
1122
- # Response: { "message": "Logged out successfully" }
346
+ **Fix:**
347
+ 1. Make sure plugin is in `config/plugins.ts`
348
+ 2. Run `npm run build`
349
+ 3. Restart Strapi
350
+ 4. Refresh browser (Cmd+Shift+R)
1123
351
 
1124
- # Check session is inactive
1125
- curl http://localhost:1337/api/magic-sessionmanager/sessions \
1126
- -H "Authorization: Bearer $JWT"
352
+ ### Sessions not being created
1127
353
 
1128
- # Should show:
1129
- # - isActive: false
1130
- # - logoutTime: (timestamp)
1131
- ```
354
+ **Fix:**
355
+ 1. Check Strapi logs for errors
356
+ 2. Make sure users are logging in (not already logged in)
357
+ 3. Check database is working
1132
358
 
1133
- ### 4. Test Force Logout
359
+ ### 401 or 403 errors
1134
360
 
1135
- ```bash
1136
- # User A terminates all their sessions
1137
- curl -X POST http://localhost:1337/api/magic-sessionmanager/logout-all \
1138
- -H "Authorization: Bearer $JWT_A"
361
+ **Fix:**
362
+ - 401 = Not logged in (need to login as admin)
363
+ - 403 = Not allowed (check you're admin, not regular user)
1139
364
 
1140
- # Try to use API with old JWT
1141
- curl http://localhost:1337/api/users \
1142
- -H "Authorization: Bearer $JWT_A"
365
+ ### Database table "sessions" already exists
1143
366
 
1144
- # Response: 401 Unauthorized
1145
- # "All sessions have been terminated. Please login again."
1146
- ```
367
+ **Fix:**
368
+ - This plugin uses `magic_sessions` table (not `sessions`)
369
+ - If you see this error, another plugin is using that name
370
+ - Our plugin automatically uses the correct name
1147
371
 
1148
372
  ---
1149
373
 
1150
- ## 🐛 Troubleshooting
1151
-
1152
- ### Sessions Not Creating
1153
-
1154
- **Problem:** Login succeeds but no session record appears.
1155
-
1156
- **Solutions:**
1157
- 1. Check Strapi logs:
1158
- ```bash
1159
- npm run develop
1160
- # Look for: [magic-sessionmanager] 🔍 Login detected!
1161
- # Look for: [magic-sessionmanager] ✅ Session X created
1162
- ```
374
+ ## 💡 When To Use This Plugin
1163
375
 
1164
- 2. Verify middleware is mounted:
1165
- ```bash
1166
- # Look for: [magic-sessionmanager] Login/Logout interceptor middleware mounted
1167
- ```
376
+ **Perfect for:**
377
+ - Multi-tenant apps (see which tenant users are online)
378
+ - E-commerce (track customer sessions)
379
+ - Collaboration tools (show who's currently working)
380
+ - Security-critical apps (force-logout compromised accounts)
381
+ - Compliance requirements (session audit logs)
1168
382
 
1169
- 3. Check `plugin::magic-sessionmanager.session` collection exists:
1170
- - Go to Admin → Content Manager
1171
- - Look for "Session" collection
383
+ **Not needed if:**
384
+ - Single-user app
385
+ - No need to see who's logged in
386
+ - No security requirements
1172
387
 
1173
- ### JWT Still Works After Logout
1174
-
1175
- **Problem:** After logout, JWT still authenticates API requests.
1176
-
1177
- **Explanation:** This is EXPECTED behavior!
1178
- - JWT tokens are **stateless** - validated by signature alone
1179
- - Plugin marks session `isActive = false`
1180
- - But JWT itself remains valid until expiration
1181
- - Next authenticated request is **blocked** by LastSeen middleware
388
+ ---
1182
389
 
1183
- **Solution:** This is by design. The middleware blocks requests from users with no active sessions.
390
+ ## 🔧 How To Test It
1184
391
 
1185
- ### Orphaned Sessions
392
+ ### Quick Manual Test
1186
393
 
1187
- **Problem:** Sessions remain `isActive = true` after JWT expires.
394
+ 1. **Login to your Strapi app** (frontend or admin)
395
+ 2. **Go to Admin → Sessions**
396
+ 3. **You should see your session!**
397
+ 4. **Click "Terminate" on your session**
398
+ 5. **Try to use the app → You're logged out!**
1188
399
 
1189
- **Cause:** JWT expiration > inactivity timeout
400
+ ### With Postman
1190
401
 
1191
- **Solution:**
1192
- ```typescript
1193
- // Set inactivity timeout LOWER than JWT expiration
1194
- {
1195
- 'magic-sessionmanager': {
1196
- config: {
1197
- inactivityTimeout: 15 * 60 * 1000 // 15 min (if JWT = 30 min)
1198
- }
1199
- }
1200
- }
402
+ **1. Login:**
403
+ ```
404
+ POST http://localhost:1337/api/auth/local
405
+ Body: { "identifier": "user@test.com", "password": "pass123" }
1201
406
  ```
1202
407
 
1203
- ### LastSeen Not Updating
1204
-
1205
- **Problem:** `lastActive` timestamp doesn't change.
1206
-
1207
- **Solutions:**
1208
- 1. Check rate limit:
1209
- ```typescript
1210
- config: {
1211
- lastSeenRateLimit: 5000 // Lower for testing
1212
- }
1213
- ```
408
+ **2. Check session created:**
409
+ ```
410
+ GET http://localhost:1337/magic-sessionmanager/sessions
411
+ ```
1214
412
 
1215
- 2. Wait longer than rate limit (default 30s)
413
+ **3. Logout:**
414
+ ```
415
+ POST http://localhost:1337/api/auth/logout
416
+ Authorization: Bearer YOUR_JWT_TOKEN
417
+ ```
1216
418
 
1217
- 3. Verify middleware mounted:
1218
- ```bash
1219
- # Look for: [magic-sessionmanager] ✅ LastSeen middleware mounted
1220
- ```
419
+ **Done!**
1221
420
 
1222
421
  ---
1223
422
 
1224
- ## 🛠️ Development
423
+ ## 📦 What Gets Installed
1225
424
 
1226
- ### Plugin Structure
425
+ When you install this plugin, you get:
1227
426
 
1228
- ```
1229
- magic-sessionmanager/
1230
- ├── server/src/
1231
- │ ├── bootstrap.js # ⚙️ CORE: Mounts middlewares & intercepts routes
1232
- │ ├── middlewares/
1233
- │ │ └── last-seen.js # 🔄 Updates lastActive on each request
1234
- │ ├── services/
1235
- │ │ ├── session.js # 💾 Session CRUD operations
1236
- │ │ ├── geolocation.js # 🌍 IP geolocation (Premium)
1237
- │ │ ├── notifications.js # 📧 Email/webhook alerts
1238
- │ │ └── license-guard.js # 🔑 License validation
1239
- │ ├── controllers/
1240
- │ │ ├── session.js # 🎮 Session API handlers
1241
- │ │ ├── settings.js # ⚙️ Settings API
1242
- │ │ └── license.js # 🔑 License API
1243
- │ ├── routes/
1244
- │ │ ├── content-api.js # 🌐 User-facing routes
1245
- │ │ └── admin.js # 👑 Admin-only routes
1246
- │ └── utils/
1247
- │ └── getClientIp.js # 📍 IP extraction (proxy-aware)
1248
-
1249
- ├── admin/src/
1250
- │ ├── pages/
1251
- │ │ ├── HomePage.jsx # 📊 Main dashboard
1252
- │ │ ├── ActiveSessions.jsx # 👥 Active sessions tab
1253
- │ │ ├── Analytics.jsx # 📈 Analytics tab
1254
- │ │ ├── Settings.jsx # ⚙️ Settings tab
1255
- │ │ └── License.jsx # 🔑 License tab
1256
- │ └── components/
1257
- │ ├── SessionDetailModal.jsx
1258
- │ └── LicenseGuard.jsx
1259
-
1260
- ├── .github/workflows/
1261
- │ ├── semantic-release.yml # 🚀 NPM publishing
1262
- │ └── test.yml # ✅ CI/CD tests
1263
-
1264
- ├── package.json
1265
- ├── .releaserc.json # 📦 semantic-release config
1266
- └── README.md
1267
- ```
427
+ - ✅ Dashboard to see all sessions
428
+ - ✅ Session tracking (automatic)
429
+ - ✅ Force logout buttons
430
+ - Activity monitoring
431
+ - ✅ Encryption (secure)
432
+ - Multi-device support
1268
433
 
1269
- ### Build & Release
434
+ **Premium features require a license (free to generate):**
435
+ - 🔒 IP Geolocation
436
+ - 🔒 Threat detection
437
+ - 🔒 Auto-blocking
438
+ - 🔒 Email/webhook alerts
1270
439
 
1271
- ```bash
1272
- # Build
1273
- npm run build
440
+ ---
1274
441
 
1275
- # Release (automatic via semantic commits)
1276
- git commit -m "feat: add new feature" # → MINOR
1277
- git commit -m "fix: fix bug" # → PATCH
1278
- git commit -m "feat!: breaking change" # → MAJOR
1279
- ```
442
+ ## 🙋 FAQ
1280
443
 
1281
- ---
444
+ **Q: Do I need to change my Strapi code?**
445
+ A: No! Just install and enable the plugin.
1282
446
 
1283
- ## 📦 NPM Release Process
447
+ **Q: Will this break my existing logins?**
448
+ A: No! It just tracks them, doesn't change them.
1284
449
 
1285
- Uses **semantic-release** for automated versioning.
450
+ **Q: Can users see each other's sessions?**
451
+ A: No! Only admins can see all sessions. Users only see their own.
1286
452
 
1287
- ### Commit Format
453
+ **Q: What if I uninstall the plugin?**
454
+ A: Sessions will stop being tracked. Everything else works normally.
1288
455
 
1289
- ```bash
1290
- feat: add geo-fencing support # v1.1.0
1291
- fix: correct session cleanup # → v1.0.1
1292
- feat!: change API response format # → v2.0.0
1293
- ```
456
+ **Q: Does it slow down my app?**
457
+ A: No! It has smart rate-limiting to prevent database spam.
1294
458
 
1295
- GitHub Actions automatically publishes to NPM on push to `main`.
459
+ **Q: Can I customize the dashboard?**
460
+ A: Not yet, but it's planned for future versions!
1296
461
 
1297
462
  ---
1298
463
 
@@ -1300,16 +465,16 @@ GitHub Actions automatically publishes to NPM on push to `main`.
1300
465
 
1301
466
  - **NPM:** https://www.npmjs.com/package/strapi-plugin-magic-sessionmanager
1302
467
  - **GitHub:** https://github.com/Schero94/Magic-Sessionmanager
1303
- - **Issues:** https://github.com/Schero94/Magic-Sessionmanager/issues
468
+ - **Report Bugs:** https://github.com/Schero94/Magic-Sessionmanager/issues
1304
469
 
1305
470
  ---
1306
471
 
1307
472
  ## 📄 License
1308
473
 
1309
- **MIT License** - Free for personal & commercial use
474
+ **MIT License** - Free to use!
1310
475
 
1311
- **Copyright (c) 2025 Schero D.**
476
+ **Copyright © 2025 Schero D.**
1312
477
 
1313
478
  ---
1314
479
 
1315
- **Built with ❤️ for Strapi v5**
480
+ **Made with ❤️ for Strapi v5**