@payez/next-mvp 4.1.11 → 4.1.20
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/dist/api-handlers/account/profile.d.ts +38 -0
- package/dist/api-handlers/account/profile.js +73 -45
- package/dist/api-handlers/account/recovery/send-code.d.ts +33 -0
- package/dist/api-handlers/account/recovery/send-code.js +52 -18
- package/dist/api-handlers/account/recovery/verify-code.d.ts +33 -0
- package/dist/api-handlers/account/recovery/verify-code.js +52 -18
- package/dist/api-handlers/account/verify-email.js +15 -1
- package/dist/api-handlers/account/verify-sms.js +15 -1
- package/dist/api-handlers/auth/passkey-signin.d.ts +29 -0
- package/dist/api-handlers/auth/passkey-signin.js +97 -0
- package/dist/api-handlers/mfa/backup-code-verify.d.ts +73 -0
- package/dist/api-handlers/mfa/backup-code-verify.js +153 -0
- package/dist/api-handlers/mfa/backup-codes.d.ts +7 -0
- package/dist/api-handlers/mfa/backup-codes.js +40 -0
- package/dist/api-handlers/mfa/methods.d.ts +3 -0
- package/dist/api-handlers/mfa/methods.js +41 -0
- package/dist/api-handlers/mfa/totp-confirm.d.ts +8 -0
- package/dist/api-handlers/mfa/totp-confirm.js +41 -0
- package/dist/api-handlers/mfa/totp-enroll.d.ts +8 -0
- package/dist/api-handlers/mfa/totp-enroll.js +41 -0
- package/dist/api-handlers/mfa/totp-verify.d.ts +47 -0
- package/dist/api-handlers/mfa/totp-verify.js +134 -0
- package/dist/api-handlers/passkeys/list.d.ts +7 -0
- package/dist/api-handlers/passkeys/list.js +29 -0
- package/dist/api-handlers/passkeys/manage.d.ts +3 -0
- package/dist/api-handlers/passkeys/manage.js +54 -0
- package/dist/api-handlers/passkeys/register-options.d.ts +8 -0
- package/dist/api-handlers/passkeys/register-options.js +41 -0
- package/dist/api-handlers/passkeys/register-verify.d.ts +7 -0
- package/dist/api-handlers/passkeys/register-verify.js +40 -0
- package/dist/api-handlers/session/viability.js +19 -0
- package/dist/auth/better-auth.d.ts +68 -5
- package/dist/auth/better-auth.js +256 -42
- package/dist/auth/utils/idp-client.d.ts +13 -22
- package/dist/auth/utils/idp-client.js +12 -82
- package/dist/client/better-auth-client.d.ts +14 -2
- package/dist/lib/session-store.js +28 -21
- package/dist/lib/startup-init.js +19 -19
- package/dist/lib/token-lifecycle.js +40 -4
- package/dist/models/SessionModel.d.ts +17 -0
- package/dist/pages/login/page.d.ts +10 -1
- package/dist/pages/login/page.js +69 -80
- package/dist/pages/verify-code/page.d.ts +10 -1
- package/dist/pages/verify-code/page.js +72 -4
- package/dist/routes/auth/passkey-signin.d.ts +13 -0
- package/dist/routes/auth/passkey-signin.js +18 -0
- package/dist/routes/auth/viability.d.ts +2 -0
- package/dist/routes/auth/viability.js +88 -0
- package/dist/routes/mfa/backup-code-verify.d.ts +1 -0
- package/dist/routes/mfa/backup-code-verify.js +5 -0
- package/dist/routes/mfa/backup-codes.d.ts +10 -0
- package/dist/routes/mfa/backup-codes.js +14 -0
- package/dist/routes/mfa/methods.d.ts +21 -0
- package/dist/routes/mfa/methods.js +10 -0
- package/dist/routes/mfa/totp-confirm.d.ts +10 -0
- package/dist/routes/mfa/totp-confirm.js +14 -0
- package/dist/routes/mfa/totp-enroll.d.ts +10 -0
- package/dist/routes/mfa/totp-enroll.js +14 -0
- package/dist/routes/mfa/totp-verify.d.ts +14 -0
- package/dist/routes/mfa/totp-verify.js +18 -0
- package/dist/routes/passkeys/list.d.ts +10 -0
- package/dist/routes/passkeys/list.js +14 -0
- package/dist/routes/passkeys/manage.d.ts +18 -0
- package/dist/routes/passkeys/manage.js +13 -0
- package/dist/routes/passkeys/register-options.d.ts +10 -0
- package/dist/routes/passkeys/register-options.js +14 -0
- package/dist/routes/passkeys/register-verify.d.ts +10 -0
- package/dist/routes/passkeys/register-verify.js +14 -0
- package/dist/server/auth.d.ts +2 -2
- package/dist/server/decode-session.js +37 -3
- package/package.json +958 -893
- package/scripts/check-internal-url-usage.sh +73 -73
- package/src/api/index.ts +17 -17
- package/src/api-handlers/account/masked-info.ts +45 -45
- package/src/api-handlers/account/profile.ts +99 -80
- package/src/api-handlers/account/recovery/initiate.ts +23 -23
- package/src/api-handlers/account/recovery/send-code.ts +73 -25
- package/src/api-handlers/account/recovery/verify-code.ts +73 -25
- package/src/api-handlers/account/reset-password.ts +23 -23
- package/src/api-handlers/account/send-code.ts +76 -76
- package/src/api-handlers/account/validate-password.ts +118 -118
- package/src/api-handlers/account/verify-email.ts +15 -1
- package/src/api-handlers/account/verify-sms.ts +15 -1
- package/src/api-handlers/admin/stats.ts +249 -249
- package/src/api-handlers/anon/preferences.ts +123 -123
- package/src/api-handlers/auth/jwks.ts +20 -20
- package/src/api-handlers/auth/login.ts +240 -240
- package/src/api-handlers/auth/passkey-signin.ts +98 -0
- package/src/api-handlers/auth/validate.ts +43 -43
- package/src/api-handlers/mfa/backup-code-verify.ts +175 -0
- package/src/api-handlers/mfa/backup-codes.ts +41 -0
- package/src/api-handlers/mfa/methods.ts +46 -0
- package/src/api-handlers/mfa/totp-confirm.ts +42 -0
- package/src/api-handlers/mfa/totp-enroll.ts +42 -0
- package/src/api-handlers/mfa/totp-verify.ts +156 -0
- package/src/api-handlers/passkeys/list.ts +31 -0
- package/src/api-handlers/passkeys/manage.ts +54 -0
- package/src/api-handlers/passkeys/register-options.ts +42 -0
- package/src/api-handlers/passkeys/register-verify.ts +41 -0
- package/src/api-handlers/session/viability.ts +161 -142
- package/src/auth/better-auth.ts +247 -6
- package/src/auth/unauthenticated-routes.ts +2 -2
- package/src/auth/utils/idp-client.ts +13 -95
- package/src/client/better-auth-client.ts +70 -70
- package/src/client/fetchWithSession.ts +21 -21
- package/src/client/index.ts +13 -13
- package/src/client/useAnonSession.ts +131 -131
- package/src/components/admin/VibeAdminContext.tsx +87 -87
- package/src/config/logging-config.ts +82 -82
- package/src/config/unauthenticated-routes.ts +19 -19
- package/src/edge/internal-api-url.ts +65 -65
- package/src/edge/middleware.ts +42 -42
- package/src/hooks/useProfile.ts +75 -75
- package/src/lib/anon-session.ts +213 -213
- package/src/lib/auth-secret.ts +137 -137
- package/src/lib/demo-mode.ts +17 -17
- package/src/lib/idp-client-config.ts +559 -559
- package/src/lib/idp-fetch.ts +126 -126
- package/src/lib/internal-api.ts +171 -171
- package/src/lib/jwt-decode-client.ts +45 -45
- package/src/lib/rate-limit-service.ts +9 -9
- package/src/lib/redis.ts +26 -26
- package/src/lib/refresh-token-validator.ts +64 -64
- package/src/lib/secret-validation.ts +8 -8
- package/src/lib/session-store.ts +702 -695
- package/src/lib/session.ts +34 -34
- package/src/lib/startup-init.ts +251 -251
- package/src/lib/token-expiry.ts +40 -40
- package/src/lib/token-lifecycle.ts +533 -497
- package/src/lib/types/api-responses.ts +336 -336
- package/src/middleware/auth-decision.ts +43 -43
- package/src/models/DecodedAccessToken.ts +16 -16
- package/src/models/SessionModel.ts +282 -264
- package/src/pages/admin-roles/index.ts +9 -9
- package/src/pages/login/page.tsx +123 -228
- package/src/pages/security/EnhancedSecurityPage.tsx +9 -9
- package/src/pages/verify-code/page.tsx +71 -5
- package/src/routes/account/index.ts +31 -31
- package/src/routes/account/masked-info.ts +36 -36
- package/src/routes/account/send-code.ts +39 -39
- package/src/routes/account/verify-email.ts +40 -40
- package/src/routes/account/verify-sms.ts +40 -40
- package/src/routes/auth/index.ts +22 -22
- package/src/routes/auth/passkey-signin.ts +13 -0
- package/src/routes/auth/refresh.ts +48 -48
- package/src/routes/auth/session.ts +166 -166
- package/src/routes/auth/viability.ts +89 -0
- package/src/routes/index.ts +17 -17
- package/src/routes/mfa/backup-code-verify.ts +1 -0
- package/src/routes/mfa/backup-codes.ts +10 -0
- package/src/routes/mfa/methods.ts +22 -0
- package/src/routes/mfa/totp-confirm.ts +10 -0
- package/src/routes/mfa/totp-enroll.ts +10 -0
- package/src/routes/mfa/totp-verify.ts +14 -0
- package/src/routes/passkeys/list.ts +10 -0
- package/src/routes/passkeys/manage.ts +23 -0
- package/src/routes/passkeys/register-options.ts +10 -0
- package/src/routes/passkeys/register-verify.ts +10 -0
- package/src/routes/session/index.ts +7 -7
- package/src/routes/session/refresh-viability.ts +17 -17
- package/src/server/auth.ts +373 -373
- package/src/server/decode-session.ts +235 -202
- package/src/services/signalrActivityService.ts +258 -258
- package/src/theme/ThemeProvider.tsx +39 -39
- package/src/theme/default.ts +33 -33
- package/src/theme/index.ts +31 -31
- package/src/theme/types.ts +69 -69
- package/src/theme/useTheme.ts +57 -57
- package/src/theme/utils.ts +40 -40
- package/src/types/api.ts +12 -12
- package/src/types/auth.d.ts +23 -23
- package/src/types/auth.ts +22 -22
- package/src/types/logging.ts +11 -11
- package/src/types/recovery.ts +54 -54
- package/src/utils/api.ts +353 -353
- package/src/utils/circuitBreaker.ts +40 -40
- package/src/utils/error-message.ts +108 -108
- package/src/utils/layout/reservedSpace.ts +124 -124
package/src/lib/auth-secret.ts
CHANGED
|
@@ -1,137 +1,137 @@
|
|
|
1
|
-
import 'server-only';
|
|
2
|
-
import { validateAuthSecret } from './secret-validation';
|
|
3
|
-
import { randomUUID } from 'crypto';
|
|
4
|
-
|
|
5
|
-
let cachedSecret: string | null = null;
|
|
6
|
-
let lastFetchedAt = 0;
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Resolve the Better Auth signing secret (server-only).
|
|
10
|
-
*
|
|
11
|
-
* Priority:
|
|
12
|
-
* 1) Use process.env.BETTER_AUTH_SECRET (preferred) or NEXTAUTH_SECRET (legacy)
|
|
13
|
-
* if present — allows overrides/production via env.
|
|
14
|
-
* 2) Fetch from IDP broker endpoint — IDP handles all Key Vault/signing.
|
|
15
|
-
* 3) Cache result in-memory and set process.env.BETTER_AUTH_SECRET for
|
|
16
|
-
* subsequent calls.
|
|
17
|
-
*
|
|
18
|
-
* NOTE on naming: this secret is the cryptographic key Better Auth uses to
|
|
19
|
-
* sign session JWTs. The IDP backend still names the broker endpoint and
|
|
20
|
-
* response field with the legacy "next-auth" / "nextAuthSecret" names; we
|
|
21
|
-
* read both new and legacy on the wire during the migration window.
|
|
22
|
-
*/
|
|
23
|
-
export async function resolveAuthSecret(): Promise<string> {
|
|
24
|
-
// Check if already in environment (prefer new name, fall back to legacy)
|
|
25
|
-
const envSecret =
|
|
26
|
-
(process.env.BETTER_AUTH_SECRET && process.env.BETTER_AUTH_SECRET.trim() !== ''
|
|
27
|
-
? process.env.BETTER_AUTH_SECRET
|
|
28
|
-
: undefined) ||
|
|
29
|
-
(process.env.NEXTAUTH_SECRET && process.env.NEXTAUTH_SECRET.trim() !== ''
|
|
30
|
-
? process.env.NEXTAUTH_SECRET
|
|
31
|
-
: undefined);
|
|
32
|
-
if (envSecret) {
|
|
33
|
-
// Silent - already configured
|
|
34
|
-
return envSecret;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Check if cached and fresh (within 5 minutes)
|
|
38
|
-
if (cachedSecret && Date.now() - lastFetchedAt < 5 * 60 * 1000) {
|
|
39
|
-
return cachedSecret;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Broker mode: fetch from IDP (IDP handles all Key Vault/signing)
|
|
43
|
-
const base = process.env.IDP_URL;
|
|
44
|
-
if (!base) throw new Error('IDP_URL environment variable is required');
|
|
45
|
-
|
|
46
|
-
const clientIdStr = process.env.CLIENT_ID;
|
|
47
|
-
if (!clientIdStr || clientIdStr.trim() === '') throw new Error('CLIENT_ID is required (e.g., "ideal_resume_website")');
|
|
48
|
-
|
|
49
|
-
// Step 1: Request IDP to sign a client assertion (IDP has the keys, not us)
|
|
50
|
-
|
|
51
|
-
const signingUrl = new URL(`${base.replace(/\/$/, '')}/api/ExternalAuth/sign-client-assertion`);
|
|
52
|
-
|
|
53
|
-
const signingPayload = {
|
|
54
|
-
issuer: clientIdStr,
|
|
55
|
-
subject: clientIdStr,
|
|
56
|
-
audience: 'urn:payez:externalauth:nextauthsecret',
|
|
57
|
-
expires_in: 60,
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
const signingResp = await fetch(signingUrl.toString(), {
|
|
61
|
-
method: 'POST',
|
|
62
|
-
headers: {
|
|
63
|
-
'Accept': 'application/json',
|
|
64
|
-
'Content-Type': 'application/json',
|
|
65
|
-
'X-Client-Id': clientIdStr,
|
|
66
|
-
'X-Correlation-Id': randomUUID().replace(/-/g, ''),
|
|
67
|
-
},
|
|
68
|
-
body: JSON.stringify(signingPayload),
|
|
69
|
-
cache: 'no-store'
|
|
70
|
-
} as RequestInit);
|
|
71
|
-
|
|
72
|
-
if (!signingResp.ok) {
|
|
73
|
-
const txt = await signingResp.text().catch(() => 'Unknown error');
|
|
74
|
-
throw new Error(`Failed to sign client assertion: ${signingResp.status} ${signingResp.statusText} - ${txt}`);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const signingBody: any = await signingResp.json().catch(() => ({}));
|
|
78
|
-
const client_assertion = (
|
|
79
|
-
signingBody?.data?.client_assertion ??
|
|
80
|
-
signingBody?.data?.clientAssertion ??
|
|
81
|
-
signingBody?.client_assertion ??
|
|
82
|
-
signingBody?.clientAssertion ??
|
|
83
|
-
signingBody?.data?.ClientAssertion ??
|
|
84
|
-
signingBody?.ClientAssertion
|
|
85
|
-
) as string | undefined;
|
|
86
|
-
|
|
87
|
-
if (!client_assertion || typeof client_assertion !== 'string') {
|
|
88
|
-
throw new Error('IDP did not return a valid signed client assertion');
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// Step 2: Use the signed assertion to fetch the auth secret
|
|
92
|
-
// (Endpoint is still served at /next-auth/secret on the IDP — legacy path.)
|
|
93
|
-
|
|
94
|
-
const proxyUrl = new URL(`${base.replace(/\/$/, '')}/api/ExternalAuth/next-auth/secret`);
|
|
95
|
-
|
|
96
|
-
const proxyResp = await fetch(proxyUrl.toString(), {
|
|
97
|
-
method: 'POST',
|
|
98
|
-
headers: {
|
|
99
|
-
'Accept': 'application/json',
|
|
100
|
-
'Content-Type': 'application/json',
|
|
101
|
-
'X-Client-Id': clientIdStr,
|
|
102
|
-
'X-Correlation-Id': randomUUID().replace(/-/g, ''),
|
|
103
|
-
},
|
|
104
|
-
body: JSON.stringify({ client_assertion }),
|
|
105
|
-
cache: 'no-store'
|
|
106
|
-
} as RequestInit);
|
|
107
|
-
|
|
108
|
-
if (!proxyResp.ok) {
|
|
109
|
-
const txt = await proxyResp.text().catch(() => 'Unknown error');
|
|
110
|
-
throw new Error(`Proxy error: ${proxyResp.status} ${proxyResp.statusText} - ${txt}`);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const proxyBody: any = await proxyResp.json().catch(() => ({}));
|
|
114
|
-
|
|
115
|
-
const secret = (proxyBody?.data?.secret ?? proxyBody?.secret) as string | undefined;
|
|
116
|
-
// Configuration is available but we don't log it verbosely
|
|
117
|
-
|
|
118
|
-
if (!secret || typeof secret !== 'string') {
|
|
119
|
-
throw new Error('Proxy did not return a valid auth secret');
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
const validation = validateAuthSecret(secret);
|
|
123
|
-
if (!validation.valid) {
|
|
124
|
-
throw new Error(`Fetched auth secret failed validation: ${validation.reason}`);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
cachedSecret = secret;
|
|
128
|
-
lastFetchedAt = Date.now();
|
|
129
|
-
process.env.BETTER_AUTH_SECRET = secret;
|
|
130
|
-
// Also set legacy name during transition so any consumer still reading
|
|
131
|
-
// process.env.NEXTAUTH_SECRET keeps working until they upgrade.
|
|
132
|
-
process.env.NEXTAUTH_SECRET = secret;
|
|
133
|
-
|
|
134
|
-
console.log('[AUTH-SECRET] Resolved from IDP (length:', secret.length + ')');
|
|
135
|
-
|
|
136
|
-
return secret;
|
|
137
|
-
}
|
|
1
|
+
import 'server-only';
|
|
2
|
+
import { validateAuthSecret } from './secret-validation';
|
|
3
|
+
import { randomUUID } from 'crypto';
|
|
4
|
+
|
|
5
|
+
let cachedSecret: string | null = null;
|
|
6
|
+
let lastFetchedAt = 0;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Resolve the Better Auth signing secret (server-only).
|
|
10
|
+
*
|
|
11
|
+
* Priority:
|
|
12
|
+
* 1) Use process.env.BETTER_AUTH_SECRET (preferred) or NEXTAUTH_SECRET (legacy)
|
|
13
|
+
* if present — allows overrides/production via env.
|
|
14
|
+
* 2) Fetch from IDP broker endpoint — IDP handles all Key Vault/signing.
|
|
15
|
+
* 3) Cache result in-memory and set process.env.BETTER_AUTH_SECRET for
|
|
16
|
+
* subsequent calls.
|
|
17
|
+
*
|
|
18
|
+
* NOTE on naming: this secret is the cryptographic key Better Auth uses to
|
|
19
|
+
* sign session JWTs. The IDP backend still names the broker endpoint and
|
|
20
|
+
* response field with the legacy "next-auth" / "nextAuthSecret" names; we
|
|
21
|
+
* read both new and legacy on the wire during the migration window.
|
|
22
|
+
*/
|
|
23
|
+
export async function resolveAuthSecret(): Promise<string> {
|
|
24
|
+
// Check if already in environment (prefer new name, fall back to legacy)
|
|
25
|
+
const envSecret =
|
|
26
|
+
(process.env.BETTER_AUTH_SECRET && process.env.BETTER_AUTH_SECRET.trim() !== ''
|
|
27
|
+
? process.env.BETTER_AUTH_SECRET
|
|
28
|
+
: undefined) ||
|
|
29
|
+
(process.env.NEXTAUTH_SECRET && process.env.NEXTAUTH_SECRET.trim() !== ''
|
|
30
|
+
? process.env.NEXTAUTH_SECRET
|
|
31
|
+
: undefined);
|
|
32
|
+
if (envSecret) {
|
|
33
|
+
// Silent - already configured
|
|
34
|
+
return envSecret;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Check if cached and fresh (within 5 minutes)
|
|
38
|
+
if (cachedSecret && Date.now() - lastFetchedAt < 5 * 60 * 1000) {
|
|
39
|
+
return cachedSecret;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Broker mode: fetch from IDP (IDP handles all Key Vault/signing)
|
|
43
|
+
const base = process.env.IDP_URL;
|
|
44
|
+
if (!base) throw new Error('IDP_URL environment variable is required');
|
|
45
|
+
|
|
46
|
+
const clientIdStr = process.env.CLIENT_ID;
|
|
47
|
+
if (!clientIdStr || clientIdStr.trim() === '') throw new Error('CLIENT_ID is required (e.g., "ideal_resume_website")');
|
|
48
|
+
|
|
49
|
+
// Step 1: Request IDP to sign a client assertion (IDP has the keys, not us)
|
|
50
|
+
|
|
51
|
+
const signingUrl = new URL(`${base.replace(/\/$/, '')}/api/ExternalAuth/sign-client-assertion`);
|
|
52
|
+
|
|
53
|
+
const signingPayload = {
|
|
54
|
+
issuer: clientIdStr,
|
|
55
|
+
subject: clientIdStr,
|
|
56
|
+
audience: 'urn:payez:externalauth:nextauthsecret',
|
|
57
|
+
expires_in: 60,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const signingResp = await fetch(signingUrl.toString(), {
|
|
61
|
+
method: 'POST',
|
|
62
|
+
headers: {
|
|
63
|
+
'Accept': 'application/json',
|
|
64
|
+
'Content-Type': 'application/json',
|
|
65
|
+
'X-Client-Id': clientIdStr,
|
|
66
|
+
'X-Correlation-Id': randomUUID().replace(/-/g, ''),
|
|
67
|
+
},
|
|
68
|
+
body: JSON.stringify(signingPayload),
|
|
69
|
+
cache: 'no-store'
|
|
70
|
+
} as RequestInit);
|
|
71
|
+
|
|
72
|
+
if (!signingResp.ok) {
|
|
73
|
+
const txt = await signingResp.text().catch(() => 'Unknown error');
|
|
74
|
+
throw new Error(`Failed to sign client assertion: ${signingResp.status} ${signingResp.statusText} - ${txt}`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const signingBody: any = await signingResp.json().catch(() => ({}));
|
|
78
|
+
const client_assertion = (
|
|
79
|
+
signingBody?.data?.client_assertion ??
|
|
80
|
+
signingBody?.data?.clientAssertion ??
|
|
81
|
+
signingBody?.client_assertion ??
|
|
82
|
+
signingBody?.clientAssertion ??
|
|
83
|
+
signingBody?.data?.ClientAssertion ??
|
|
84
|
+
signingBody?.ClientAssertion
|
|
85
|
+
) as string | undefined;
|
|
86
|
+
|
|
87
|
+
if (!client_assertion || typeof client_assertion !== 'string') {
|
|
88
|
+
throw new Error('IDP did not return a valid signed client assertion');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Step 2: Use the signed assertion to fetch the auth secret
|
|
92
|
+
// (Endpoint is still served at /next-auth/secret on the IDP — legacy path.)
|
|
93
|
+
|
|
94
|
+
const proxyUrl = new URL(`${base.replace(/\/$/, '')}/api/ExternalAuth/next-auth/secret`);
|
|
95
|
+
|
|
96
|
+
const proxyResp = await fetch(proxyUrl.toString(), {
|
|
97
|
+
method: 'POST',
|
|
98
|
+
headers: {
|
|
99
|
+
'Accept': 'application/json',
|
|
100
|
+
'Content-Type': 'application/json',
|
|
101
|
+
'X-Client-Id': clientIdStr,
|
|
102
|
+
'X-Correlation-Id': randomUUID().replace(/-/g, ''),
|
|
103
|
+
},
|
|
104
|
+
body: JSON.stringify({ client_assertion }),
|
|
105
|
+
cache: 'no-store'
|
|
106
|
+
} as RequestInit);
|
|
107
|
+
|
|
108
|
+
if (!proxyResp.ok) {
|
|
109
|
+
const txt = await proxyResp.text().catch(() => 'Unknown error');
|
|
110
|
+
throw new Error(`Proxy error: ${proxyResp.status} ${proxyResp.statusText} - ${txt}`);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const proxyBody: any = await proxyResp.json().catch(() => ({}));
|
|
114
|
+
|
|
115
|
+
const secret = (proxyBody?.data?.secret ?? proxyBody?.secret) as string | undefined;
|
|
116
|
+
// Configuration is available but we don't log it verbosely
|
|
117
|
+
|
|
118
|
+
if (!secret || typeof secret !== 'string') {
|
|
119
|
+
throw new Error('Proxy did not return a valid auth secret');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const validation = validateAuthSecret(secret);
|
|
123
|
+
if (!validation.valid) {
|
|
124
|
+
throw new Error(`Fetched auth secret failed validation: ${validation.reason}`);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
cachedSecret = secret;
|
|
128
|
+
lastFetchedAt = Date.now();
|
|
129
|
+
process.env.BETTER_AUTH_SECRET = secret;
|
|
130
|
+
// Also set legacy name during transition so any consumer still reading
|
|
131
|
+
// process.env.NEXTAUTH_SECRET keeps working until they upgrade.
|
|
132
|
+
process.env.NEXTAUTH_SECRET = secret;
|
|
133
|
+
|
|
134
|
+
console.log('[AUTH-SECRET] Resolved from IDP (length:', secret.length + ')');
|
|
135
|
+
|
|
136
|
+
return secret;
|
|
137
|
+
}
|
package/src/lib/demo-mode.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Demo mode utilities
|
|
3
|
-
* When DEMO_MODE=true, auth package is installed but not enforced
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export function isDemoMode(): boolean {
|
|
7
|
-
return process.env.DEMO_MODE === 'true' || process.env.NEXT_PUBLIC_DEMO_MODE === 'true';
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function isAuthConfigured(): boolean {
|
|
11
|
-
if (isDemoMode()) return false;
|
|
12
|
-
return !!(
|
|
13
|
-
process.env.BETTER_AUTH_SECRET ||
|
|
14
|
-
process.env.NEXTAUTH_SECRET ||
|
|
15
|
-
(process.env.NEXT_CLIENT_ID && process.env.NEXT_CLIENT_PRIVATE_KEY_PEM)
|
|
16
|
-
);
|
|
17
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Demo mode utilities
|
|
3
|
+
* When DEMO_MODE=true, auth package is installed but not enforced
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export function isDemoMode(): boolean {
|
|
7
|
+
return process.env.DEMO_MODE === 'true' || process.env.NEXT_PUBLIC_DEMO_MODE === 'true';
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function isAuthConfigured(): boolean {
|
|
11
|
+
if (isDemoMode()) return false;
|
|
12
|
+
return !!(
|
|
13
|
+
process.env.BETTER_AUTH_SECRET ||
|
|
14
|
+
process.env.NEXTAUTH_SECRET ||
|
|
15
|
+
(process.env.NEXT_CLIENT_ID && process.env.NEXT_CLIENT_PRIVATE_KEY_PEM)
|
|
16
|
+
);
|
|
17
|
+
}
|