@payez/next-mvp 4.8.0 โ†’ 4.8.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 (301) hide show
  1. package/POST-INSTALL.md +408 -408
  2. package/README.md +859 -859
  3. package/dist/components/account/MobileNavDrawer.js +18 -18
  4. package/dist/components/account/UserAvatarMenu.js +1 -1
  5. package/dist/components/admin/AlertSettingsTab.js +40 -40
  6. package/dist/components/admin/LoggingSettingsTab.js +28 -28
  7. package/dist/lib/session-store.js +21 -21
  8. package/dist/lib/startup-init.js +19 -19
  9. package/dist/middleware/create-middleware.js +6 -5
  10. package/dist/pages/login/page.js +28 -28
  11. package/dist/pages/settings/EnhancedSettingsPage.js +17 -17
  12. package/dist/vibe/sessions.js +28 -3
  13. package/package.json +2 -2
  14. package/scripts/check-publish-eol.mjs +33 -15
  15. package/src/api/auth-handler.ts +550 -550
  16. package/src/api/index.ts +17 -17
  17. package/src/api-handlers/account/change-password.ts +170 -170
  18. package/src/api-handlers/account/masked-info.ts +46 -46
  19. package/src/api-handlers/account/profile.ts +99 -99
  20. package/src/api-handlers/account/recovery/forward.ts +117 -117
  21. package/src/api-handlers/account/recovery/initiate.ts +59 -59
  22. package/src/api-handlers/account/recovery/send-code.ts +21 -21
  23. package/src/api-handlers/account/recovery/verify-code.ts +20 -20
  24. package/src/api-handlers/account/reset-password.ts +87 -87
  25. package/src/api-handlers/account/send-code.ts +70 -70
  26. package/src/api-handlers/account/update-phone.ts +84 -84
  27. package/src/api-handlers/account/validate-password.ts +139 -139
  28. package/src/api-handlers/account/verify-email.ts +134 -134
  29. package/src/api-handlers/account/verify-sms.ts +134 -134
  30. package/src/api-handlers/admin/analytics.ts +452 -452
  31. package/src/api-handlers/admin/audit.ts +232 -232
  32. package/src/api-handlers/admin/index.ts +63 -63
  33. package/src/api-handlers/admin/redis-sessions.ts +259 -259
  34. package/src/api-handlers/admin/sessions.ts +327 -327
  35. package/src/api-handlers/admin/site-logs.ts +388 -388
  36. package/src/api-handlers/admin/stats.ts +260 -260
  37. package/src/api-handlers/admin/users.ts +251 -251
  38. package/src/api-handlers/admin/vibe-data.ts +333 -333
  39. package/src/api-handlers/anon/preferences.ts +123 -123
  40. package/src/api-handlers/auth/credential-login-email-code.ts +92 -92
  41. package/src/api-handlers/auth/credential-login.ts +948 -948
  42. package/src/api-handlers/auth/jwks.ts +31 -31
  43. package/src/api-handlers/auth/login.ts +252 -252
  44. package/src/api-handlers/auth/passkey-signin.ts +116 -116
  45. package/src/api-handlers/auth/refresh.ts +829 -829
  46. package/src/api-handlers/auth/signout.ts +201 -201
  47. package/src/api-handlers/auth/status.ts +23 -23
  48. package/src/api-handlers/auth/update-session.ts +144 -144
  49. package/src/api-handlers/auth/validate.ts +45 -45
  50. package/src/api-handlers/auth/verify-code.ts +116 -116
  51. package/src/api-handlers/mfa/backup-code-verify.ts +170 -170
  52. package/src/api-handlers/mfa/backup-codes.ts +42 -42
  53. package/src/api-handlers/mfa/methods.ts +47 -47
  54. package/src/api-handlers/mfa/totp-confirm.ts +43 -43
  55. package/src/api-handlers/mfa/totp-enroll.ts +43 -43
  56. package/src/api-handlers/mfa/totp-verify.ts +172 -172
  57. package/src/api-handlers/oauth/resume.ts +182 -182
  58. package/src/api-handlers/onboarding/send-email-code.ts +18 -18
  59. package/src/api-handlers/onboarding/set-password.ts +21 -21
  60. package/src/api-handlers/onboarding/verify-code.ts +20 -20
  61. package/src/api-handlers/onboarding/verify-welcome-email.ts +17 -17
  62. package/src/api-handlers/passkeys/list.ts +32 -32
  63. package/src/api-handlers/passkeys/manage.ts +55 -55
  64. package/src/api-handlers/passkeys/register-options.ts +43 -43
  65. package/src/api-handlers/passkeys/register-verify.ts +42 -42
  66. package/src/api-handlers/session/refresh-viability.ts +56 -56
  67. package/src/api-handlers/session/viability.ts +238 -238
  68. package/src/api-handlers/test/force-expire.ts +167 -167
  69. package/src/auth/auth-decision.ts +292 -292
  70. package/src/auth/better-auth.ts +1688 -1688
  71. package/src/auth/idp-oauth.ts +310 -310
  72. package/src/auth/password-reset-bridge.ts +98 -98
  73. package/src/auth/route-config.ts +236 -236
  74. package/src/auth/safe-callback.ts +199 -199
  75. package/src/auth/session-cookie-clear.ts +30 -30
  76. package/src/auth/session-reset-link.ts +159 -159
  77. package/src/auth/session-response-sanitizer.ts +151 -151
  78. package/src/auth/types/auth-types.ts +555 -555
  79. package/src/auth/types/index.ts +7 -7
  80. package/src/auth/unauthenticated-routes.ts +2 -2
  81. package/src/auth/utils/idp-client.ts +364 -364
  82. package/src/auth/utils/index.ts +6 -6
  83. package/src/auth/utils/token-utils.ts +243 -243
  84. package/src/client/AuthContext.tsx +192 -192
  85. package/src/client/better-auth-client.ts +70 -70
  86. package/src/client/fetch-with-auth.ts +47 -47
  87. package/src/client/fetchWithSession.ts +21 -21
  88. package/src/client/index.ts +13 -13
  89. package/src/client/useAnonSession.ts +131 -131
  90. package/src/components/SessionSync.tsx +138 -138
  91. package/src/components/SignalRHealthCheck.tsx +131 -131
  92. package/src/components/account/MobileNavDrawer.tsx +305 -305
  93. package/src/components/account/UserAvatarMenu.tsx +277 -277
  94. package/src/components/account/index.ts +13 -13
  95. package/src/components/admin/AlertSettingsTab.tsx +728 -728
  96. package/src/components/admin/AnalyticsTab.tsx +703 -703
  97. package/src/components/admin/DataBrowserTab.tsx +508 -508
  98. package/src/components/admin/LoggingSettingsTab.tsx +665 -665
  99. package/src/components/admin/SessionsTab.tsx +421 -421
  100. package/src/components/admin/StatsTab.tsx +379 -379
  101. package/src/components/admin/VibeAdminContext.tsx +87 -87
  102. package/src/components/admin/VibeAdminLayout.tsx +187 -187
  103. package/src/components/admin/index.ts +59 -59
  104. package/src/components/auth/CredentialSignInForm.tsx +240 -240
  105. package/src/components/auth/FederatedAuthSection.tsx +129 -129
  106. package/src/components/auth/ModeAwareLoginPage.tsx +146 -146
  107. package/src/components/auth/ModeAwareSignupPage.tsx +200 -200
  108. package/src/components/auth/PasswordResetBridge.tsx +30 -30
  109. package/src/components/auth/TraditionalAuthSection.tsx +103 -103
  110. package/src/components/recovery/CompleteStep.tsx +36 -36
  111. package/src/components/recovery/InitiateRecoveryStep.tsx +68 -68
  112. package/src/components/recovery/RequestedStep.tsx +30 -30
  113. package/src/components/recovery/SelectMethodStep.tsx +73 -73
  114. package/src/components/recovery/SetPasswordStep.tsx +118 -118
  115. package/src/components/recovery/VerifyCodeStep.tsx +90 -90
  116. package/src/components/reserved/ReservedRecoveryWarning.tsx +160 -160
  117. package/src/components/reserved/ReservedStatusBox.tsx +118 -118
  118. package/src/components/ui/BetaBadge.tsx +58 -58
  119. package/src/components/ui/Footer.tsx +93 -93
  120. package/src/config/env.ts +55 -55
  121. package/src/config/logger.ts +62 -62
  122. package/src/config/logging-config.ts +82 -82
  123. package/src/config/unauthenticated-routes.ts +19 -19
  124. package/src/config/vibe-log-transport.ts +264 -264
  125. package/src/edge/internal-api-url.ts +65 -65
  126. package/src/edge/middleware.ts +42 -42
  127. package/src/hooks/useAuth.ts +117 -117
  128. package/src/hooks/useAuthSettings.ts +109 -109
  129. package/src/hooks/useAvailableProviders.ts +143 -143
  130. package/src/hooks/usePasswordValidation.ts +127 -127
  131. package/src/hooks/useProfile.ts +82 -82
  132. package/src/hooks/usePublicAuthSettings.ts +171 -171
  133. package/src/hooks/useSessionExpiration.ts +101 -101
  134. package/src/hooks/useViabilitySession.ts +337 -337
  135. package/src/index.ts +64 -64
  136. package/src/lib/anon-session.ts +213 -213
  137. package/src/lib/api-handler.ts +643 -643
  138. package/src/lib/app-slug.ts +228 -228
  139. package/src/lib/authorize-resume.ts +172 -172
  140. package/src/lib/bearer-fetch.ts +31 -31
  141. package/src/lib/client-key.ts +88 -88
  142. package/src/lib/code-step-copy.ts +83 -83
  143. package/src/lib/credential-sign-in-client.ts +101 -101
  144. package/src/lib/demo-mode.ts +18 -18
  145. package/src/lib/device-id.ts +67 -67
  146. package/src/lib/ensure-fresh-access-token.ts +509 -509
  147. package/src/lib/geolocation.ts +265 -265
  148. package/src/lib/idp-client-config.ts +1005 -1005
  149. package/src/lib/idp-fetch.ts +169 -169
  150. package/src/lib/idp-url-guard.ts +37 -37
  151. package/src/lib/internal-api.ts +171 -171
  152. package/src/lib/jwt-decode-client.ts +45 -45
  153. package/src/lib/jwt-decode.ts +82 -82
  154. package/src/lib/lock-window.ts +49 -49
  155. package/src/lib/login-error-message.ts +41 -41
  156. package/src/lib/never-in-response.ts +64 -64
  157. package/src/lib/nextauth-secret.ts +168 -168
  158. package/src/lib/onboarding-proxy.ts +57 -57
  159. package/src/lib/password-rules.ts +50 -50
  160. package/src/lib/rate-limit-service.ts +9 -9
  161. package/src/lib/redis.ts +105 -105
  162. package/src/lib/refresh-token-validator.ts +64 -64
  163. package/src/lib/roles.ts +177 -177
  164. package/src/lib/safe-error-response.ts +149 -149
  165. package/src/lib/secret-validation.ts +8 -8
  166. package/src/lib/session-cookie-shape.ts +185 -185
  167. package/src/lib/session-store.ts +1092 -1092
  168. package/src/lib/session.ts +34 -34
  169. package/src/lib/single-flight.ts +64 -64
  170. package/src/lib/site-logger.ts +245 -245
  171. package/src/lib/standardized-client-api.ts +901 -901
  172. package/src/lib/startup-init.ts +276 -276
  173. package/src/lib/test-aware-get-token.ts +41 -41
  174. package/src/lib/token-expiry.ts +40 -40
  175. package/src/lib/token-lifecycle.ts +546 -546
  176. package/src/lib/token-log-id.ts +69 -69
  177. package/src/lib/twofa-rejection.ts +91 -91
  178. package/src/lib/types/api-responses.ts +336 -336
  179. package/src/lib/user-agent-parser.ts +252 -252
  180. package/src/logging/api/admin-analytics.ts +51 -51
  181. package/src/logging/api/audit-log.ts +53 -53
  182. package/src/logging/components/AdminAnalyticsLayout.tsx +49 -49
  183. package/src/logging/components/AuditLogViewer.tsx +125 -125
  184. package/src/logging/components/ErrorMetricsCard.tsx +98 -98
  185. package/src/logging/components/HealthMetricsCard.tsx +70 -70
  186. package/src/logging/hooks/useAdminAnalytics.ts +22 -22
  187. package/src/logging/hooks/useAuditLog.ts +24 -24
  188. package/src/logging/hooks/useErrorMetrics.ts +40 -40
  189. package/src/logging/hooks/useHealthMetrics.ts +44 -44
  190. package/src/logging/index.ts +18 -18
  191. package/src/logging/types/analytics.ts +81 -81
  192. package/src/logging/types/audit.ts +31 -31
  193. package/src/logging/types/index.ts +3 -3
  194. package/src/middleware/create-middleware.ts +1139 -1138
  195. package/src/middleware/rbac-check.ts +279 -279
  196. package/src/middleware/twofa-presets.ts +224 -224
  197. package/src/models/DecodedAccessToken.ts +16 -16
  198. package/src/models/SessionModel.ts +331 -331
  199. package/src/pages/admin-login/page.tsx +111 -111
  200. package/src/pages/admin-page-permissions/PagePermissionsAdminPage.tsx +527 -527
  201. package/src/pages/admin-page-permissions/index.ts +7 -7
  202. package/src/pages/admin-roles/RolesAdminPage.tsx +533 -533
  203. package/src/pages/admin-roles/index.ts +9 -9
  204. package/src/pages/admin-roles/modals.tsx +469 -469
  205. package/src/pages/client-admin/ClientSiteAdminPage.tsx +382 -382
  206. package/src/pages/client-admin/index.ts +33 -33
  207. package/src/pages/coming-soon/page.tsx +83 -83
  208. package/src/pages/login/page.tsx +338 -338
  209. package/src/pages/onboarding/index.ts +11 -11
  210. package/src/pages/onboarding/page.tsx +212 -212
  211. package/src/pages/profile/EnhancedProfilePage.tsx +514 -514
  212. package/src/pages/profile/index.ts +9 -9
  213. package/src/pages/profile/page.tsx +166 -166
  214. package/src/pages/recovery/page.tsx +267 -267
  215. package/src/pages/roles/MyRolesPage.tsx +211 -211
  216. package/src/pages/roles/components.tsx +294 -294
  217. package/src/pages/roles/index.ts +17 -17
  218. package/src/pages/security/EnhancedSecurityPage.tsx +660 -660
  219. package/src/pages/security/index.ts +12 -12
  220. package/src/pages/security/page.tsx +507 -507
  221. package/src/pages/settings/EnhancedSettingsPage.tsx +642 -642
  222. package/src/pages/settings/index.ts +9 -9
  223. package/src/pages/settings/page.tsx +47 -47
  224. package/src/pages/showcase/ShowcasePage.tsx +532 -532
  225. package/src/pages/showcase/index.ts +13 -13
  226. package/src/pages/test-env/EmergencyLogoutPage.tsx +192 -192
  227. package/src/pages/test-env/JwtInspectPage.tsx +449 -449
  228. package/src/pages/test-env/RefreshTokenPage.tsx +178 -178
  229. package/src/pages/test-env/TestEnvPage.tsx +130 -130
  230. package/src/pages/test-env/guarded.tsx +81 -81
  231. package/src/pages/test-env/index.ts +77 -77
  232. package/src/pages/test-env/redact-credentials.ts +96 -96
  233. package/src/pages/verify-code/page.tsx +746 -746
  234. package/src/routes/account/index.ts +31 -31
  235. package/src/routes/account/masked-info.ts +36 -36
  236. package/src/routes/account/send-code.ts +39 -39
  237. package/src/routes/account/update-phone.ts +13 -13
  238. package/src/routes/account/verify-email.ts +40 -40
  239. package/src/routes/account/verify-sms.ts +40 -40
  240. package/src/routes/auth/credential-login-email-code.ts +6 -6
  241. package/src/routes/auth/credential-login.ts +6 -6
  242. package/src/routes/auth/index.ts +22 -22
  243. package/src/routes/auth/logout.ts +111 -111
  244. package/src/routes/auth/nextauth.ts +45 -45
  245. package/src/routes/auth/passkey-signin.ts +13 -13
  246. package/src/routes/auth/refresh.ts +77 -77
  247. package/src/routes/auth/session-reset.ts +37 -37
  248. package/src/routes/auth/session.ts +261 -261
  249. package/src/routes/auth/settings.ts +181 -181
  250. package/src/routes/auth/viability.ts +519 -519
  251. package/src/routes/index.ts +17 -17
  252. package/src/routes/mfa/backup-code-verify.ts +1 -1
  253. package/src/routes/mfa/backup-codes.ts +10 -10
  254. package/src/routes/mfa/methods.ts +22 -22
  255. package/src/routes/mfa/totp-confirm.ts +10 -10
  256. package/src/routes/mfa/totp-enroll.ts +10 -10
  257. package/src/routes/mfa/totp-verify.ts +14 -14
  258. package/src/routes/onboarding/index.ts +15 -15
  259. package/src/routes/onboarding/send-email-code.ts +2 -2
  260. package/src/routes/onboarding/set-password.ts +2 -2
  261. package/src/routes/onboarding/verify-code.ts +2 -2
  262. package/src/routes/onboarding/verify-welcome-email.ts +2 -2
  263. package/src/routes/passkeys/list.ts +10 -10
  264. package/src/routes/passkeys/manage.ts +23 -23
  265. package/src/routes/passkeys/register-options.ts +10 -10
  266. package/src/routes/passkeys/register-verify.ts +10 -10
  267. package/src/routes/session/index.ts +7 -7
  268. package/src/routes/session/refresh-viability.ts +17 -17
  269. package/src/server/auth-guard.ts +203 -203
  270. package/src/server/auth.ts +486 -486
  271. package/src/server/decode-session.ts +309 -309
  272. package/src/server/slim-middleware.ts +117 -117
  273. package/src/server/verified-session-token.ts +103 -103
  274. package/src/server/with-auth.ts +93 -93
  275. package/src/services/signalrActivityService.ts +258 -258
  276. package/src/stores/authStore.ts +1900 -1900
  277. package/src/templates/instrumentation.ts +60 -60
  278. package/src/theme/ThemeProvider.tsx +39 -39
  279. package/src/theme/default.ts +33 -33
  280. package/src/theme/index.ts +31 -31
  281. package/src/theme/types.ts +69 -69
  282. package/src/theme/useTheme.ts +57 -57
  283. package/src/theme/utils.ts +40 -40
  284. package/src/types/api.ts +12 -12
  285. package/src/types/auth.d.ts +23 -23
  286. package/src/types/auth.ts +48 -48
  287. package/src/types/logging.ts +11 -11
  288. package/src/types/recovery.ts +54 -54
  289. package/src/utils/api.ts +401 -401
  290. package/src/utils/circuitBreaker.ts +40 -40
  291. package/src/utils/error-message.ts +108 -108
  292. package/src/utils/layout/reservedSpace.ts +124 -124
  293. package/src/utils/logout.ts +30 -30
  294. package/src/vibe/client.ts +877 -877
  295. package/src/vibe/enterprise-auth.ts +208 -208
  296. package/src/vibe/errors.ts +209 -209
  297. package/src/vibe/generic.ts +339 -339
  298. package/src/vibe/hooks/index.ts +367 -367
  299. package/src/vibe/index.ts +133 -133
  300. package/src/vibe/sessions.ts +925 -899
  301. package/src/vibe/types.ts +577 -577
