@vivinkv28/strapi-2fa-admin-plugin 0.1.1 → 0.1.2

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 +88 -190
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -2,84 +2,50 @@
2
2
 
3
3
  `@vivinkv28/strapi-2fa-admin-plugin` is a Strapi 5 plugin that provides the backend side of an OTP-based 2FA flow for Strapi admin authentication.
4
4
 
5
- This package handles:
5
+ ## What This Plugin Handles
6
6
 
7
- - admin credential check
7
+ - admin credential validation
8
8
  - OTP challenge generation and hashing
9
9
  - OTP resend and verification
10
10
  - rate limiting for login, verify, and resend
11
11
  - OTP delivery through Strapi's email plugin
12
12
  - final Strapi admin session creation after OTP verification
13
13
 
14
- This package does **not** replace the Strapi admin login UI by itself. You still need a frontend/admin integration layer that calls the plugin endpoints.
14
+ ## Important Scope
15
15
 
16
- ## Documentation
16
+ This package is a backend/admin-auth engine.
17
17
 
18
- - [Integration Guide](#integration-guide)
19
- - [Architecture Guide](#architecture-guide)
20
- - [Admin UI Integration](#admin-ui-integration)
18
+ It does **not** replace the Strapi admin login UI by itself. Your host project still needs an admin-side integration layer that:
19
+
20
+ 1. collects admin email and password
21
+ 2. calls the plugin login endpoint
22
+ 3. shows an OTP input UI
23
+ 4. calls the plugin verify endpoint
24
+ 5. optionally calls the resend endpoint
21
25
 
22
26
  ## Endpoints
23
27
 
24
- The plugin exposes these content API routes:
28
+ The plugin exposes these routes:
25
29
 
26
30
  - `POST /api/admin-2fa/login`
27
31
  - `POST /api/admin-2fa/verify`
28
32
  - `POST /api/admin-2fa/resend`
29
33
 
30
- See the detailed request and response flow in the `Integration Guide` section below.
31
-
32
34
  ## Requirements
33
35
 
34
36
  - Strapi 5
35
37
  - Node.js `20.x` or `22.x`
36
- - A configured Strapi email provider
37
-
38
- ## Install In An Existing Strapi Project
39
-
40
- ### Option 1: Use as a published npm package
38
+ - a configured Strapi email provider
41
39
 
42
- Install the package in your Strapi app:
40
+ ## Install
43
41
 
44
42
  ```bash
45
43
  npm install @vivinkv28/strapi-2fa-admin-plugin
46
44
  ```
47
45
 
48
- Then enable it in your Strapi app plugin config:
46
+ ## Enable In A Strapi Project
49
47
 
50
- ```ts
51
- // config/plugins.ts
52
- import type { Core } from "@strapi/strapi";
53
-
54
- const config = ({ env }: Core.Config.Shared.ConfigParams): Core.Config.Plugin => ({
55
- "admin-2fa": {
56
- enabled: true,
57
- config: {
58
- otpDigits: env.int("ADMIN_OTP_DIGITS", 6),
59
- otpTtlSeconds: env.int("ADMIN_OTP_TTL_SECONDS", 300),
60
- maxAttempts: env.int("ADMIN_OTP_MAX_ATTEMPTS", 5),
61
- maxResends: env.int("ADMIN_OTP_MAX_RESENDS", 3),
62
- rateLimitWindowSeconds: env.int("ADMIN_OTP_RATE_LIMIT_WINDOW_SECONDS", 900),
63
- loginIpLimit: env.int("ADMIN_OTP_LOGIN_IP_LIMIT", 10),
64
- loginEmailLimit: env.int("ADMIN_OTP_LOGIN_EMAIL_LIMIT", 5),
65
- verifyIpLimit: env.int("ADMIN_OTP_VERIFY_IP_LIMIT", 20),
66
- verifyEmailLimit: env.int("ADMIN_OTP_VERIFY_EMAIL_LIMIT", 10),
67
- resendIpLimit: env.int("ADMIN_OTP_RESEND_IP_LIMIT", 10),
68
- resendEmailLimit: env.int("ADMIN_OTP_RESEND_EMAIL_LIMIT", 5),
69
- debugTimings: env.bool(
70
- "ADMIN_OTP_DEBUG_TIMINGS",
71
- env("NODE_ENV", "development") !== "production"
72
- ),
73
- },
74
- },
75
- });
76
-
77
- export default config;
78
- ```
79
-
80
- ### Option 2: Use as a local external plugin
81
-
82
- If the plugin lives next to your Strapi app, point Strapi to it with `resolve`:
48
+ Add the plugin to your Strapi app config:
83
49
 
84
50
  ```ts
85
51
  // config/plugins.ts
@@ -88,7 +54,6 @@ import type { Core } from "@strapi/strapi";
88
54
  const config = ({ env }: Core.Config.Shared.ConfigParams): Core.Config.Plugin => ({
89
55
  "admin-2fa": {
90
56
  enabled: true,
91
- resolve: "../strapi-2fa-admin-plugin",
92
57
  config: {
93
58
  otpDigits: env.int("ADMIN_OTP_DIGITS", 6),
94
59
  otpTtlSeconds: env.int("ADMIN_OTP_TTL_SECONDS", 300),
@@ -112,36 +77,33 @@ const config = ({ env }: Core.Config.Shared.ConfigParams): Core.Config.Plugin =>
112
77
  export default config;
113
78
  ```
114
79
 
115
- ## Required Host App Setup
116
-
117
- ### 1. Configure an email provider
80
+ ## Admin UI Integration
118
81
 
119
- The plugin uses Strapi's `email` plugin to send OTP emails. Your host project must configure an email provider in `config/plugins.ts`.
82
+ Because this package does not inject the full login UI by itself, the host project must integrate the admin flow.
120
83
 
121
- ### 2. Add an admin login integration layer
84
+ ### Expected UI flow
122
85
 
123
- This plugin is backend-only. To use it for real admin login 2FA, your project must:
86
+ #### 1. Credentials step
124
87
 
125
- - intercept the normal admin login flow
126
- - call `POST /api/admin-2fa/login`
127
- - show an OTP input step
128
- - call `POST /api/admin-2fa/verify`
129
- - optionally call `POST /api/admin-2fa/resend`
88
+ - collect email and password
89
+ - send them to `POST /api/admin-2fa/login`
90
+ - if successful, store `challengeId` and switch to OTP mode
130
91
 
131
- The expected frontend flow, payloads, and response handling are documented in [docs/INTEGRATION.md](./docs/INTEGRATION.md).
132
- The expected frontend flow, payloads, and response handling are documented in the `Integration Guide` and `Admin UI Integration` sections below.
92
+ #### 2. OTP step
133
93
 
134
- ## Integration Guide
94
+ - collect the OTP code
95
+ - send it to `POST /api/admin-2fa/verify`
96
+ - if successful, continue the normal authenticated admin flow
97
+ - provide a resend action that calls `POST /api/admin-2fa/resend`
135
98
 
136
- This plugin is intended to be used as the backend engine for an admin OTP login flow.
99
+ ### Recommended UI behavior
137
100
 
138
- The normal integration flow is:
101
+ - keep login and OTP as separate form states
102
+ - do not treat password validation as a completed login
103
+ - complete the login only after `/verify` succeeds
104
+ - restart from the credentials step if the challenge expires
139
105
 
140
- 1. collect admin email and password
141
- 2. call `POST /api/admin-2fa/login`
142
- 3. display an OTP entry screen
143
- 4. call `POST /api/admin-2fa/verify`
144
- 5. optionally call `POST /api/admin-2fa/resend`
106
+ ## Integration Guide
145
107
 
146
108
  ### Login request
147
109
 
@@ -227,102 +189,21 @@ Example payload:
227
189
  - OTP session not found
228
190
  - invalid OTP code
229
191
  - too many authentication attempts
230
- - resend limit exceeded
231
-
232
- ## Admin UI Integration
233
-
234
- This package is backend-focused. To make it usable in a real Strapi admin login flow, the host project must provide an admin-side integration.
235
-
236
- A typical admin UI integration has two screens or states:
237
-
238
- ### 1. Credentials step
239
-
240
- - collect email and password
241
- - send them to `/api/admin-2fa/login`
242
- - if successful, store `challengeId` in memory and switch the UI into OTP mode
243
-
244
- ### 2. OTP step
245
-
246
- - collect the OTP code
247
- - submit it to `/api/admin-2fa/verify`
248
- - if successful, continue the normal authenticated admin flow
249
- - provide a resend button that calls `/api/admin-2fa/resend`
250
-
251
- ### Recommended UI behavior
252
-
253
- - keep login and OTP as separate form states
254
- - do not create a session after password validation alone
255
- - only treat the login as complete after `/verify` succeeds
256
- - if resend or verify says the challenge expired, restart from the credentials step
257
-
258
- ### Current integration approach used by the example project
259
-
260
- In the companion Strapi app used during development, the admin login UI is integrated by patching Strapi's admin login screen and auth service so they call:
192
+ - maximum resend attempts exceeded
261
193
 
262
- - `/api/admin-2fa/login`
263
- - `/api/admin-2fa/verify`
264
- - `/api/admin-2fa/resend`
194
+ ## Host Project Requirements
265
195
 
266
- This plugin itself does not inject that UI automatically. That choice is left to the host app because Strapi admin login customization is more app-specific than the backend OTP engine.
196
+ ### Email provider
267
197
 
268
- ## Architecture Guide
198
+ The plugin sends OTP emails through Strapi's email plugin, so the host project must configure an email provider.
269
199
 
270
- The plugin has a minimal admin entry and a backend-focused server implementation.
200
+ ### Proxy and HTTPS
271
201
 
272
- ### Main files
202
+ If the project runs behind a reverse proxy, configure `config/server.ts` correctly so secure admin cookies work.
273
203
 
274
- ```text
275
- admin/src/index.js
276
- server/src/index.js
277
- server/src/routes/index.js
278
- server/src/controllers/auth.js
279
- server/src/services/auth.js
280
- server/src/utils/strapi-session-auth.js
281
- ```
282
-
283
- ### Responsibilities
284
-
285
- - `admin/src/index.js`
286
- Minimal admin plugin stub required by the Strapi Plugin SDK.
287
-
288
- - `server/src/routes/index.js`
289
- Declares the plugin routes for login, verify, and resend.
290
-
291
- - `server/src/controllers/auth.js`
292
- Reads requests, extracts client IP, delegates to the service, and sets the admin refresh cookie after successful verification.
293
-
294
- - `server/src/services/auth.js`
295
- Core OTP logic: credential validation, challenge lifecycle, resend/verify rules, rate limiting, email sending, and final session creation.
296
-
297
- - `server/src/utils/strapi-session-auth.js`
298
- Runtime helper that resolves Strapi's internal admin session utility needed to create the final admin session.
299
-
300
- ### Security model
301
-
302
- - password-only login is not enough
303
- - raw OTP values are never stored
304
- - OTPs expire
305
- - verify/resend/login are rate-limited
306
- - the final Strapi admin session is created only after OTP verification
307
-
308
- ### Important limitation
309
-
310
- This is email OTP, not TOTP or WebAuthn. It improves admin security substantially, but it is still weaker than authenticator-app or passkey-based 2FA.
311
-
312
- If you already maintain a patched Strapi admin login screen, point it to:
313
-
314
- - `/api/admin-2fa/login`
315
- - `/api/admin-2fa/verify`
316
- - `/api/admin-2fa/resend`
317
-
318
- ### 3. Ensure proxy / HTTPS settings are correct in production
319
-
320
- If your Strapi app runs behind a proxy, make sure `config/server.ts` is configured correctly so secure admin cookies work.
321
-
322
- Example:
204
+ Typical example:
323
205
 
324
206
  ```ts
325
- // config/server.ts
326
207
  import type { Core } from "@strapi/strapi";
327
208
 
328
209
  const config = ({ env }: Core.Config.Shared.ConfigParams): Core.Config.Server => ({
@@ -340,7 +221,7 @@ export default config;
340
221
 
341
222
  ## Environment Variables
342
223
 
343
- Suggested variables for the host Strapi project:
224
+ Suggested defaults:
344
225
 
345
226
  ```env
346
227
  ADMIN_OTP_DIGITS=6
@@ -357,51 +238,68 @@ ADMIN_OTP_RESEND_EMAIL_LIMIT=5
357
238
  ADMIN_OTP_DEBUG_TIMINGS=false
358
239
  ```
359
240
 
360
- ## Plugin Development
241
+ ## Code-Level Architecture
361
242
 
362
- Install dependencies:
243
+ Main files:
363
244
 
364
- ```bash
365
- npm install
245
+ ```text
246
+ admin/src/index.js
247
+ server/src/index.js
248
+ server/src/routes/index.js
249
+ server/src/controllers/auth.js
250
+ server/src/services/auth.js
251
+ server/src/utils/strapi-session-auth.js
366
252
  ```
367
253
 
368
- Build the plugin:
254
+ Responsibilities:
369
255
 
370
- ```bash
371
- npm run build
372
- ```
256
+ - `admin/src/index.js`
257
+ Minimal admin plugin stub required by the Strapi Plugin SDK.
373
258
 
374
- Watch during development:
259
+ - `server/src/routes/index.js`
260
+ Declares the login, verify, and resend routes.
375
261
 
376
- ```bash
377
- npm run watch
378
- ```
262
+ - `server/src/controllers/auth.js`
263
+ Reads the request, extracts client IP, delegates to the service, and sets the admin refresh cookie after successful OTP verification.
264
+
265
+ - `server/src/services/auth.js`
266
+ Core OTP logic: credential validation, challenge lifecycle, resend/verify rules, rate limiting, email sending, and final session creation.
379
267
 
380
- Verify publishable output:
268
+ - `server/src/utils/strapi-session-auth.js`
269
+ Runtime helper that resolves Strapi's internal admin session utility for final session creation.
381
270
 
382
- ```bash
383
- npm run verify
384
- ```
271
+ ## Repo Docs
385
272
 
386
- Link to a Strapi project with the SDK workflow:
273
+ If you are reading the source repository directly, deeper docs are also available in:
274
+
275
+ - `docs/INTEGRATION.md`
276
+ - `docs/ARCHITECTURE.md`
277
+
278
+ ## Development
387
279
 
388
280
  ```bash
389
- npm run watch:link
281
+ npm install
282
+ npm run build
390
283
  ```
391
284
 
392
- ## Publishing Checklist
285
+ Useful commands:
286
+
287
+ - `npm run build`
288
+ - `npm run watch`
289
+ - `npm run watch:link`
290
+ - `npm run verify`
393
291
 
394
- Before publishing:
292
+ ## Publishing Checklist
395
293
 
396
- 1. Run `npm install`
397
- 2. Run `npm run build`
398
- 3. Run `npm run verify`
399
- 4. Confirm the host Strapi app works with the built package
400
- 5. Update the package version
401
- 6. Publish with `npm publish`
294
+ 1. run `npm install`
295
+ 2. run `npm run build`
296
+ 3. run `npm run verify`
297
+ 4. verify the plugin in a real Strapi app
298
+ 5. bump the version
299
+ 6. publish with `npm publish --access public`
402
300
 
403
301
  ## Production Notes
404
302
 
405
- - Email OTP is a practical 2FA improvement, but it is weaker than TOTP or WebAuthn.
406
- - If an attacker controls the admin email inbox, they can still complete the second factor.
407
- - For stronger security, consider adding trusted devices, backup codes, TOTP, or passkeys in a future version.
303
+ - Email OTP is better than password-only login, but weaker than TOTP or WebAuthn.
304
+ - If the admin mailbox is compromised, the second factor can still be bypassed.
305
+ - For stronger security later, consider TOTP, backup codes, trusted devices, or passkeys.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vivinkv28/strapi-2fa-admin-plugin",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Reusable Strapi admin 2FA plugin",
5
5
  "type": "commonjs",
6
6
  "keywords": [