@payez/next-mvp 4.0.4 → 4.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -18
- package/dist/auth/better-auth.d.ts +9 -0
- package/dist/auth/better-auth.js +18 -2
- package/dist/server/auth.d.ts +9 -0
- package/package.json +5 -1
- package/src/auth/better-auth.ts +21 -2
package/README.md
CHANGED
|
@@ -1,30 +1,40 @@
|
|
|
1
1
|
# @payez/next-mvp
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Drop-in authentication for Next.js. One package, zero secret management in production.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
```bash
|
|
6
|
+
npm install @payez/next-mvp next-auth
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## How Secrets Work
|
|
10
|
+
|
|
11
|
+
You never manage signing keys or OAuth credentials directly. The package resolves them automatically at startup based on your environment.
|
|
6
12
|
|
|
7
|
-
|
|
8
|
-
|
|
13
|
+
| Environment | How it works | Secrets in your config? |
|
|
14
|
+
|-------------|-------------|------------------------|
|
|
15
|
+
| **Dev** | App calls IDP broker on your private network. One API key in `.env.local`. | One key (rotatable via CLI) |
|
|
16
|
+
| **Production** | App calls a cluster-internal endpoint. Network boundary = identity. | None |
|
|
17
|
+
| **Enterprise** | App uses an issued license key against your own or our IDP. | One key (rotatable via CLI) |
|
|
9
18
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
19
|
+
**In production, there are no secrets to configure, rotate, or leak.** The app proves its identity by being inside the cluster.
|
|
20
|
+
|
|
21
|
+
In dev, you have one key. Rotate it anytime:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npx @payez/cli secret rotate
|
|
25
|
+
```
|
|
13
26
|
|
|
14
|
-
|
|
15
|
-
- Auth-ready v2 handlers with pre-configured routes
|
|
16
|
-
- Redis session management improvements
|
|
17
|
-
- Token refresh optimizations
|
|
27
|
+
Full architecture: [SECRET-MANAGEMENT-ARCHITECTURE.md](../../docs/SECRET-MANAGEMENT-ARCHITECTURE.md)
|
|
18
28
|
|
|
19
29
|
## Features
|
|
20
30
|
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
31
|
+
- **Zero-secret production deployment** — no signing keys, no OAuth secrets in your env
|
|
32
|
+
- **Complete authentication flow** — login, logout, session management, password recovery
|
|
33
|
+
- **Pre-built UI components** — themed login, recovery, and verify-code pages
|
|
34
|
+
- **Automatic token refresh** — built-in refresh token handling with Redis session backing
|
|
35
|
+
- **Google OAuth + 2FA** — pre-configured providers, MFA with email/SMS
|
|
36
|
+
- **Themeable** — branding, colors, and layout via ThemeProvider
|
|
37
|
+
- **Next.js 14/15** — App Router, React Server Components, middleware-ready
|
|
28
38
|
|
|
29
39
|
## Installation
|
|
30
40
|
|
|
@@ -29,6 +29,7 @@ export declare function buildBetterAuthProviders(config: IDPClientConfig): Recor
|
|
|
29
29
|
* Call after getIDPClientConfig() resolves.
|
|
30
30
|
*/
|
|
31
31
|
export declare function createBetterAuthInstance(idpConfig: IDPClientConfig): import("better-auth").Auth<{
|
|
32
|
+
baseURL: string;
|
|
32
33
|
secret: string;
|
|
33
34
|
socialProviders: Record<string, BetterAuthSocialProvider>;
|
|
34
35
|
trustedOrigins: string[];
|
|
@@ -39,6 +40,14 @@ export declare function createBetterAuthInstance(idpConfig: IDPClientConfig): im
|
|
|
39
40
|
refreshCache: true;
|
|
40
41
|
};
|
|
41
42
|
};
|
|
43
|
+
advanced: {
|
|
44
|
+
cookiePrefix: string;
|
|
45
|
+
cookies: {
|
|
46
|
+
session_token: {
|
|
47
|
+
name: string;
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
};
|
|
42
51
|
plugins: [{
|
|
43
52
|
id: "next-cookies";
|
|
44
53
|
hooks: {
|
package/dist/auth/better-auth.js
CHANGED
|
@@ -19,6 +19,7 @@ const better_auth_1 = require("better-auth");
|
|
|
19
19
|
const next_js_1 = require("better-auth/next-js");
|
|
20
20
|
const next_js_2 = require("better-auth/next-js");
|
|
21
21
|
const idp_client_config_1 = require("../lib/idp-client-config");
|
|
22
|
+
const app_slug_1 = require("../lib/app-slug");
|
|
22
23
|
/**
|
|
23
24
|
* Build Better Auth social providers from IDP config.
|
|
24
25
|
*/
|
|
@@ -43,13 +44,19 @@ function buildBetterAuthProviders(config) {
|
|
|
43
44
|
* Call after getIDPClientConfig() resolves.
|
|
44
45
|
*/
|
|
45
46
|
function createBetterAuthInstance(idpConfig) {
|
|
47
|
+
const appSlug = idpConfig.clientSlug || (0, app_slug_1.getAppSlug)();
|
|
48
|
+
// Resolve base URL: BETTER_AUTH_URL env > IDP config > localhost fallback
|
|
49
|
+
const baseURL = process.env.BETTER_AUTH_URL
|
|
50
|
+
|| idpConfig.baseClientUrl
|
|
51
|
+
|| `http://localhost:${process.env.PORT || '3000'}`;
|
|
46
52
|
return (0, better_auth_1.betterAuth)({
|
|
53
|
+
baseURL,
|
|
47
54
|
secret: idpConfig.nextAuthSecret,
|
|
48
55
|
socialProviders: buildBetterAuthProviders(idpConfig),
|
|
49
56
|
// Trust the app's own origin + any configured base URL
|
|
50
57
|
trustedOrigins: [
|
|
51
|
-
|
|
52
|
-
...(
|
|
58
|
+
baseURL,
|
|
59
|
+
...(idpConfig.baseClientUrl && idpConfig.baseClientUrl !== baseURL ? [idpConfig.baseClientUrl] : []),
|
|
53
60
|
'http://localhost:3000',
|
|
54
61
|
'http://localhost:3400',
|
|
55
62
|
'http://localhost:3600',
|
|
@@ -63,6 +70,15 @@ function createBetterAuthInstance(idpConfig) {
|
|
|
63
70
|
refreshCache: true,
|
|
64
71
|
},
|
|
65
72
|
},
|
|
73
|
+
// Cookie prefix must match slim-middleware expectations ({slug}.session-token)
|
|
74
|
+
advanced: {
|
|
75
|
+
cookiePrefix: appSlug,
|
|
76
|
+
cookies: {
|
|
77
|
+
session_token: {
|
|
78
|
+
name: `${appSlug}.session-token`,
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
},
|
|
66
82
|
plugins: [
|
|
67
83
|
(0, next_js_1.nextCookies)(),
|
|
68
84
|
],
|
package/dist/server/auth.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ import 'server-only';
|
|
|
12
12
|
* Get the initialized Better Auth instance (singleton).
|
|
13
13
|
*/
|
|
14
14
|
export declare function getAuthInstance(): Promise<import("better-auth/types").Auth<{
|
|
15
|
+
baseURL: string;
|
|
15
16
|
secret: string;
|
|
16
17
|
socialProviders: Record<string, import("../auth/better-auth").BetterAuthSocialProvider>;
|
|
17
18
|
trustedOrigins: string[];
|
|
@@ -22,6 +23,14 @@ export declare function getAuthInstance(): Promise<import("better-auth/types").A
|
|
|
22
23
|
refreshCache: true;
|
|
23
24
|
};
|
|
24
25
|
};
|
|
26
|
+
advanced: {
|
|
27
|
+
cookiePrefix: string;
|
|
28
|
+
cookies: {
|
|
29
|
+
session_token: {
|
|
30
|
+
name: string;
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
};
|
|
25
34
|
plugins: [{
|
|
26
35
|
id: "next-cookies";
|
|
27
36
|
hooks: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@payez/next-mvp",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.6",
|
|
4
4
|
"sideEffects": false,
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -861,6 +861,7 @@
|
|
|
861
861
|
"dependencies": {
|
|
862
862
|
"@azure/identity": "^4.0.1",
|
|
863
863
|
"@azure/keyvault-secrets": "^4.7.0",
|
|
864
|
+
"@better-auth/memory-adapter": "^1.5.6",
|
|
864
865
|
"@upstash/redis": "^1.35.6",
|
|
865
866
|
"better-auth": "^1.5.6",
|
|
866
867
|
"ioredis": "^5.3.2",
|
|
@@ -872,10 +873,13 @@
|
|
|
872
873
|
"nanoid": "^5.0.7"
|
|
873
874
|
},
|
|
874
875
|
"devDependencies": {
|
|
876
|
+
"@microsoft/signalr": "^8.0.17",
|
|
877
|
+
"@tanstack/react-query": "^5.95.2",
|
|
875
878
|
"@types/jsonwebtoken": "^9.0.6",
|
|
876
879
|
"@types/jwk-to-pem": "^2.0.3",
|
|
877
880
|
"@types/node": "^22.14.0",
|
|
878
881
|
"@types/react": "^19.0.0",
|
|
882
|
+
"lucide-react": "^1.7.0",
|
|
879
883
|
"next": "^16.1.5",
|
|
880
884
|
"tsc-alias": "^1.8.16",
|
|
881
885
|
"typescript": "^5.4.5",
|
package/src/auth/better-auth.ts
CHANGED
|
@@ -15,6 +15,7 @@ import { nextCookies } from 'better-auth/next-js';
|
|
|
15
15
|
import { toNextJsHandler } from 'better-auth/next-js';
|
|
16
16
|
import type { IDPClientConfig } from '../lib/idp-client-config';
|
|
17
17
|
import { getIDPClientConfig } from '../lib/idp-client-config';
|
|
18
|
+
import { getAppSlug } from '../lib/app-slug';
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* Better Auth social provider config shape.
|
|
@@ -53,15 +54,23 @@ export function buildBetterAuthProviders(
|
|
|
53
54
|
* Call after getIDPClientConfig() resolves.
|
|
54
55
|
*/
|
|
55
56
|
export function createBetterAuthInstance(idpConfig: IDPClientConfig) {
|
|
57
|
+
const appSlug = idpConfig.clientSlug || getAppSlug();
|
|
58
|
+
|
|
59
|
+
// Resolve base URL: BETTER_AUTH_URL env > IDP config > localhost fallback
|
|
60
|
+
const baseURL = process.env.BETTER_AUTH_URL
|
|
61
|
+
|| idpConfig.baseClientUrl
|
|
62
|
+
|| `http://localhost:${process.env.PORT || '3000'}`;
|
|
63
|
+
|
|
56
64
|
return betterAuth({
|
|
65
|
+
baseURL,
|
|
57
66
|
secret: idpConfig.nextAuthSecret as string,
|
|
58
67
|
|
|
59
68
|
socialProviders: buildBetterAuthProviders(idpConfig),
|
|
60
69
|
|
|
61
70
|
// Trust the app's own origin + any configured base URL
|
|
62
71
|
trustedOrigins: [
|
|
63
|
-
|
|
64
|
-
...(
|
|
72
|
+
baseURL,
|
|
73
|
+
...(idpConfig.baseClientUrl && idpConfig.baseClientUrl !== baseURL ? [idpConfig.baseClientUrl] : []),
|
|
65
74
|
'http://localhost:3000',
|
|
66
75
|
'http://localhost:3400',
|
|
67
76
|
'http://localhost:3600',
|
|
@@ -77,6 +86,16 @@ export function createBetterAuthInstance(idpConfig: IDPClientConfig) {
|
|
|
77
86
|
},
|
|
78
87
|
},
|
|
79
88
|
|
|
89
|
+
// Cookie prefix must match slim-middleware expectations ({slug}.session-token)
|
|
90
|
+
advanced: {
|
|
91
|
+
cookiePrefix: appSlug,
|
|
92
|
+
cookies: {
|
|
93
|
+
session_token: {
|
|
94
|
+
name: `${appSlug}.session-token`,
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
|
|
80
99
|
plugins: [
|
|
81
100
|
nextCookies(),
|
|
82
101
|
],
|