package/README.md CHANGED
@@ -1,859 +1,859 @@
1
- # @payez/next-mvp
2
-
3
- Drop-in authentication for Next.js. One package, zero secret management in production.
4
-
5
- ```bash
6
- npm install @payez/next-mvp next-auth
7
- ```
8
-
9
- > **Installing is not finishing.** There is no `postinstall` step and no generator, so the
10
- > package cannot mount its own routes or pages into your `app/` directory, and it does not
11
- > emit the CSS variables its components read. **[POST-INSTALL.md](./POST-INSTALL.md) is the
12
- > complete list of what you must still do by hand** โ€” including three that leave the site
13
- > broken with nothing to tell you why: the auth routes, the login page, and the sixteen theme
14
- > variables. Read it before you conclude something is wrong with the package.
15
-
16
- ## How Secrets Work
17
-
18
- You never manage signing keys or OAuth credentials directly. The package resolves them automatically at startup based on your environment.
19
-
20
- | Environment | How it works | Secrets in your config? |
21
- |-------------|-------------|------------------------|
22
- | **Dev** | App calls IDP broker on your private network. One API key in `.env.local`. | One key (rotatable via CLI) |
23
- | **Production** | App calls a cluster-internal endpoint. Network boundary = identity. | None |
24
- | **Enterprise** | App uses an issued license key against your own or our IDP. | One key (rotatable via CLI) |
25
-
26
- **In production, there are no secrets to configure, rotate, or leak.** The app proves its identity by being inside the cluster.
27
-
28
- In dev, you have one key. Rotate it anytime:
29
-
30
- ```bash
31
- npx @payez/cli secret rotate
32
- ```
33
-
34
- Full architecture: [SECRET-MANAGEMENT-ARCHITECTURE.md](../../docs/SECRET-MANAGEMENT-ARCHITECTURE.md)
35
-
36
- ## Features
37
-
38
- - **Zero-secret production deployment** โ€” no signing keys, no OAuth secrets in your env
39
- - **Complete authentication flow** โ€” login, logout, session management, password recovery
40
- - **Pre-built UI components** โ€” themed login, recovery, and verify-code pages
41
- - **Automatic token refresh** โ€” built-in refresh token handling with Redis session backing
42
- - **Google OAuth + 2FA** โ€” pre-configured providers, MFA with email/SMS
43
- - **Themeable** โ€” branding, colors, and layout via ThemeProvider
44
- - **Next.js 14/15** โ€” App Router, React Server Components, middleware-ready
45
-
46
- ## Installation
47
-
48
- ```bash
49
- npm install @payez/next-mvp next-auth
50
- # or
51
- yarn add @payez/next-mvp next-auth
52
- ```
53
-
54
- ### Peer Dependencies
55
-
56
- Ensure you have these installed:
57
-
58
- ```bash
59
- npm install next@^14.0.0 next-auth@^4.24.7 react@^18.2.0 react-dom@^18.2.0
60
- ```
61
-
62
- ---
63
-
64
- ## Development Scripts
65
-
66
- PayEz MVP includes convenient development scripts for getting started quickly:
67
-
68
- ### `npm run dev:local`
69
-
70
- **Local Development Mode** - Perfect for first-time setup and testing without an external IDP:
71
- - Auto-generates `NEXTAUTH_SECRET` for you
72
- - No external IDP connection required
73
- - Great for UI development and testing
74
-
75
- ```bash
76
- npm run dev:local
77
- ```
78
-
79
- This will:
80
- 1. Generate a secure random `NEXTAUTH_SECRET`
81
- 2. Display the secret (save it to your `.env.local`)
82
- 3. Start the Next.js dev server on port 3000
83
-
84
- ### `npm run dev:broker`
85
-
86
- **Broker Mode** - Production-like authentication with PayEz IDP:
87
- - Uses OAuth/OIDC flow with PayEz IDP
88
- - Client assertion authentication
89
- - Required for testing real authentication flows
90
- - **This is a core feature for PayEz MVP users**
91
-
92
- ```bash
93
- npm run dev:broker
94
- ```
95
-
96
- This will:
97
- 1. Enable broker mode (`USE_BROKER_MODE=true`)
98
- 2. Set client ID for IDP authentication
99
- 3. Start the Next.js dev server on port 3000
100
- 4. Automatically kills any existing process on port 3000
101
-
102
- **Custom Port & Client ID:**
103
- ```bash
104
- # In your consuming project's package.json
105
- "scripts": {
106
- "dev:broker": "pwsh -NoProfile -ExecutionPolicy Bypass -File node_modules/@payez/next-mvp/scripts/dev-broker.ps1 -ClientId 2 -Port 3400"
107
- }
108
- ```
109
-
110
- ### Which Script to Use?
111
-
112
- | Scenario | Script | When to Use |
113
- |----------|--------|-------------|
114
- | ๐ŸŽจ UI Development | `dev:local` | Building components, testing UI flows |
115
- | ๐Ÿ” Auth Testing | `dev:broker` | Testing real OAuth flows, token management |
116
- | ๐Ÿš€ Production-like | `dev:broker` | Testing with actual IDP integration |
117
-
118
- ---
119
-
120
- ## Quick Start (App Router with UI Components)
121
-
122
- ### 1. Configure Next.js
123
-
124
- Add to your `next.config.ts`:
125
-
126
- ```typescript
127
- import type { NextConfig } from "next";
128
-
129
- const nextConfig: NextConfig = {
130
- transpilePackages: ['@payez/next-mvp'],
131
- };
132
-
133
- export default nextConfig;
134
- ```
135
-
136
- ### 2. Set Environment Variables
137
-
138
- Create `.env.local` (or `.env.development`) in your project root:
139
-
140
- ```bash
141
- # PayEz IDP Configuration (required)
142
- CLIENT_ID=your_client_slug_from_payez # e.g., "payez_idp_admin_web"
143
- IDP_URL=https://idp.payez.net # or http://localhost:32785 for local dev
144
-
145
- # NextAuth trusts request headers for OAuth callback URLs
146
- AUTH_TRUST_HOST=true
147
-
148
- # Secrets are resolved ENV FIRST, IdP client config second (PAY-1460, 4.4.6+).
149
- # The IdP is retiring the secrets it serves in client config, so production
150
- # deployments should set these from a k8s secret:
151
- # BETTER_AUTH_SECRET=... # session signing secret (canonical name)
152
- # NEXTAUTH_SECRET=... # legacy alias, used only if BETTER_AUTH_SECRET is unset
153
- # GOOGLE_CLIENT_SECRET=... # per OAuth provider: <PROVIDER>_CLIENT_SECRET,
154
- # APPLE_CLIENT_SECRET=... # provider name upper-cased, non-alphanumerics as "_"
155
- # Startup is FATAL only when BOTH the env and the IdP config lack a signing secret.
156
- # Values are never logged; the log names the source ("authSecret source: env:BETTER_AUTH_SECRET").
157
- # Env-sourced secrets are never written to the Redis config cache.
158
-
159
- # Optional
160
- REDIS_URL=redis://localhost:6379 # For session storage
161
- NEXT_PUBLIC_IDP_BASE_URL=https://idp.payez.net # For client-side redirects
162
- ```
163
-
164
- > **Note:** `NEXTAUTH_SECRET` is intentionally omitted. The MVP automatically fetches it from the IDP at startup using the broker pattern. See [Environment Variables Reference](#environment-variables-reference) for details.
165
-
166
- ### 3. Create NextAuth API Route
167
-
168
- Create `app/api/auth/[...nextauth]/route.ts`:
169
-
170
- ```typescript
171
- /**
172
- * NextAuth API Route Handler
173
- * Uses pre-configured handler from @payez/next-mvp
174
- */
175
- export { GET, POST } from '@payez/next-mvp/routes/auth/nextauth';
176
- ```
177
-
178
- ### 4. Wrap Your App with Providers
179
-
180
- Create `app/providers.tsx`:
181
-
182
- ```typescript
183
- 'use client';
184
-
185
- import { SessionProvider } from 'next-auth/react';
186
- import { ThemeProvider } from '@payez/next-mvp/theme';
187
-
188
- export function Providers({ children }: { children: React.ReactNode }) {
189
- return (
190
- <SessionProvider>
191
- <ThemeProvider>
192
- {children}
193
- </ThemeProvider>
194
- </SessionProvider>
195
- );
196
- }
197
- ```
198
-
199
- Update `app/layout.tsx`:
200
-
201
- ```typescript
202
- import { Providers } from './providers';
203
-
204
- export default function RootLayout({
205
- children,
206
- }: {
207
- children: React.ReactNode;
208
- }) {
209
- return (
210
- <html lang="en">
211
- <body>
212
- <Providers>
213
- {children}
214
- </Providers>
215
- </body>
216
- </html>
217
- );
218
- }
219
- ```
220
-
221
- ### 5. Add Authentication Pages
222
-
223
- **Login Page** - `app/account-auth/login/page.tsx`:
224
-
225
- ```typescript
226
- 'use client';
227
-
228
- import LoginPage from '@payez/next-mvp/dist/pages/login';
229
-
230
- export default function LoginPageWrapper() {
231
- return <LoginPage />;
232
- }
233
- ```
234
-
235
- **Password Recovery** - `app/account-auth/recovery/page.tsx`:
236
-
237
- ```typescript
238
- 'use client';
239
-
240
- import RecoveryPage from '@payez/next-mvp/dist/pages/recovery';
241
-
242
- export default function RecoveryPageWrapper() {
243
- return <RecoveryPage />;
244
- }
245
- ```
246
-
247
- **Verify Code (2FA)** - `app/account-auth/verify-code/page.tsx`:
248
-
249
- ```typescript
250
- 'use client';
251
-
252
- import VerifyCodePage from '@payez/next-mvp/dist/pages/verify-code';
253
-
254
- export default function VerifyCodePageWrapper() {
255
- return <VerifyCodePage />;
256
- }
257
- ```
258
-
259
- #### What your app must serve (PAY-2121)
260
-
261
- The IdP emails links that land on paths your app must host. Two of them are
262
- conventions the kit mounts for you; wire them or the link 404s at your site:
263
-
264
- **Invitation / onboarding** - `app/account-auth/onboarding/page.tsx`:
265
-
266
- ```typescript
267
- // The IdP's welcome email links to
268
- // {your site}/account-auth/onboarding?client_id=&onboard_token=
269
- export { default } from '@payez/next-mvp/pages/onboarding';
270
- ```
271
-
272
- and the API it posts to (token-driven, no session) - one mount file each:
273
-
274
- ```typescript
275
- // app/api/onboarding/verify-code/route.ts
276
- export { POST } from '@payez/next-mvp/routes/onboarding/verify-code';
277
- // app/api/onboarding/send-email-code/route.ts
278
- export { POST } from '@payez/next-mvp/routes/onboarding/send-email-code';
279
- // app/api/onboarding/verify-welcome-email/route.ts
280
- export { POST } from '@payez/next-mvp/routes/onboarding/verify-welcome-email';
281
- // app/api/onboarding/set-password/route.ts
282
- export { POST } from '@payez/next-mvp/routes/onboarding/set-password';
283
- ```
284
-
285
- **Post-verify reset fragment on `/`** - mount the bridge on your home page:
286
-
287
- ```typescript
288
- // app/page.tsx
289
- import { PasswordResetBridge } from '@payez/next-mvp/components/auth/PasswordResetBridge';
290
-
291
- export default function Home() {
292
- return (<><PasswordResetBridge />{/* your home page */}</>);
293
- }
294
- ```
295
-
296
- When the IdP's verification redirect lands on `/#password_reset_required=true&reset_token=โ€ฆ&email=โ€ฆ`
297
- (a fragment, for a passwordless account), the bridge performs one replace to
298
- `/account-auth/recovery?token=โ€ฆ&email=โ€ฆ` and clears the hash. With any other
299
- fragment it renders nothing. `npx @payez/create-next-app` writes all of the above.
300
-
301
- **Registration** has two doors, and the kit ships neither as a page:
302
-
303
- - **Owner-initiated invite** (shipped here): an existing owner invites a user; the invite
304
- email lands on `/account-auth/onboarding` (above), which the kit now serves.
305
- - **Self-serve sign-up**: the kit exposes the IdP's ProgressiveAuth flow as API endpoints
306
- (`/api/ProgressiveAuth/step1`..`step5`, then `/api/ProgressiveAuth/verify-email`;
307
- `API_ENDPOINTS.progressiveAuth` in `config/env.ts`). The kit ships **no** registration
308
- page, so a developer who wants self-serve sign-up authors a page that drives that flow,
309
- respecting the tenant's `allow_public_registration` / waitlist state. The login page no
310
- longer links a register page, because the kit does not ship one.
311
-
312
- ### 6. Protect Routes with Authentication
313
-
314
- **Server-side protection:**
315
-
316
- ```typescript
317
- import { getServerSession } from 'next-auth';
318
- import { redirect } from 'next/navigation';
319
-
320
- export default async function DashboardPage() {
321
- const session = await getServerSession();
322
-
323
- if (!session) {
324
- redirect('/account-auth/login');
325
- }
326
-
327
- return (
328
- <div>
329
- <h1>Welcome, {session.user?.email}</h1>
330
- </div>
331
- );
332
- }
333
- ```
334
-
335
- **Client-side hook:**
336
-
337
- ```typescript
338
- 'use client';
339
-
340
- import { useSession } from 'next-auth/react';
341
-
342
- export default function ProfilePage() {
343
- const { data: session, status } = useSession();
344
-
345
- if (status === 'loading') return <div>Loading...</div>;
346
- if (status === 'unauthenticated') return <div>Access Denied</div>;
347
-
348
- return <div>Logged in as {session?.user?.email}</div>;
349
- }
350
- ```
351
-
352
- ---
353
-
354
- ## Advanced: V2 Middleware-Based Setup
355
-
356
- For applications requiring middleware-based route protection:
357
-
358
- ### 1. Configure Public Routes
359
-
360
- Create `src/lib/auth.ts`:
361
-
362
- ```typescript
363
- import { configurePublicRoutes, createAuthOptions } from '@payez/next-mvp';
364
- import CredentialsProvider from 'next-auth/providers/credentials';
365
-
366
- // Define routes that do NOT require authentication
367
- const publicRoutes = [
368
- '/',
369
- '/login',
370
- '/api/health',
371
- '/api/public/*', // Wildcard example
372
- ];
373
-
374
- configurePublicRoutes(publicRoutes);
375
-
376
- export const authOptions = createAuthOptions({
377
- credentialsProvider: CredentialsProvider,
378
- // Additional NextAuthOptions can be passed here
379
- });
380
-
381
- export { authOptions as GET, authOptions as POST } from './auth';
382
- ```
383
-
384
- ### 2. Setup NextAuth API Route
385
-
386
- **For Pages Router (`pages/api/auth/[...nextauth].ts`):**
387
-
388
- ```typescript
389
- import NextAuth from 'next-auth';
390
- import { authOptions } from '../../../src/lib/auth';
391
-
392
- export default NextAuth(authOptions);
393
- ```
394
-
395
- **For App Router (`app/api/auth/[...nextauth]/route.ts`):**
396
-
397
- ```typescript
398
- export { GET, POST } from '../../../src/lib/auth';
399
- ```
400
-
401
- ### 3. Implement Middleware
402
-
403
- Create `middleware.ts` at project root:
404
-
405
- ```typescript
406
- import { createMvpMiddleware } from '@payez/next-mvp';
407
-
408
- export default createMvpMiddleware();
409
-
410
- export const config = {
411
- matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
412
- };
413
- ```
414
-
415
- ### 4. Use `fetchWithAuth` for Protected API Calls
416
-
417
- ```typescript
418
- import { fetchWithAuth } from '@payez/next-mvp';
419
-
420
- async function fetchData() {
421
- try {
422
- const response = await fetchWithAuth('/api/protected-data');
423
- const data = await response.json();
424
- console.log(data);
425
- } catch (error) {
426
- console.error('Failed to fetch protected data:', error);
427
- }
428
- }
429
- ```
430
-
431
- ### 5. Session Viability API Handler
432
-
433
- **For Pages Router (`pages/api/session/viability.ts`):**
434
-
435
- ```typescript
436
- import viabilityHandler from '@payez/next-mvp/api-handlers/session/viability';
437
-
438
- export default viabilityHandler;
439
- ```
440
-
441
- **For App Router (`app/api/session/viability/route.ts`):**
442
-
443
- ```typescript
444
- export { default as GET } from '@payez/next-mvp/api-handlers/session/viability';
445
- ```
446
-
447
- ---
448
-
449
- ## Custom Theming
450
-
451
- Customize branding and colors:
452
-
453
- ```typescript
454
- // lib/mvp-theme-config.ts
455
- import { ThemeConfig } from '@payez/next-mvp/theme';
456
-
457
- const customTheme: ThemeConfig = {
458
- branding: {
459
- companyName: "Your Company",
460
- logoUrl: "/logo.svg",
461
- logoAlt: "Your Company Logo"
462
- },
463
- colors: {
464
- primary: "#3b82f6", // Blue
465
- primaryHover: "#2563eb",
466
- secondary: "#10b981", // Green
467
- danger: "#ef4444", // Red
468
- text: "#1f2937",
469
- textLight: "#6b7280",
470
- background: "#ffffff",
471
- backgroundAlt: "#f9fafb",
472
- border: "#e5e7eb"
473
- },
474
- layout: {
475
- maxWidth: "28rem", // max-w-md
476
- padding: "1.5rem", // p-6
477
- borderRadius: "0.5rem" // rounded-lg
478
- }
479
- };
480
-
481
- export default customTheme;
482
- ```
483
-
484
- Then use in your Providers:
485
-
486
- ```typescript
487
- import customTheme from '@/lib/mvp-theme-config';
488
-
489
- export function Providers({ children }: { children: React.ReactNode }) {
490
- return (
491
- <SessionProvider>
492
- <ThemeProvider theme={customTheme}>
493
- {children}
494
- </ThemeProvider>
495
- </SessionProvider>
496
- );
497
- }
498
- ```
499
-
500
- ---
501
-
502
- ## API Routes
503
-
504
- Access pre-built API handlers:
505
-
506
- ```typescript
507
- // Session validation
508
- import { GET as validateSession } from '@payez/next-mvp/routes/auth/session';
509
-
510
- // Token refresh
511
- import { POST as refreshToken } from '@payez/next-mvp/routes/auth/refresh';
512
-
513
- // Logout
514
- import { POST as logout } from '@payez/next-mvp/routes/auth/logout';
515
- ```
516
-
517
- ---
518
-
519
- ## Environment Variables Reference
520
-
521
- | Variable | Required | Description |
522
- |----------|----------|-------------|
523
- | `CLIENT_ID` | โœ… Yes | Your PayEz IDP client ID (string slug, e.g., `payez_idp_admin_web`) |
524
- | `IDP_URL` | โœ… Yes | PayEz IDP base URL (e.g., `https://idp.payez.net` or `http://localhost:32785`) |
525
- | `AUTH_TRUST_HOST` | โœ… Yes | Must be `true` - NextAuth derives OAuth URLs from request headers |
526
- | `NEXTAUTH_SECRET` | ๐Ÿ”„ Broker | **Do NOT set** - fetched automatically from IDP at startup (see below) |
527
- | `CLIENT_SECRET` | โš ๏ธ Legacy | Not needed with broker mode - IDP handles signing |
528
- | `NEXT_PUBLIC_IDP_BASE_URL` | โš ๏ธ Optional | Public-facing IDP URL (for client-side redirects) |
529
- | `REDIS_URL` | โš ๏ธ Optional | Redis connection string for session storage |
530
-
531
- ### NEXTAUTH_SECRET Broker Flow
532
-
533
- **The MVP uses a "broker" pattern for NEXTAUTH_SECRET** - the IDP securely provides it at startup rather than storing it in env files.
534
-
535
- ```
536
- โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
537
- โ”‚ App Startup (instrumentation.ts โ†’ ensureInitialized) โ”‚
538
- โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
539
- โ”‚
540
- โ–ผ
541
- โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
542
- โ”‚ Is NEXTAUTH_SECRET set and non-empty? โ”‚
543
- โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
544
- โ”‚ โ”‚
545
- YES NO (recommended)
546
- โ”‚ โ”‚
547
- โ–ผ โ–ผ
548
- โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
549
- โ”‚ Use as-is โ”‚ โ”‚ Fetch from IDP (Broker Mode) โ”‚
550
- โ”‚ (override) โ”‚ โ”‚ 1. Sign client assertion โ”‚
551
- โ”‚ โ”‚ โ”‚ 2. POST to /next-auth/secret โ”‚
552
- โ”‚ โ”‚ โ”‚ 3. Set process.env at runtime โ”‚
553
- โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
554
- ```
555
-
556
- **Key points:**
557
- - **Do NOT set `NEXTAUTH_SECRET` in `.env` files** - leave it undefined
558
- - The IDP provides the secret securely at startup via client assertion
559
- - Secret is cached for 5 minutes, then re-fetched if needed
560
- - If you DO set it manually, that value takes precedence (useful for overrides)
561
- - The broker needs `CLIENT_ID` and `IDP_URL` to fetch the secret
562
-
563
- ---
564
-
565
- ## Troubleshooting
566
-
567
- ### SessionProvider Error
568
-
569
- If you see `useSession must be wrapped in a <SessionProvider />`:
570
-
571
- 1. Ensure `transpilePackages: ['@payez/next-mvp']` is in `next.config.ts`
572
- 2. Make sure all page components using PayEz components have `'use client'` directive
573
- 3. Verify your app is wrapped with `<Providers>` in `layout.tsx`
574
-
575
- ### Module Resolution Errors
576
-
577
- If you get `Module not found` errors:
578
-
579
- 1. Clear Next.js cache: `rm -rf .next`
580
- 2. Reinstall dependencies: `npm install`
581
- 3. Restart dev server
582
-
583
- ### Authentication Not Working
584
-
585
- 1. Verify `CLIENT_ID` and `IDP_URL` are set correctly
586
- 2. Check `CLIENT_ID` matches your PayEz IDP configuration (use the slug, not numeric ID)
587
- 3. Verify IDP is running and reachable at `IDP_URL`
588
- 4. Check server logs for broker startup messages - look for "NEXTAUTH_SECRET Successfully Fetched from IDP"
589
- 5. If secret fetch fails, check IDP logs for client assertion errors
590
- 6. Check browser console for error messages
591
-
592
- ### NEXTAUTH_SECRET Issues
593
-
594
- **"NEXTAUTH_SECRET not available" error:**
595
- - This means the broker couldn't fetch the secret from IDP
596
- - Check that `IDP_URL` is correct and IDP is running
597
- - Verify `CLIENT_ID` is registered in the IDP
598
- - Check network connectivity between your app and IDP
599
-
600
- **Cookie cross-contamination (localhost development):**
601
- - If running multiple apps on localhost (different ports), NextAuth cookies can conflict
602
- - Clear `next-auth.*` cookies in browser, or use incognito
603
- - Each app uses a unique cookie name based on CLIENT_ID to avoid conflicts
604
-
605
- ---
606
-
607
- ## Docker/CI Deployment (IMPORTANT)
608
-
609
- When consuming `@payez/next-mvp` via a local `.tgz` file in Docker builds, you **must** use a local path reference.
610
-
611
- ### The Problem
612
-
613
- If your `package.json` references the MVP like this:
614
- ```json
615
- "@payez/next-mvp": "file:../PayEz-Next-MVP/packages/next-mvp/payez-next-mvp-2.6.50.tgz"
616
- ```
617
-
618
- Docker builds will **fail** with:
619
- ```
620
- npm error ENOENT: no such file or directory, open '/PayEz-Next-MVP/packages/next-mvp/payez-next-mvp-2.6.50.tgz'
621
- ```
622
-
623
- The relative path `../` resolves incorrectly inside the Docker container's `/app` working directory.
624
-
625
- ### The Fix
626
-
627
- 1. **Copy the `.tgz` file into your project root:**
628
- ```bash
629
- cp ../PayEz-Next-MVP/packages/next-mvp/payez-next-mvp-*.tgz ./
630
- ```
631
-
632
- 2. **Update `package.json` to use a local reference:**
633
- ```json
634
- "@payez/next-mvp": "file:./payez-next-mvp-2.6.50.tgz"
635
- ```
636
-
637
- 3. **Run `npm install` to update `package-lock.json`**
638
-
639
- 4. **Ensure your Dockerfile copies the tgz:**
640
- ```dockerfile
641
- COPY payez-next-mvp-*.tgz ./
642
- ```
643
-
644
- ### Quick Fix Script
645
-
646
- Run this in your consuming project to fix the path:
647
- ```bash
648
- # Copy latest tgz
649
- cp ../PayEz-Next-MVP/packages/next-mvp/payez-next-mvp-*.tgz ./
650
-
651
- # Update package.json path (adjust version as needed)
652
- sed -i 's|file:../PayEz-Next-MVP/packages/next-mvp/|file:./|g' package.json
653
-
654
- # Regenerate lockfile
655
- npm install --legacy-peer-deps
656
- ```
657
-
658
- ### After MVP Version Updates
659
-
660
- When you update the MVP package version, repeat steps 1-3 to copy the new `.tgz` and update references.
661
-
662
- ---
663
-
664
- ## Pre-Publishing Checklist (For Package Maintainers)
665
-
666
- Before publishing this package to npm:
667
-
668
- ### โœ… Code Quality
669
- - [x] All `@/` path aliases converted to relative paths
670
- - [x] TypeScript compiles without errors: `npm run build`
671
- - [x] No hardcoded configuration values (use env variables)
672
- - [ ] Unit tests pass (if implemented)
673
-
674
- ### ๐Ÿ“ฆ Package Configuration
675
-
676
- **CRITICAL FIXES NEEDED:**
677
-
678
- 1. **Fix `main` field in package.json (Line 5):**
679
- ```json
680
- "main": "dist/index.js", // NOT "src/index.ts"
681
- ```
682
-
683
- 2. **Remove unused `tsc-alias` from devDependencies (Line 542):**
684
- ```json
685
- // DELETE this line:
686
- "tsc-alias": "^1.8.16"
687
- ```
688
-
689
- 3. **Add package metadata:**
690
- ```json
691
- {
692
- "description": "PayEz IDP authentication package for Next.js with ready-to-use login, recovery, and profile pages",
693
- "keywords": ["nextjs", "authentication", "next-auth", "payez", "idp", "oauth"],
694
- "author": "PayEz Team",
695
- "license": "MIT",
696
- "repository": {
697
- "type": "git",
698
- "url": "https://github.com/your-org/PayEz-Next-MVP"
699
- },
700
- "homepage": "https://github.com/your-org/PayEz-Next-MVP#readme",
701
- "bugs": {
702
- "url": "https://github.com/your-org/PayEz-Next-MVP/issues"
703
- }
704
- }
705
- ```
706
-
707
- ### ๐Ÿ“ Documentation
708
- - [x] README.md is complete and accurate
709
- - [ ] CHANGELOG.md exists with version history
710
- - [ ] LICENSE file exists
711
-
712
- ### ๐Ÿงช Testing
713
- - [ ] Test fresh installation in new Next.js 14 project
714
- - [ ] Test fresh installation in new Next.js 15 project
715
- - [ ] Verify all exported modules work
716
- - [ ] Test with React 18 and React 19
717
- - [ ] Test package build: `npm pack --dry-run`
718
-
719
- ### ๐Ÿš€ Publishing Steps
720
-
721
- ```bash
722
- # 1. Fix package.json issues (see above)
723
-
724
- # 2. Login to npm
725
- npm login
726
-
727
- # 3. Build package
728
- npm run build
729
-
730
- # 4. Preview what will be published
731
- npm pack --dry-run
732
-
733
- # 5. Test the tarball locally
734
- npm install ./payez-next-mvp-2.3.1.tgz
735
-
736
- # 6. Bump version (patch/minor/major)
737
- npm version patch # 2.3.1 -> 2.3.2
738
- npm version minor # 2.3.1 -> 2.4.0
739
- npm version major # 2.3.1 -> 3.0.0
740
-
741
- # 7. Publish to npm
742
- npm publish
743
-
744
- # 8. Create git tag and push
745
- git push origin main
746
- git push origin --tags
747
- ```
748
-
749
- ### ๐Ÿ“‹ .npmignore
750
-
751
- Create `.npmignore` to exclude unnecessary files:
752
-
753
- ```
754
- src/
755
- *.test.ts
756
- *.test.tsx
757
- tsconfig.json
758
- .gitignore
759
- .git
760
- node_modules/
761
- *.tgz
762
- .env*
763
- ```
764
-
765
- ### ๐Ÿ”’ Publish Configuration
766
-
767
- Add to package.json:
768
-
769
- ```json
770
- "publishConfig": {
771
- "access": "public",
772
- "registry": "https://registry.npmjs.org/"
773
- }
774
- ```
775
-
776
- ---
777
-
778
- ## ๐Ÿ“š Complete Documentation
779
-
780
- ### Core Guides
781
-
782
- - **[THEMING.md](./docs/THEMING.md)** - Complete guide to customizing auth components
783
- - Theme structure and configuration
784
- - Creating light/dark modes
785
- - Component-specific customization
786
- - Common theming issues and solutions
787
-
788
- - **[CSS_VARIABLES_INTEGRATION.md](./docs/CSS_VARIABLES_INTEGRATION.md)** - CSS variable injection for MVP components
789
- - Why CSS variables are needed
790
- - How to inject variables in your app
791
- - Color conversion utilities
792
- - Debugging CSS variable issues
793
-
794
- - **[THEME_EXAMPLES.md](./docs/THEME_EXAMPLES.md)** - Ready-to-use theme examples
795
- - 7 pre-built professional themes
796
- - Multi-brand theme support
797
- - Dynamic light/dark mode
798
- - Copy-paste theme configurations
799
-
800
- ### Topics Covered
801
-
802
- #### Theming
803
- - โœ… Brand colors and logos
804
- - โœ… Light and dark modes
805
- - โœ… Font families and typography
806
- - โœ… Layout and spacing customization
807
- - โœ… Component-specific styling
808
- - โœ… Multi-tenant/white-label setups
809
- - โœ… Accessibility and contrast
810
-
811
- #### CSS Variables
812
- - โœ… Understanding CSS custom properties
813
- - โœ… Manual variable injection
814
- - โœ… Color conversion (Tailwind โ†’ hex)
815
- - โœ… Theme provider pattern
816
- - โœ… Dynamic theme switching
817
- - โœ… Debugging in DevTools
818
-
819
- #### Examples
820
- - โœ… Corporate themes
821
- - โœ… SaaS themes
822
- - โœ… Creative/design themes
823
- - โœ… Accessible high-contrast themes
824
- - โœ… Multi-brand configurations
825
- - โœ… Gradient backgrounds
826
- - โœ… Custom branding
827
-
828
- ### Quick Links
829
-
830
- **Getting Started with Themes:**
831
- 1. Start with [THEMING.md](./docs/THEMING.md) - Quick Start section
832
- 2. Copy a theme from [THEME_EXAMPLES.md](./docs/THEME_EXAMPLES.md)
833
- 3. Follow integration pattern in [CSS_VARIABLES_INTEGRATION.md](./docs/CSS_VARIABLES_INTEGRATION.md)
834
-
835
- **For Specific Tasks:**
836
- - Want to change colors? โ†’ [THEMING.md - Creating a Theme](./docs/THEMING.md#creating-a-theme)
837
- - Pages rendering white/no color? โ†’ [CSS_VARIABLES_INTEGRATION.md - Troubleshooting](./docs/CSS_VARIABLES_INTEGRATION.md#troubleshooting)
838
- - Need a complete example? โ†’ [THEME_EXAMPLES.md](./docs/THEME_EXAMPLES.md)
839
- - Debugging styling issues? โ†’ [THEMING.md - Common Issues](./docs/THEMING.md#common-issues--solutions)
840
-
841
- ---
842
-
843
- ## License
844
-
845
- MIT
846
-
847
- ## Support
848
-
849
- For issues and questions:
850
- - GitHub Issues: https://github.com/your-org/PayEz-Next-MVP/issues
851
- - Documentation: https://docs.payez.net
852
-
853
- ## Contributing
854
-
855
- Contributions welcome! Please read our contributing guidelines first.
856
-
857
- ---
858
-
859
- Made with โค๏ธ by the PayEz Team
1
+ # @payez/next-mvp
2
+
3
+ Drop-in authentication for Next.js. One package, zero secret management in production.
4
+
5
+ ```bash
6
+ npm install @payez/next-mvp next-auth
7
+ ```
8
+
9
+ > **Installing is not finishing.** There is no `postinstall` step and no generator, so the
10
+ > package cannot mount its own routes or pages into your `app/` directory, and it does not
11
+ > emit the CSS variables its components read. **[POST-INSTALL.md](./POST-INSTALL.md) is the
12
+ > complete list of what you must still do by hand** โ€” including three that leave the site
13
+ > broken with nothing to tell you why: the auth routes, the login page, and the sixteen theme
14
+ > variables. Read it before you conclude something is wrong with the package.
15
+
16
+ ## How Secrets Work
17
+
18
+ You never manage signing keys or OAuth credentials directly. The package resolves them automatically at startup based on your environment.
19
+
20
+ | Environment | How it works | Secrets in your config? |
21
+ |-------------|-------------|------------------------|
22
+ | **Dev** | App calls IDP broker on your private network. One API key in `.env.local`. | One key (rotatable via CLI) |
23
+ | **Production** | App calls a cluster-internal endpoint. Network boundary = identity. | None |
24
+ | **Enterprise** | App uses an issued license key against your own or our IDP. | One key (rotatable via CLI) |
25
+
26
+ **In production, there are no secrets to configure, rotate, or leak.** The app proves its identity by being inside the cluster.
27
+
28
+ In dev, you have one key. Rotate it anytime:
29
+
30
+ ```bash
31
+ npx @payez/cli secret rotate
32
+ ```
33
+
34
+ Full architecture: [SECRET-MANAGEMENT-ARCHITECTURE.md](../../docs/SECRET-MANAGEMENT-ARCHITECTURE.md)
35
+
36
+ ## Features
37
+
38
+ - **Zero-secret production deployment** โ€” no signing keys, no OAuth secrets in your env
39
+ - **Complete authentication flow** โ€” login, logout, session management, password recovery
40
+ - **Pre-built UI components** โ€” themed login, recovery, and verify-code pages
41
+ - **Automatic token refresh** โ€” built-in refresh token handling with Redis session backing
42
+ - **Google OAuth + 2FA** โ€” pre-configured providers, MFA with email/SMS
43
+ - **Themeable** โ€” branding, colors, and layout via ThemeProvider
44
+ - **Next.js 14/15** โ€” App Router, React Server Components, middleware-ready
45
+
46
+ ## Installation
47
+
48
+ ```bash
49
+ npm install @payez/next-mvp next-auth
50
+ # or
51
+ yarn add @payez/next-mvp next-auth
52
+ ```
53
+
54
+ ### Peer Dependencies
55
+
56
+ Ensure you have these installed:
57
+
58
+ ```bash
59
+ npm install next@^14.0.0 next-auth@^4.24.7 react@^18.2.0 react-dom@^18.2.0
60
+ ```
61
+
62
+ ---
63
+
64
+ ## Development Scripts
65
+
66
+ PayEz MVP includes convenient development scripts for getting started quickly:
67
+
68
+ ### `npm run dev:local`
69
+
70
+ **Local Development Mode** - Perfect for first-time setup and testing without an external IDP:
71
+ - Auto-generates `NEXTAUTH_SECRET` for you
72
+ - No external IDP connection required
73
+ - Great for UI development and testing
74
+
75
+ ```bash
76
+ npm run dev:local
77
+ ```
78
+
79
+ This will:
80
+ 1. Generate a secure random `NEXTAUTH_SECRET`
81
+ 2. Display the secret (save it to your `.env.local`)
82
+ 3. Start the Next.js dev server on port 3000
83
+
84
+ ### `npm run dev:broker`
85
+
86
+ **Broker Mode** - Production-like authentication with PayEz IDP:
87
+ - Uses OAuth/OIDC flow with PayEz IDP
88
+ - Client assertion authentication
89
+ - Required for testing real authentication flows
90
+ - **This is a core feature for PayEz MVP users**
91
+
92
+ ```bash
93
+ npm run dev:broker
94
+ ```
95
+
96
+ This will:
97
+ 1. Enable broker mode (`USE_BROKER_MODE=true`)
98
+ 2. Set client ID for IDP authentication
99
+ 3. Start the Next.js dev server on port 3000
100
+ 4. Automatically kills any existing process on port 3000
101
+
102
+ **Custom Port & Client ID:**
103
+ ```bash
104
+ # In your consuming project's package.json
105
+ "scripts": {
106
+ "dev:broker": "pwsh -NoProfile -ExecutionPolicy Bypass -File node_modules/@payez/next-mvp/scripts/dev-broker.ps1 -ClientId 2 -Port 3400"
107
+ }
108
+ ```
109
+
110
+ ### Which Script to Use?
111
+
112
+ | Scenario | Script | When to Use |
113
+ |----------|--------|-------------|
114
+ | ๐ŸŽจ UI Development | `dev:local` | Building components, testing UI flows |
115
+ | ๐Ÿ” Auth Testing | `dev:broker` | Testing real OAuth flows, token management |
116
+ | ๐Ÿš€ Production-like | `dev:broker` | Testing with actual IDP integration |
117
+
118
+ ---
119
+
120
+ ## Quick Start (App Router with UI Components)
121
+
122
+ ### 1. Configure Next.js
123
+
124
+ Add to your `next.config.ts`:
125
+
126
+ ```typescript
127
+ import type { NextConfig } from "next";
128
+
129
+ const nextConfig: NextConfig = {
130
+ transpilePackages: ['@payez/next-mvp'],
131
+ };
132
+
133
+ export default nextConfig;
134
+ ```
135
+
136
+ ### 2. Set Environment Variables
137
+
138
+ Create `.env.local` (or `.env.development`) in your project root:
139
+
140
+ ```bash
141
+ # PayEz IDP Configuration (required)
142
+ CLIENT_ID=your_client_slug_from_payez # e.g., "payez_idp_admin_web"
143
+ IDP_URL=https://idp.payez.net # or http://localhost:32785 for local dev
144
+
145
+ # NextAuth trusts request headers for OAuth callback URLs
146
+ AUTH_TRUST_HOST=true
147
+
148
+ # Secrets are resolved ENV FIRST, IdP client config second (PAY-1460, 4.4.6+).
149
+ # The IdP is retiring the secrets it serves in client config, so production
150
+ # deployments should set these from a k8s secret:
151
+ # BETTER_AUTH_SECRET=... # session signing secret (canonical name)
152
+ # NEXTAUTH_SECRET=... # legacy alias, used only if BETTER_AUTH_SECRET is unset
153
+ # GOOGLE_CLIENT_SECRET=... # per OAuth provider: <PROVIDER>_CLIENT_SECRET,
154
+ # APPLE_CLIENT_SECRET=... # provider name upper-cased, non-alphanumerics as "_"
155
+ # Startup is FATAL only when BOTH the env and the IdP config lack a signing secret.
156
+ # Values are never logged; the log names the source ("authSecret source: env:BETTER_AUTH_SECRET").
157
+ # Env-sourced secrets are never written to the Redis config cache.
158
+
159
+ # Optional
160
+ REDIS_URL=redis://localhost:6379 # For session storage
161
+ NEXT_PUBLIC_IDP_BASE_URL=https://idp.payez.net # For client-side redirects
162
+ ```
163
+
164
+ > **Note:** `NEXTAUTH_SECRET` is intentionally omitted. The MVP automatically fetches it from the IDP at startup using the broker pattern. See [Environment Variables Reference](#environment-variables-reference) for details.
165
+
166
+ ### 3. Create NextAuth API Route
167
+
168
+ Create `app/api/auth/[...nextauth]/route.ts`:
169
+
170
+ ```typescript
171
+ /**
172
+ * NextAuth API Route Handler
173
+ * Uses pre-configured handler from @payez/next-mvp
174
+ */
175
+ export { GET, POST } from '@payez/next-mvp/routes/auth/nextauth';
176
+ ```
177
+
178
+ ### 4. Wrap Your App with Providers
179
+
180
+ Create `app/providers.tsx`:
181
+
182
+ ```typescript
183
+ 'use client';
184
+
185
+ import { SessionProvider } from 'next-auth/react';
186
+ import { ThemeProvider } from '@payez/next-mvp/theme';
187
+
188
+ export function Providers({ children }: { children: React.ReactNode }) {
189
+ return (
190
+ <SessionProvider>
191
+ <ThemeProvider>
192
+ {children}
193
+ </ThemeProvider>
194
+ </SessionProvider>
195
+ );
196
+ }
197
+ ```
198
+
199
+ Update `app/layout.tsx`:
200
+
201
+ ```typescript
202
+ import { Providers } from './providers';
203
+
204
+ export default function RootLayout({
205
+ children,
206
+ }: {
207
+ children: React.ReactNode;
208
+ }) {
209
+ return (
210
+ <html lang="en">
211
+ <body>
212
+ <Providers>
213
+ {children}
214
+ </Providers>
215
+ </body>
216
+ </html>
217
+ );
218
+ }
219
+ ```
220
+
221
+ ### 5. Add Authentication Pages
222
+
223
+ **Login Page** - `app/account-auth/login/page.tsx`:
224
+
225
+ ```typescript
226
+ 'use client';
227
+
228
+ import LoginPage from '@payez/next-mvp/dist/pages/login';
229
+
230
+ export default function LoginPageWrapper() {
231
+ return <LoginPage />;
232
+ }
233
+ ```
234
+
235
+ **Password Recovery** - `app/account-auth/recovery/page.tsx`:
236
+
237
+ ```typescript
238
+ 'use client';
239
+
240
+ import RecoveryPage from '@payez/next-mvp/dist/pages/recovery';
241
+
242
+ export default function RecoveryPageWrapper() {
243
+ return <RecoveryPage />;
244
+ }
245
+ ```
246
+
247
+ **Verify Code (2FA)** - `app/account-auth/verify-code/page.tsx`:
248
+
249
+ ```typescript
250
+ 'use client';
251
+
252
+ import VerifyCodePage from '@payez/next-mvp/dist/pages/verify-code';
253
+
254
+ export default function VerifyCodePageWrapper() {
255
+ return <VerifyCodePage />;
256
+ }
257
+ ```
258
+
259
+ #### What your app must serve (PAY-2121)
260
+
261
+ The IdP emails links that land on paths your app must host. Two of them are
262
+ conventions the kit mounts for you; wire them or the link 404s at your site:
263
+
264
+ **Invitation / onboarding** - `app/account-auth/onboarding/page.tsx`:
265
+
266
+ ```typescript
267
+ // The IdP's welcome email links to
268
+ // {your site}/account-auth/onboarding?client_id=&onboard_token=
269
+ export { default } from '@payez/next-mvp/pages/onboarding';
270
+ ```
271
+
272
+ and the API it posts to (token-driven, no session) - one mount file each:
273
+
274
+ ```typescript
275
+ // app/api/onboarding/verify-code/route.ts
276
+ export { POST } from '@payez/next-mvp/routes/onboarding/verify-code';
277
+ // app/api/onboarding/send-email-code/route.ts
278
+ export { POST } from '@payez/next-mvp/routes/onboarding/send-email-code';
279
+ // app/api/onboarding/verify-welcome-email/route.ts
280
+ export { POST } from '@payez/next-mvp/routes/onboarding/verify-welcome-email';
281
+ // app/api/onboarding/set-password/route.ts
282
+ export { POST } from '@payez/next-mvp/routes/onboarding/set-password';
283
+ ```
284
+
285
+ **Post-verify reset fragment on `/`** - mount the bridge on your home page:
286
+
287
+ ```typescript
288
+ // app/page.tsx
289
+ import { PasswordResetBridge } from '@payez/next-mvp/components/auth/PasswordResetBridge';
290
+
291
+ export default function Home() {
292
+ return (<><PasswordResetBridge />{/* your home page */}</>);
293
+ }
294
+ ```
295
+
296
+ When the IdP's verification redirect lands on `/#password_reset_required=true&reset_token=โ€ฆ&email=โ€ฆ`
297
+ (a fragment, for a passwordless account), the bridge performs one replace to
298
+ `/account-auth/recovery?token=โ€ฆ&email=โ€ฆ` and clears the hash. With any other
299
+ fragment it renders nothing. `npx @payez/create-next-app` writes all of the above.
300
+
301
+ **Registration** has two doors, and the kit ships neither as a page:
302
+
303
+ - **Owner-initiated invite** (shipped here): an existing owner invites a user; the invite
304
+ email lands on `/account-auth/onboarding` (above), which the kit now serves.
305
+ - **Self-serve sign-up**: the kit exposes the IdP's ProgressiveAuth flow as API endpoints
306
+ (`/api/ProgressiveAuth/step1`..`step5`, then `/api/ProgressiveAuth/verify-email`;
307
+ `API_ENDPOINTS.progressiveAuth` in `config/env.ts`). The kit ships **no** registration
308
+ page, so a developer who wants self-serve sign-up authors a page that drives that flow,
309
+ respecting the tenant's `allow_public_registration` / waitlist state. The login page no
310
+ longer links a register page, because the kit does not ship one.
311
+
312
+ ### 6. Protect Routes with Authentication
313
+
314
+ **Server-side protection:**
315
+
316
+ ```typescript
317
+ import { getServerSession } from 'next-auth';
318
+ import { redirect } from 'next/navigation';
319
+
320
+ export default async function DashboardPage() {
321
+ const session = await getServerSession();
322
+
323
+ if (!session) {
324
+ redirect('/account-auth/login');
325
+ }
326
+
327
+ return (
328
+ <div>
329
+ <h1>Welcome, {session.user?.email}</h1>
330
+ </div>
331
+ );
332
+ }
333
+ ```
334
+
335
+ **Client-side hook:**
336
+
337
+ ```typescript
338
+ 'use client';
339
+
340
+ import { useSession } from 'next-auth/react';
341
+
342
+ export default function ProfilePage() {
343
+ const { data: session, status } = useSession();
344
+
345
+ if (status === 'loading') return <div>Loading...</div>;
346
+ if (status === 'unauthenticated') return <div>Access Denied</div>;
347
+
348
+ return <div>Logged in as {session?.user?.email}</div>;
349
+ }
350
+ ```
351
+
352
+ ---
353
+
354
+ ## Advanced: V2 Middleware-Based Setup
355
+
356
+ For applications requiring middleware-based route protection:
357
+
358
+ ### 1. Configure Public Routes
359
+
360
+ Create `src/lib/auth.ts`:
361
+
362
+ ```typescript
363
+ import { configurePublicRoutes, createAuthOptions } from '@payez/next-mvp';
364
+ import CredentialsProvider from 'next-auth/providers/credentials';
365
+
366
+ // Define routes that do NOT require authentication
367
+ const publicRoutes = [
368
+ '/',
369
+ '/login',
370
+ '/api/health',
371
+ '/api/public/*', // Wildcard example
372
+ ];
373
+
374
+ configurePublicRoutes(publicRoutes);
375
+
376
+ export const authOptions = createAuthOptions({
377
+ credentialsProvider: CredentialsProvider,
378
+ // Additional NextAuthOptions can be passed here
379
+ });
380
+
381
+ export { authOptions as GET, authOptions as POST } from './auth';
382
+ ```
383
+
384
+ ### 2. Setup NextAuth API Route
385
+
386
+ **For Pages Router (`pages/api/auth/[...nextauth].ts`):**
387
+
388
+ ```typescript
389
+ import NextAuth from 'next-auth';
390
+ import { authOptions } from '../../../src/lib/auth';
391
+
392
+ export default NextAuth(authOptions);
393
+ ```
394
+
395
+ **For App Router (`app/api/auth/[...nextauth]/route.ts`):**
396
+
397
+ ```typescript
398
+ export { GET, POST } from '../../../src/lib/auth';
399
+ ```
400
+
401
+ ### 3. Implement Middleware
402
+
403
+ Create `middleware.ts` at project root:
404
+
405
+ ```typescript
406
+ import { createMvpMiddleware } from '@payez/next-mvp';
407
+
408
+ export default createMvpMiddleware();
409
+
410
+ export const config = {
411
+ matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
412
+ };
413
+ ```
414
+
415
+ ### 4. Use `fetchWithAuth` for Protected API Calls
416
+
417
+ ```typescript
418
+ import { fetchWithAuth } from '@payez/next-mvp';
419
+
420
+ async function fetchData() {
421
+ try {
422
+ const response = await fetchWithAuth('/api/protected-data');
423
+ const data = await response.json();
424
+ console.log(data);
425
+ } catch (error) {
426
+ console.error('Failed to fetch protected data:', error);
427
+ }
428
+ }
429
+ ```
430
+
431
+ ### 5. Session Viability API Handler
432
+
433
+ **For Pages Router (`pages/api/session/viability.ts`):**
434
+
435
+ ```typescript
436
+ import viabilityHandler from '@payez/next-mvp/api-handlers/session/viability';
437
+
438
+ export default viabilityHandler;
439
+ ```
440
+
441
+ **For App Router (`app/api/session/viability/route.ts`):**
442
+
443
+ ```typescript
444
+ export { default as GET } from '@payez/next-mvp/api-handlers/session/viability';
445
+ ```
446
+
447
+ ---
448
+
449
+ ## Custom Theming
450
+
451
+ Customize branding and colors:
452
+
453
+ ```typescript
454
+ // lib/mvp-theme-config.ts
455
+ import { ThemeConfig } from '@payez/next-mvp/theme';
456
+
457
+ const customTheme: ThemeConfig = {
458
+ branding: {
459
+ companyName: "Your Company",
460
+ logoUrl: "/logo.svg",
461
+ logoAlt: "Your Company Logo"
462
+ },
463
+ colors: {
464
+ primary: "#3b82f6", // Blue
465
+ primaryHover: "#2563eb",
466
+ secondary: "#10b981", // Green
467
+ danger: "#ef4444", // Red
468
+ text: "#1f2937",
469
+ textLight: "#6b7280",
470
+ background: "#ffffff",
471
+ backgroundAlt: "#f9fafb",
472
+ border: "#e5e7eb"
473
+ },
474
+ layout: {
475
+ maxWidth: "28rem", // max-w-md
476
+ padding: "1.5rem", // p-6
477
+ borderRadius: "0.5rem" // rounded-lg
478
+ }
479
+ };
480
+
481
+ export default customTheme;
482
+ ```
483
+
484
+ Then use in your Providers:
485
+
486
+ ```typescript
487
+ import customTheme from '@/lib/mvp-theme-config';
488
+
489
+ export function Providers({ children }: { children: React.ReactNode }) {
490
+ return (
491
+ <SessionProvider>
492
+ <ThemeProvider theme={customTheme}>
493
+ {children}
494
+ </ThemeProvider>
495
+ </SessionProvider>
496
+ );
497
+ }
498
+ ```
499
+
500
+ ---
501
+
502
+ ## API Routes
503
+
504
+ Access pre-built API handlers:
505
+
506
+ ```typescript
507
+ // Session validation
508
+ import { GET as validateSession } from '@payez/next-mvp/routes/auth/session';
509
+
510
+ // Token refresh
511
+ import { POST as refreshToken } from '@payez/next-mvp/routes/auth/refresh';
512
+
513
+ // Logout
514
+ import { POST as logout } from '@payez/next-mvp/routes/auth/logout';
515
+ ```
516
+
517
+ ---
518
+
519
+ ## Environment Variables Reference
520
+
521
+ | Variable | Required | Description |
522
+ |----------|----------|-------------|
523
+ | `CLIENT_ID` | โœ… Yes | Your PayEz IDP client ID (string slug, e.g., `payez_idp_admin_web`) |
524
+ | `IDP_URL` | โœ… Yes | PayEz IDP base URL (e.g., `https://idp.payez.net` or `http://localhost:32785`) |
525
+ | `AUTH_TRUST_HOST` | โœ… Yes | Must be `true` - NextAuth derives OAuth URLs from request headers |
526
+ | `NEXTAUTH_SECRET` | ๐Ÿ”„ Broker | **Do NOT set** - fetched automatically from IDP at startup (see below) |
527
+ | `CLIENT_SECRET` | โš ๏ธ Legacy | Not needed with broker mode - IDP handles signing |
528
+ | `NEXT_PUBLIC_IDP_BASE_URL` | โš ๏ธ Optional | Public-facing IDP URL (for client-side redirects) |
529
+ | `REDIS_URL` | โš ๏ธ Optional | Redis connection string for session storage |
530
+
531
+ ### NEXTAUTH_SECRET Broker Flow
532
+
533
+ **The MVP uses a "broker" pattern for NEXTAUTH_SECRET** - the IDP securely provides it at startup rather than storing it in env files.
534
+
535
+ ```
536
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
537
+ โ”‚ App Startup (instrumentation.ts โ†’ ensureInitialized) โ”‚
538
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
539
+ โ”‚
540
+ โ–ผ
541
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
542
+ โ”‚ Is NEXTAUTH_SECRET set and non-empty? โ”‚
543
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
544
+ โ”‚ โ”‚
545
+ YES NO (recommended)
546
+ โ”‚ โ”‚
547
+ โ–ผ โ–ผ
548
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
549
+ โ”‚ Use as-is โ”‚ โ”‚ Fetch from IDP (Broker Mode) โ”‚
550
+ โ”‚ (override) โ”‚ โ”‚ 1. Sign client assertion โ”‚
551
+ โ”‚ โ”‚ โ”‚ 2. POST to /next-auth/secret โ”‚
552
+ โ”‚ โ”‚ โ”‚ 3. Set process.env at runtime โ”‚
553
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
554
+ ```
555
+
556
+ **Key points:**
557
+ - **Do NOT set `NEXTAUTH_SECRET` in `.env` files** - leave it undefined
558
+ - The IDP provides the secret securely at startup via client assertion
559
+ - Secret is cached for 5 minutes, then re-fetched if needed
560
+ - If you DO set it manually, that value takes precedence (useful for overrides)
561
+ - The broker needs `CLIENT_ID` and `IDP_URL` to fetch the secret
562
+
563
+ ---
564
+
565
+ ## Troubleshooting
566
+
567
+ ### SessionProvider Error
568
+
569
+ If you see `useSession must be wrapped in a <SessionProvider />`:
570
+
571
+ 1. Ensure `transpilePackages: ['@payez/next-mvp']` is in `next.config.ts`
572
+ 2. Make sure all page components using PayEz components have `'use client'` directive
573
+ 3. Verify your app is wrapped with `<Providers>` in `layout.tsx`
574
+
575
+ ### Module Resolution Errors
576
+
577
+ If you get `Module not found` errors:
578
+
579
+ 1. Clear Next.js cache: `rm -rf .next`
580
+ 2. Reinstall dependencies: `npm install`
581
+ 3. Restart dev server
582
+
583
+ ### Authentication Not Working
584
+
585
+ 1. Verify `CLIENT_ID` and `IDP_URL` are set correctly
586
+ 2. Check `CLIENT_ID` matches your PayEz IDP configuration (use the slug, not numeric ID)
587
+ 3. Verify IDP is running and reachable at `IDP_URL`
588
+ 4. Check server logs for broker startup messages - look for "NEXTAUTH_SECRET Successfully Fetched from IDP"
589
+ 5. If secret fetch fails, check IDP logs for client assertion errors
590
+ 6. Check browser console for error messages
591
+
592
+ ### NEXTAUTH_SECRET Issues
593
+
594
+ **"NEXTAUTH_SECRET not available" error:**
595
+ - This means the broker couldn't fetch the secret from IDP
596
+ - Check that `IDP_URL` is correct and IDP is running
597
+ - Verify `CLIENT_ID` is registered in the IDP
598
+ - Check network connectivity between your app and IDP
599
+
600
+ **Cookie cross-contamination (localhost development):**
601
+ - If running multiple apps on localhost (different ports), NextAuth cookies can conflict
602
+ - Clear `next-auth.*` cookies in browser, or use incognito
603
+ - Each app uses a unique cookie name based on CLIENT_ID to avoid conflicts
604
+
605
+ ---
606
+
607
+ ## Docker/CI Deployment (IMPORTANT)
608
+
609
+ When consuming `@payez/next-mvp` via a local `.tgz` file in Docker builds, you **must** use a local path reference.
610
+
611
+ ### The Problem
612
+
613
+ If your `package.json` references the MVP like this:
614
+ ```json
615
+ "@payez/next-mvp": "file:../PayEz-Next-MVP/packages/next-mvp/payez-next-mvp-2.6.50.tgz"
616
+ ```
617
+
618
+ Docker builds will **fail** with:
619
+ ```
620
+ npm error ENOENT: no such file or directory, open '/PayEz-Next-MVP/packages/next-mvp/payez-next-mvp-2.6.50.tgz'
621
+ ```
622
+
623
+ The relative path `../` resolves incorrectly inside the Docker container's `/app` working directory.
624
+
625
+ ### The Fix
626
+
627
+ 1. **Copy the `.tgz` file into your project root:**
628
+ ```bash
629
+ cp ../PayEz-Next-MVP/packages/next-mvp/payez-next-mvp-*.tgz ./
630
+ ```
631
+
632
+ 2. **Update `package.json` to use a local reference:**
633
+ ```json
634
+ "@payez/next-mvp": "file:./payez-next-mvp-2.6.50.tgz"
635
+ ```
636
+
637
+ 3. **Run `npm install` to update `package-lock.json`**
638
+
639
+ 4. **Ensure your Dockerfile copies the tgz:**
640
+ ```dockerfile
641
+ COPY payez-next-mvp-*.tgz ./
642
+ ```
643
+
644
+ ### Quick Fix Script
645
+
646
+ Run this in your consuming project to fix the path:
647
+ ```bash
648
+ # Copy latest tgz
649
+ cp ../PayEz-Next-MVP/packages/next-mvp/payez-next-mvp-*.tgz ./
650
+
651
+ # Update package.json path (adjust version as needed)
652
+ sed -i 's|file:../PayEz-Next-MVP/packages/next-mvp/|file:./|g' package.json
653
+
654
+ # Regenerate lockfile
655
+ npm install --legacy-peer-deps
656
+ ```
657
+
658
+ ### After MVP Version Updates
659
+
660
+ When you update the MVP package version, repeat steps 1-3 to copy the new `.tgz` and update references.
661
+
662
+ ---
663
+
664
+ ## Pre-Publishing Checklist (For Package Maintainers)
665
+
666
+ Before publishing this package to npm:
667
+
668
+ ### โœ… Code Quality
669
+ - [x] All `@/` path aliases converted to relative paths
670
+ - [x] TypeScript compiles without errors: `npm run build`
671
+ - [x] No hardcoded configuration values (use env variables)
672
+ - [ ] Unit tests pass (if implemented)
673
+
674
+ ### ๐Ÿ“ฆ Package Configuration
675
+
676
+ **CRITICAL FIXES NEEDED:**
677
+
678
+ 1. **Fix `main` field in package.json (Line 5):**
679
+ ```json
680
+ "main": "dist/index.js", // NOT "src/index.ts"
681
+ ```
682
+
683
+ 2. **Remove unused `tsc-alias` from devDependencies (Line 542):**
684
+ ```json
685
+ // DELETE this line:
686
+ "tsc-alias": "^1.8.16"
687
+ ```
688
+
689
+ 3. **Add package metadata:**
690
+ ```json
691
+ {
692
+ "description": "PayEz IDP authentication package for Next.js with ready-to-use login, recovery, and profile pages",
693
+ "keywords": ["nextjs", "authentication", "next-auth", "payez", "idp", "oauth"],
694
+ "author": "PayEz Team",
695
+ "license": "MIT",
696
+ "repository": {
697
+ "type": "git",
698
+ "url": "https://github.com/your-org/PayEz-Next-MVP"
699
+ },
700
+ "homepage": "https://github.com/your-org/PayEz-Next-MVP#readme",
701
+ "bugs": {
702
+ "url": "https://github.com/your-org/PayEz-Next-MVP/issues"
703
+ }
704
+ }
705
+ ```
706
+
707
+ ### ๐Ÿ“ Documentation
708
+ - [x] README.md is complete and accurate
709
+ - [ ] CHANGELOG.md exists with version history
710
+ - [ ] LICENSE file exists
711
+
712
+ ### ๐Ÿงช Testing
713
+ - [ ] Test fresh installation in new Next.js 14 project
714
+ - [ ] Test fresh installation in new Next.js 15 project
715
+ - [ ] Verify all exported modules work
716
+ - [ ] Test with React 18 and React 19
717
+ - [ ] Test package build: `npm pack --dry-run`
718
+
719
+ ### ๐Ÿš€ Publishing Steps
720
+
721
+ ```bash
722
+ # 1. Fix package.json issues (see above)
723
+
724
+ # 2. Login to npm
725
+ npm login
726
+
727
+ # 3. Build package
728
+ npm run build
729
+
730
+ # 4. Preview what will be published
731
+ npm pack --dry-run
732
+
733
+ # 5. Test the tarball locally
734
+ npm install ./payez-next-mvp-2.3.1.tgz
735
+
736
+ # 6. Bump version (patch/minor/major)
737
+ npm version patch # 2.3.1 -> 2.3.2
738
+ npm version minor # 2.3.1 -> 2.4.0
739
+ npm version major # 2.3.1 -> 3.0.0
740
+
741
+ # 7. Publish to npm
742
+ npm publish
743
+
744
+ # 8. Create git tag and push
745
+ git push origin main
746
+ git push origin --tags
747
+ ```
748
+
749
+ ### ๐Ÿ“‹ .npmignore
750
+
751
+ Create `.npmignore` to exclude unnecessary files:
752
+
753
+ ```
754
+ src/
755
+ *.test.ts
756
+ *.test.tsx
757
+ tsconfig.json
758
+ .gitignore
759
+ .git
760
+ node_modules/
761
+ *.tgz
762
+ .env*
763
+ ```
764
+
765
+ ### ๐Ÿ”’ Publish Configuration
766
+
767
+ Add to package.json:
768
+
769
+ ```json
770
+ "publishConfig": {
771
+ "access": "public",
772
+ "registry": "https://registry.npmjs.org/"
773
+ }
774
+ ```
775
+
776
+ ---
777
+
778
+ ## ๐Ÿ“š Complete Documentation
779
+
780
+ ### Core Guides
781
+
782
+ - **[THEMING.md](./docs/THEMING.md)** - Complete guide to customizing auth components
783
+ - Theme structure and configuration
784
+ - Creating light/dark modes
785
+ - Component-specific customization
786
+ - Common theming issues and solutions
787
+
788
+ - **[CSS_VARIABLES_INTEGRATION.md](./docs/CSS_VARIABLES_INTEGRATION.md)** - CSS variable injection for MVP components
789
+ - Why CSS variables are needed
790
+ - How to inject variables in your app
791
+ - Color conversion utilities
792
+ - Debugging CSS variable issues
793
+
794
+ - **[THEME_EXAMPLES.md](./docs/THEME_EXAMPLES.md)** - Ready-to-use theme examples
795
+ - 7 pre-built professional themes
796
+ - Multi-brand theme support
797
+ - Dynamic light/dark mode
798
+ - Copy-paste theme configurations
799
+
800
+ ### Topics Covered
801
+
802
+ #### Theming
803
+ - โœ… Brand colors and logos
804
+ - โœ… Light and dark modes
805
+ - โœ… Font families and typography
806
+ - โœ… Layout and spacing customization
807
+ - โœ… Component-specific styling
808
+ - โœ… Multi-tenant/white-label setups
809
+ - โœ… Accessibility and contrast
810
+
811
+ #### CSS Variables
812
+ - โœ… Understanding CSS custom properties
813
+ - โœ… Manual variable injection
814
+ - โœ… Color conversion (Tailwind โ†’ hex)
815
+ - โœ… Theme provider pattern
816
+ - โœ… Dynamic theme switching
817
+ - โœ… Debugging in DevTools
818
+
819
+ #### Examples
820
+ - โœ… Corporate themes
821
+ - โœ… SaaS themes
822
+ - โœ… Creative/design themes
823
+ - โœ… Accessible high-contrast themes
824
+ - โœ… Multi-brand configurations
825
+ - โœ… Gradient backgrounds
826
+ - โœ… Custom branding
827
+
828
+ ### Quick Links
829
+
830
+ **Getting Started with Themes:**
831
+ 1. Start with [THEMING.md](./docs/THEMING.md) - Quick Start section
832
+ 2. Copy a theme from [THEME_EXAMPLES.md](./docs/THEME_EXAMPLES.md)
833
+ 3. Follow integration pattern in [CSS_VARIABLES_INTEGRATION.md](./docs/CSS_VARIABLES_INTEGRATION.md)
834
+
835
+ **For Specific Tasks:**
836
+ - Want to change colors? โ†’ [THEMING.md - Creating a Theme](./docs/THEMING.md#creating-a-theme)
837
+ - Pages rendering white/no color? โ†’ [CSS_VARIABLES_INTEGRATION.md - Troubleshooting](./docs/CSS_VARIABLES_INTEGRATION.md#troubleshooting)
838
+ - Need a complete example? โ†’ [THEME_EXAMPLES.md](./docs/THEME_EXAMPLES.md)
839
+ - Debugging styling issues? โ†’ [THEMING.md - Common Issues](./docs/THEMING.md#common-issues--solutions)
840
+
841
+ ---
842
+
843
+ ## License
844
+
845
+ MIT
846
+
847
+ ## Support
848
+
849
+ For issues and questions:
850
+ - GitHub Issues: https://github.com/your-org/PayEz-Next-MVP/issues
851
+ - Documentation: https://docs.payez.net
852
+
853
+ ## Contributing
854
+
855
+ Contributions welcome! Please read our contributing guidelines first.
856
+
857
+ ---
858
+
859
+ Made with โค๏ธ by the PayEz Team