@vivinkv28/strapi-2fa-admin-plugin 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,227 @@
1
+ # @vivinkv28/strapi-2fa-admin-plugin
2
+
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
+
5
+ This package handles:
6
+
7
+ - admin credential check
8
+ - OTP challenge generation and hashing
9
+ - OTP resend and verification
10
+ - rate limiting for login, verify, and resend
11
+ - OTP delivery through Strapi's email plugin
12
+ - final Strapi admin session creation after OTP verification
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.
15
+
16
+ ## Documentation
17
+
18
+ - [Integration guide](./docs/INTEGRATION.md)
19
+ - [Architecture guide](./docs/ARCHITECTURE.md)
20
+
21
+ ## Endpoints
22
+
23
+ The plugin exposes these content API routes:
24
+
25
+ - `POST /api/admin-2fa/login`
26
+ - `POST /api/admin-2fa/verify`
27
+ - `POST /api/admin-2fa/resend`
28
+
29
+ See the full request and response flow in [docs/INTEGRATION.md](./docs/INTEGRATION.md).
30
+
31
+ ## Requirements
32
+
33
+ - Strapi 5
34
+ - Node.js `20.x` or `22.x`
35
+ - A configured Strapi email provider
36
+
37
+ ## Install In An Existing Strapi Project
38
+
39
+ ### Option 1: Use as a published npm package
40
+
41
+ Install the package in your Strapi app:
42
+
43
+ ```bash
44
+ npm install @vivinkv28/strapi-2fa-admin-plugin
45
+ ```
46
+
47
+ Then enable it in your Strapi app plugin config:
48
+
49
+ ```ts
50
+ // config/plugins.ts
51
+ import type { Core } from "@strapi/strapi";
52
+
53
+ const config = ({ env }: Core.Config.Shared.ConfigParams): Core.Config.Plugin => ({
54
+ "admin-2fa": {
55
+ enabled: true,
56
+ config: {
57
+ otpDigits: env.int("ADMIN_OTP_DIGITS", 6),
58
+ otpTtlSeconds: env.int("ADMIN_OTP_TTL_SECONDS", 300),
59
+ maxAttempts: env.int("ADMIN_OTP_MAX_ATTEMPTS", 5),
60
+ maxResends: env.int("ADMIN_OTP_MAX_RESENDS", 3),
61
+ rateLimitWindowSeconds: env.int("ADMIN_OTP_RATE_LIMIT_WINDOW_SECONDS", 900),
62
+ loginIpLimit: env.int("ADMIN_OTP_LOGIN_IP_LIMIT", 10),
63
+ loginEmailLimit: env.int("ADMIN_OTP_LOGIN_EMAIL_LIMIT", 5),
64
+ verifyIpLimit: env.int("ADMIN_OTP_VERIFY_IP_LIMIT", 20),
65
+ verifyEmailLimit: env.int("ADMIN_OTP_VERIFY_EMAIL_LIMIT", 10),
66
+ resendIpLimit: env.int("ADMIN_OTP_RESEND_IP_LIMIT", 10),
67
+ resendEmailLimit: env.int("ADMIN_OTP_RESEND_EMAIL_LIMIT", 5),
68
+ debugTimings: env.bool(
69
+ "ADMIN_OTP_DEBUG_TIMINGS",
70
+ env("NODE_ENV", "development") !== "production"
71
+ ),
72
+ },
73
+ },
74
+ });
75
+
76
+ export default config;
77
+ ```
78
+
79
+ ### Option 2: Use as a local external plugin
80
+
81
+ If the plugin lives next to your Strapi app, point Strapi to it with `resolve`:
82
+
83
+ ```ts
84
+ // config/plugins.ts
85
+ import type { Core } from "@strapi/strapi";
86
+
87
+ const config = ({ env }: Core.Config.Shared.ConfigParams): Core.Config.Plugin => ({
88
+ "admin-2fa": {
89
+ enabled: true,
90
+ resolve: "../strapi-2fa-admin-plugin",
91
+ config: {
92
+ otpDigits: env.int("ADMIN_OTP_DIGITS", 6),
93
+ otpTtlSeconds: env.int("ADMIN_OTP_TTL_SECONDS", 300),
94
+ maxAttempts: env.int("ADMIN_OTP_MAX_ATTEMPTS", 5),
95
+ maxResends: env.int("ADMIN_OTP_MAX_RESENDS", 3),
96
+ rateLimitWindowSeconds: env.int("ADMIN_OTP_RATE_LIMIT_WINDOW_SECONDS", 900),
97
+ loginIpLimit: env.int("ADMIN_OTP_LOGIN_IP_LIMIT", 10),
98
+ loginEmailLimit: env.int("ADMIN_OTP_LOGIN_EMAIL_LIMIT", 5),
99
+ verifyIpLimit: env.int("ADMIN_OTP_VERIFY_IP_LIMIT", 20),
100
+ verifyEmailLimit: env.int("ADMIN_OTP_VERIFY_EMAIL_LIMIT", 10),
101
+ resendIpLimit: env.int("ADMIN_OTP_RESEND_IP_LIMIT", 10),
102
+ resendEmailLimit: env.int("ADMIN_OTP_RESEND_EMAIL_LIMIT", 5),
103
+ debugTimings: env.bool(
104
+ "ADMIN_OTP_DEBUG_TIMINGS",
105
+ env("NODE_ENV", "development") !== "production"
106
+ ),
107
+ },
108
+ },
109
+ });
110
+
111
+ export default config;
112
+ ```
113
+
114
+ ## Required Host App Setup
115
+
116
+ ### 1. Configure an email provider
117
+
118
+ The plugin uses Strapi's `email` plugin to send OTP emails. Your host project must configure an email provider in `config/plugins.ts`.
119
+
120
+ ### 2. Add an admin login integration layer
121
+
122
+ This plugin is backend-only. To use it for real admin login 2FA, your project must:
123
+
124
+ - intercept the normal admin login flow
125
+ - call `POST /api/admin-2fa/login`
126
+ - show an OTP input step
127
+ - call `POST /api/admin-2fa/verify`
128
+ - optionally call `POST /api/admin-2fa/resend`
129
+
130
+ The expected frontend flow, payloads, and response handling are documented in [docs/INTEGRATION.md](./docs/INTEGRATION.md).
131
+
132
+ If you already maintain a patched Strapi admin login screen, point it to:
133
+
134
+ - `/api/admin-2fa/login`
135
+ - `/api/admin-2fa/verify`
136
+ - `/api/admin-2fa/resend`
137
+
138
+ ### 3. Ensure proxy / HTTPS settings are correct in production
139
+
140
+ If your Strapi app runs behind a proxy, make sure `config/server.ts` is configured correctly so secure admin cookies work.
141
+
142
+ Example:
143
+
144
+ ```ts
145
+ // config/server.ts
146
+ import type { Core } from "@strapi/strapi";
147
+
148
+ const config = ({ env }: Core.Config.Shared.ConfigParams): Core.Config.Server => ({
149
+ host: env("HOST", "0.0.0.0"),
150
+ port: env.int("PORT", 1337),
151
+ url: env("URL", "http://localhost:1337"),
152
+ proxy: env.bool("IS_PROXIED", env("NODE_ENV", "development") === "production"),
153
+ app: {
154
+ keys: env.array("APP_KEYS"),
155
+ },
156
+ });
157
+
158
+ export default config;
159
+ ```
160
+
161
+ ## Environment Variables
162
+
163
+ Suggested variables for the host Strapi project:
164
+
165
+ ```env
166
+ ADMIN_OTP_DIGITS=6
167
+ ADMIN_OTP_TTL_SECONDS=300
168
+ ADMIN_OTP_MAX_ATTEMPTS=5
169
+ ADMIN_OTP_MAX_RESENDS=3
170
+ ADMIN_OTP_RATE_LIMIT_WINDOW_SECONDS=900
171
+ ADMIN_OTP_LOGIN_IP_LIMIT=10
172
+ ADMIN_OTP_LOGIN_EMAIL_LIMIT=5
173
+ ADMIN_OTP_VERIFY_IP_LIMIT=20
174
+ ADMIN_OTP_VERIFY_EMAIL_LIMIT=10
175
+ ADMIN_OTP_RESEND_IP_LIMIT=10
176
+ ADMIN_OTP_RESEND_EMAIL_LIMIT=5
177
+ ADMIN_OTP_DEBUG_TIMINGS=false
178
+ ```
179
+
180
+ ## Plugin Development
181
+
182
+ Install dependencies:
183
+
184
+ ```bash
185
+ npm install
186
+ ```
187
+
188
+ Build the plugin:
189
+
190
+ ```bash
191
+ npm run build
192
+ ```
193
+
194
+ Watch during development:
195
+
196
+ ```bash
197
+ npm run watch
198
+ ```
199
+
200
+ Verify publishable output:
201
+
202
+ ```bash
203
+ npm run verify
204
+ ```
205
+
206
+ Link to a Strapi project with the SDK workflow:
207
+
208
+ ```bash
209
+ npm run watch:link
210
+ ```
211
+
212
+ ## Publishing Checklist
213
+
214
+ Before publishing:
215
+
216
+ 1. Run `npm install`
217
+ 2. Run `npm run build`
218
+ 3. Run `npm run verify`
219
+ 4. Confirm the host Strapi app works with the built package
220
+ 5. Update the package version
221
+ 6. Publish with `npm publish`
222
+
223
+ ## Production Notes
224
+
225
+ - Email OTP is a practical 2FA improvement, but it is weaker than TOTP or WebAuthn.
226
+ - If an attacker controls the admin email inbox, they can still complete the second factor.
227
+ - For stronger security, consider adding trusted devices, backup codes, TOTP, or passkeys in a future version.
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ function getDefaultExportFromCjs(x) {
3
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
4
+ }
5
+ var src = {
6
+ register() {
7
+ },
8
+ bootstrap() {
9
+ },
10
+ async registerTrads() {
11
+ return [];
12
+ }
13
+ };
14
+ const index = /* @__PURE__ */ getDefaultExportFromCjs(src);
15
+ module.exports = index;
@@ -0,0 +1,16 @@
1
+ function getDefaultExportFromCjs(x) {
2
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
3
+ }
4
+ var src = {
5
+ register() {
6
+ },
7
+ bootstrap() {
8
+ },
9
+ async registerTrads() {
10
+ return [];
11
+ }
12
+ };
13
+ const index = /* @__PURE__ */ getDefaultExportFromCjs(src);
14
+ export {
15
+ index as default
16
+ };