@delmaredigital/payload-better-auth 0.3.6 → 0.3.8
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 +60 -12
- package/dist/adapter/collections.d.ts.map +1 -1
- package/dist/adapter/collections.js +126 -88
- package/dist/adapter/collections.js.map +1 -1
- package/dist/adapter/index.js +197 -150
- package/dist/adapter/index.js.map +1 -1
- package/dist/components/BeforeLogin.d.ts +1 -1
- package/dist/components/BeforeLogin.d.ts.map +1 -1
- package/dist/components/BeforeLogin.js +15 -7
- package/dist/components/BeforeLogin.js.map +1 -1
- package/dist/components/LoginView.d.ts +2 -2
- package/dist/components/LoginView.d.ts.map +1 -1
- package/dist/components/LoginView.js +660 -218
- package/dist/components/LoginView.js.map +1 -1
- package/dist/components/LoginViewWrapper.d.ts +1 -1
- package/dist/components/LoginViewWrapper.d.ts.map +1 -1
- package/dist/components/LoginViewWrapper.js +14 -4
- package/dist/components/LoginViewWrapper.js.map +1 -1
- package/dist/components/LogoutButton.d.ts +1 -1
- package/dist/components/LogoutButton.d.ts.map +1 -1
- package/dist/components/LogoutButton.js +19 -11
- package/dist/components/LogoutButton.js.map +1 -1
- package/dist/components/PasskeyRegisterButton.d.ts +2 -2
- package/dist/components/PasskeyRegisterButton.d.ts.map +1 -1
- package/dist/components/PasskeyRegisterButton.js +20 -16
- package/dist/components/PasskeyRegisterButton.js.map +1 -1
- package/dist/components/PasskeySignInButton.d.ts +2 -2
- package/dist/components/PasskeySignInButton.d.ts.map +1 -1
- package/dist/components/PasskeySignInButton.js +14 -12
- package/dist/components/PasskeySignInButton.js.map +1 -1
- package/dist/components/auth/ForgotPasswordView.d.ts +1 -1
- package/dist/components/auth/ForgotPasswordView.d.ts.map +1 -1
- package/dist/components/auth/ForgotPasswordView.js +133 -43
- package/dist/components/auth/ForgotPasswordView.js.map +1 -1
- package/dist/components/auth/ResetPasswordView.d.ts +1 -1
- package/dist/components/auth/ResetPasswordView.d.ts.map +1 -1
- package/dist/components/auth/ResetPasswordView.js +154 -50
- package/dist/components/auth/ResetPasswordView.js.map +1 -1
- package/dist/components/auth/index.js +2 -2
- package/dist/components/auth/index.js.map +1 -1
- package/dist/components/management/ApiKeysManagementClient.d.ts +2 -2
- package/dist/components/management/ApiKeysManagementClient.d.ts.map +1 -1
- package/dist/components/management/ApiKeysManagementClient.js +539 -222
- package/dist/components/management/ApiKeysManagementClient.js.map +1 -1
- package/dist/components/management/PasskeysManagementClient.d.ts +2 -2
- package/dist/components/management/PasskeysManagementClient.d.ts.map +1 -1
- package/dist/components/management/PasskeysManagementClient.js +215 -92
- package/dist/components/management/PasskeysManagementClient.js.map +1 -1
- package/dist/components/management/SecurityNavLinks.d.ts +1 -1
- package/dist/components/management/SecurityNavLinks.d.ts.map +1 -1
- package/dist/components/management/SecurityNavLinks.js +51 -24
- package/dist/components/management/SecurityNavLinks.js.map +1 -1
- package/dist/components/management/TwoFactorManagementClient.d.ts +2 -2
- package/dist/components/management/TwoFactorManagementClient.d.ts.map +1 -1
- package/dist/components/management/TwoFactorManagementClient.js +270 -111
- package/dist/components/management/TwoFactorManagementClient.js.map +1 -1
- package/dist/components/management/index.js +2 -2
- package/dist/components/management/index.js.map +1 -1
- package/dist/components/management/views/ApiKeysView.d.ts +1 -1
- package/dist/components/management/views/ApiKeysView.d.ts.map +1 -1
- package/dist/components/management/views/ApiKeysView.js +19 -4
- package/dist/components/management/views/ApiKeysView.js.map +1 -1
- package/dist/components/management/views/PasskeysView.d.ts +1 -1
- package/dist/components/management/views/PasskeysView.d.ts.map +1 -1
- package/dist/components/management/views/PasskeysView.js +16 -4
- package/dist/components/management/views/PasskeysView.js.map +1 -1
- package/dist/components/management/views/TwoFactorView.d.ts +1 -1
- package/dist/components/management/views/TwoFactorView.d.ts.map +1 -1
- package/dist/components/management/views/TwoFactorView.js +16 -4
- package/dist/components/management/views/TwoFactorView.js.map +1 -1
- package/dist/components/management/views/index.js +2 -2
- package/dist/components/management/views/index.js.map +1 -1
- package/dist/components/twoFactor/TwoFactorSetupView.d.ts +1 -1
- package/dist/components/twoFactor/TwoFactorSetupView.d.ts.map +1 -1
- package/dist/components/twoFactor/TwoFactorSetupView.js +240 -87
- package/dist/components/twoFactor/TwoFactorSetupView.js.map +1 -1
- package/dist/components/twoFactor/TwoFactorVerifyView.d.ts +1 -1
- package/dist/components/twoFactor/TwoFactorVerifyView.d.ts.map +1 -1
- package/dist/components/twoFactor/TwoFactorVerifyView.js +108 -45
- package/dist/components/twoFactor/TwoFactorVerifyView.js.map +1 -1
- package/dist/components/twoFactor/index.js +2 -2
- package/dist/components/twoFactor/index.js.map +1 -1
- package/dist/exports/client.d.ts +2356 -2
- package/dist/exports/client.d.ts.map +1 -1
- package/dist/exports/client.js +48 -8
- package/dist/exports/client.js.map +1 -1
- package/dist/exports/components.js +2 -2
- package/dist/exports/components.js.map +1 -1
- package/dist/exports/management.js +3 -3
- package/dist/exports/management.js.map +1 -1
- package/dist/exports/rsc.js +2 -2
- package/dist/exports/rsc.js.map +1 -1
- package/dist/generated-types.js +4 -2
- package/dist/generated-types.js.map +1 -1
- package/dist/index.js +6 -6
- package/dist/index.js.map +1 -1
- package/dist/plugin/index.d.ts +35 -2
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +198 -162
- package/dist/plugin/index.js.map +1 -1
- package/dist/scripts/generate-types.js +66 -50
- package/dist/scripts/generate-types.js.map +1 -1
- package/dist/types/apiKey.js +7 -2
- package/dist/types/apiKey.js.map +1 -1
- package/dist/types/betterAuth.js +23 -2
- package/dist/types/betterAuth.js.map +1 -1
- package/dist/utils/access.js +78 -81
- package/dist/utils/access.js.map +1 -1
- package/dist/utils/apiKeyAccess.js +65 -72
- package/dist/utils/apiKeyAccess.js.map +1 -1
- package/dist/utils/betterAuthDefaults.js +8 -8
- package/dist/utils/betterAuthDefaults.js.map +1 -1
- package/dist/utils/detectAuthConfig.js +8 -11
- package/dist/utils/detectAuthConfig.js.map +1 -1
- package/dist/utils/detectEnabledPlugins.js +6 -7
- package/dist/utils/detectEnabledPlugins.js.map +1 -1
- package/dist/utils/firstUserAdmin.js +18 -20
- package/dist/utils/firstUserAdmin.js.map +1 -1
- package/dist/utils/generateScopes.js +40 -41
- package/dist/utils/generateScopes.js.map +1 -1
- package/dist/utils/session.js +8 -9
- package/dist/utils/session.js.map +1 -1
- package/package.json +97 -26
- package/src/adapter/collections.ts +621 -0
- package/src/adapter/index.ts +712 -0
- package/src/components/BeforeLogin.tsx +39 -0
- package/src/components/LoginView.tsx +1516 -0
- package/src/components/LoginViewWrapper.tsx +35 -0
- package/src/components/LogoutButton.tsx +58 -0
- package/src/components/PasskeyRegisterButton.tsx +105 -0
- package/src/components/PasskeySignInButton.tsx +96 -0
- package/src/components/auth/ForgotPasswordView.tsx +274 -0
- package/src/components/auth/ResetPasswordView.tsx +331 -0
- package/src/components/auth/index.ts +8 -0
- package/src/components/management/ApiKeysManagementClient.tsx +988 -0
- package/src/components/management/PasskeysManagementClient.tsx +409 -0
- package/src/components/management/SecurityNavLinks.tsx +117 -0
- package/src/components/management/TwoFactorManagementClient.tsx +560 -0
- package/src/components/management/index.ts +20 -0
- package/src/components/management/views/ApiKeysView.tsx +57 -0
- package/src/components/management/views/PasskeysView.tsx +42 -0
- package/src/components/management/views/TwoFactorView.tsx +42 -0
- package/src/components/management/views/index.ts +10 -0
- package/src/components/twoFactor/TwoFactorSetupView.tsx +515 -0
- package/src/components/twoFactor/TwoFactorVerifyView.tsx +238 -0
- package/src/components/twoFactor/index.ts +8 -0
- package/src/exports/client.ts +77 -0
- package/src/exports/components.ts +30 -0
- package/src/exports/management.ts +25 -0
- package/src/exports/rsc.ts +11 -0
- package/src/generated-types.ts +269 -0
- package/src/index.ts +135 -0
- package/src/plugin/index.ts +834 -0
- package/src/scripts/generate-types.ts +269 -0
- package/src/types/apiKey.ts +63 -0
- package/src/types/betterAuth.ts +253 -0
- package/src/utils/access.ts +410 -0
- package/src/utils/apiKeyAccess.ts +443 -0
- package/src/utils/betterAuthDefaults.ts +102 -0
- package/src/utils/detectAuthConfig.ts +47 -0
- package/src/utils/detectEnabledPlugins.ts +69 -0
- package/src/utils/firstUserAdmin.ts +164 -0
- package/src/utils/generateScopes.ts +150 -0
- package/src/utils/session.ts +91 -0
package/dist/plugin/index.js
CHANGED
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
* Payload Plugins for Better Auth
|
|
3
3
|
*
|
|
4
4
|
* @packageDocumentation
|
|
5
|
-
*/
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { buildAvailableScopes, scopesToPermissions, } from '../utils/generateScopes.js';
|
|
5
|
+
*/ import { detectAuthConfig } from '../utils/detectAuthConfig.js';
|
|
6
|
+
import { detectEnabledPlugins } from '../utils/detectEnabledPlugins.js';
|
|
7
|
+
import { buildAvailableScopes, scopesToPermissions } from '../utils/generateScopes.js';
|
|
9
8
|
// Track auth instance for HMR
|
|
10
9
|
let authInstance = null;
|
|
11
10
|
// Store API key scopes config for access by management views
|
|
@@ -13,20 +12,27 @@ let apiKeyScopesConfig = undefined;
|
|
|
13
12
|
/**
|
|
14
13
|
* Get the configured API key scopes config.
|
|
15
14
|
* Used by the ApiKeysView to build available scopes.
|
|
16
|
-
*/
|
|
17
|
-
export function getApiKeyScopesConfig() {
|
|
15
|
+
*/ export function getApiKeyScopesConfig() {
|
|
18
16
|
return apiKeyScopesConfig;
|
|
19
17
|
}
|
|
20
18
|
/**
|
|
21
19
|
* Handle API key creation with scopes server-side.
|
|
22
20
|
* Converts scopes to permissions and calls Better Auth's server API.
|
|
23
|
-
*/
|
|
24
|
-
async function handleApiKeyCreateWithScopes(authApi, payload, headers, body) {
|
|
21
|
+
*/ async function handleApiKeyCreateWithScopes(authApi, payload, headers, body) {
|
|
25
22
|
try {
|
|
26
23
|
// Get the current session to find the user
|
|
27
|
-
const session = await authApi.getSession({
|
|
24
|
+
const session = await authApi.getSession({
|
|
25
|
+
headers
|
|
26
|
+
});
|
|
28
27
|
if (!session?.user?.id) {
|
|
29
|
-
return new Response(JSON.stringify({
|
|
28
|
+
return new Response(JSON.stringify({
|
|
29
|
+
error: 'Unauthorized'
|
|
30
|
+
}), {
|
|
31
|
+
status: 401,
|
|
32
|
+
headers: {
|
|
33
|
+
'Content-Type': 'application/json'
|
|
34
|
+
}
|
|
35
|
+
});
|
|
30
36
|
}
|
|
31
37
|
// Extract scopes from the request body
|
|
32
38
|
const scopes = body.scopes ?? [];
|
|
@@ -45,61 +51,83 @@ async function handleApiKeyCreateWithScopes(authApi, payload, headers, body) {
|
|
|
45
51
|
expiresIn: body.expiresIn,
|
|
46
52
|
prefix: body.prefix,
|
|
47
53
|
permissions: permissions && Object.keys(permissions).length > 0 ? permissions : undefined,
|
|
48
|
-
metadata: scopes.length > 0
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
54
|
+
metadata: scopes.length > 0 ? {
|
|
55
|
+
...body.metadata,
|
|
56
|
+
scopes
|
|
57
|
+
} : body.metadata
|
|
58
|
+
}
|
|
52
59
|
};
|
|
53
60
|
// Call Better Auth's server-side API
|
|
54
61
|
if (typeof authApi.createApiKey !== 'function') {
|
|
55
|
-
return new Response(JSON.stringify({
|
|
62
|
+
return new Response(JSON.stringify({
|
|
63
|
+
error: 'API key plugin not enabled'
|
|
64
|
+
}), {
|
|
65
|
+
status: 400,
|
|
66
|
+
headers: {
|
|
67
|
+
'Content-Type': 'application/json'
|
|
68
|
+
}
|
|
69
|
+
});
|
|
56
70
|
}
|
|
57
71
|
try {
|
|
58
72
|
const result = await authApi.createApiKey(createOptions);
|
|
59
73
|
return new Response(JSON.stringify(result), {
|
|
60
74
|
status: 200,
|
|
61
|
-
headers: {
|
|
75
|
+
headers: {
|
|
76
|
+
'Content-Type': 'application/json'
|
|
77
|
+
}
|
|
62
78
|
});
|
|
63
|
-
}
|
|
64
|
-
catch (createError) {
|
|
79
|
+
} catch (createError) {
|
|
65
80
|
// Check if error is due to metadata being disabled
|
|
66
81
|
const errorMessage = createError instanceof Error ? createError.message : String(createError);
|
|
67
|
-
const isMetadataDisabled = errorMessage.toLowerCase().includes('metadata') &&
|
|
68
|
-
errorMessage.toLowerCase().includes('disabled');
|
|
82
|
+
const isMetadataDisabled = errorMessage.toLowerCase().includes('metadata') && errorMessage.toLowerCase().includes('disabled');
|
|
69
83
|
if (isMetadataDisabled && createOptions.body.metadata) {
|
|
70
84
|
// Retry without metadata - key will still work, just won't show scopes in UI
|
|
71
85
|
console.warn('[better-auth] Metadata disabled, creating API key without scope metadata. Enable metadata with apiKeyWithDefaults() for better UX.');
|
|
72
86
|
const optionsWithoutMetadata = {
|
|
73
87
|
body: {
|
|
74
88
|
...createOptions.body,
|
|
75
|
-
metadata: undefined
|
|
76
|
-
}
|
|
89
|
+
metadata: undefined
|
|
90
|
+
}
|
|
77
91
|
};
|
|
78
92
|
const result = await authApi.createApiKey(optionsWithoutMetadata);
|
|
79
93
|
return new Response(JSON.stringify(result), {
|
|
80
94
|
status: 200,
|
|
81
|
-
headers: {
|
|
95
|
+
headers: {
|
|
96
|
+
'Content-Type': 'application/json'
|
|
97
|
+
}
|
|
82
98
|
});
|
|
83
99
|
}
|
|
84
100
|
// Re-throw other errors
|
|
85
101
|
throw createError;
|
|
86
102
|
}
|
|
87
|
-
}
|
|
88
|
-
catch (error) {
|
|
103
|
+
} catch (error) {
|
|
89
104
|
console.error('[better-auth] API key creation error:', error);
|
|
90
105
|
const message = error instanceof Error ? error.message : 'Failed to create API key';
|
|
91
|
-
return new Response(JSON.stringify({
|
|
106
|
+
return new Response(JSON.stringify({
|
|
107
|
+
error: message
|
|
108
|
+
}), {
|
|
109
|
+
status: 500,
|
|
110
|
+
headers: {
|
|
111
|
+
'Content-Type': 'application/json'
|
|
112
|
+
}
|
|
113
|
+
});
|
|
92
114
|
}
|
|
93
115
|
}
|
|
94
116
|
/**
|
|
95
117
|
* Creates the auth endpoint handler that proxies requests to Better Auth.
|
|
96
|
-
*/
|
|
97
|
-
|
|
98
|
-
return async (req) => {
|
|
118
|
+
*/ function createAuthEndpointHandler() {
|
|
119
|
+
return async (req)=>{
|
|
99
120
|
const payloadWithAuth = req.payload;
|
|
100
121
|
const auth = payloadWithAuth.betterAuth;
|
|
101
122
|
if (!auth) {
|
|
102
|
-
return new Response(JSON.stringify({
|
|
123
|
+
return new Response(JSON.stringify({
|
|
124
|
+
error: 'Better Auth not initialized'
|
|
125
|
+
}), {
|
|
126
|
+
status: 500,
|
|
127
|
+
headers: {
|
|
128
|
+
'Content-Type': 'application/json'
|
|
129
|
+
}
|
|
130
|
+
});
|
|
103
131
|
}
|
|
104
132
|
try {
|
|
105
133
|
// Construct the full URL for Better Auth
|
|
@@ -107,9 +135,7 @@ function createAuthEndpointHandler() {
|
|
|
107
135
|
const protocol = req.headers.get('x-forwarded-proto') || 'http';
|
|
108
136
|
const host = req.headers.get('host') || 'localhost';
|
|
109
137
|
const pathname = req.pathname || '';
|
|
110
|
-
const search = req.search ||
|
|
111
|
-
req.url?.split('?')[1] ||
|
|
112
|
-
'';
|
|
138
|
+
const search = req.search || req.url?.split('?')[1] || '';
|
|
113
139
|
const url = new URL(pathname, `${protocol}://${host}`);
|
|
114
140
|
if (search) {
|
|
115
141
|
url.search = search.startsWith('?') ? search : `?${search}`;
|
|
@@ -117,7 +143,10 @@ function createAuthEndpointHandler() {
|
|
|
117
143
|
// Get request body for non-GET methods
|
|
118
144
|
let body;
|
|
119
145
|
let parsedBody;
|
|
120
|
-
if (req.method && ![
|
|
146
|
+
if (req.method && ![
|
|
147
|
+
'GET',
|
|
148
|
+
'HEAD'
|
|
149
|
+
].includes(req.method)) {
|
|
121
150
|
try {
|
|
122
151
|
// Try to get body from request
|
|
123
152
|
if (typeof req.text === 'function') {
|
|
@@ -125,18 +154,15 @@ function createAuthEndpointHandler() {
|
|
|
125
154
|
if (body) {
|
|
126
155
|
try {
|
|
127
156
|
parsedBody = JSON.parse(body);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// Not JSON, that's okay
|
|
157
|
+
} catch {
|
|
158
|
+
// Not JSON, that's okay
|
|
131
159
|
}
|
|
132
160
|
}
|
|
133
|
-
}
|
|
134
|
-
else if (req.data) {
|
|
161
|
+
} else if (req.data) {
|
|
135
162
|
parsedBody = req.data;
|
|
136
163
|
body = JSON.stringify(parsedBody);
|
|
137
164
|
}
|
|
138
|
-
}
|
|
139
|
-
catch {
|
|
165
|
+
} catch {
|
|
140
166
|
// Body might already be consumed, try data property
|
|
141
167
|
if (req.data) {
|
|
142
168
|
parsedBody = req.data;
|
|
@@ -146,10 +172,7 @@ function createAuthEndpointHandler() {
|
|
|
146
172
|
}
|
|
147
173
|
// Intercept API key creation requests with scopes
|
|
148
174
|
// Better Auth's API key create endpoint is POST /api-key/create
|
|
149
|
-
const isApiKeyCreate = req.method === 'POST' &&
|
|
150
|
-
pathname.endsWith('/api-key/create') &&
|
|
151
|
-
parsedBody?.scopes &&
|
|
152
|
-
Array.isArray(parsedBody.scopes);
|
|
175
|
+
const isApiKeyCreate = req.method === 'POST' && pathname.endsWith('/api-key/create') && parsedBody?.scopes && Array.isArray(parsedBody.scopes);
|
|
153
176
|
if (isApiKeyCreate && parsedBody) {
|
|
154
177
|
return handleApiKeyCreateWithScopes(auth.api, req.payload, req.headers, parsedBody);
|
|
155
178
|
}
|
|
@@ -157,69 +180,71 @@ function createAuthEndpointHandler() {
|
|
|
157
180
|
const request = new Request(url.toString(), {
|
|
158
181
|
method: req.method || 'GET',
|
|
159
182
|
headers: req.headers,
|
|
160
|
-
body
|
|
183
|
+
body
|
|
161
184
|
});
|
|
162
185
|
const response = await auth.handler(request);
|
|
163
186
|
return response;
|
|
164
|
-
}
|
|
165
|
-
catch (error) {
|
|
187
|
+
} catch (error) {
|
|
166
188
|
console.error('[better-auth] Endpoint handler error:', error);
|
|
167
|
-
return new Response(JSON.stringify({
|
|
189
|
+
return new Response(JSON.stringify({
|
|
190
|
+
error: 'Internal server error'
|
|
191
|
+
}), {
|
|
192
|
+
status: 500,
|
|
193
|
+
headers: {
|
|
194
|
+
'Content-Type': 'application/json'
|
|
195
|
+
}
|
|
196
|
+
});
|
|
168
197
|
}
|
|
169
198
|
};
|
|
170
199
|
}
|
|
171
200
|
/**
|
|
172
201
|
* Generates Payload endpoints for Better Auth.
|
|
173
|
-
*/
|
|
174
|
-
function generateAuthEndpoints(basePath) {
|
|
202
|
+
*/ function generateAuthEndpoints(basePath) {
|
|
175
203
|
const handler = createAuthEndpointHandler();
|
|
176
|
-
const methods = [
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
204
|
+
const methods = [
|
|
205
|
+
'get',
|
|
206
|
+
'post',
|
|
207
|
+
'patch',
|
|
208
|
+
'put',
|
|
209
|
+
'delete'
|
|
210
|
+
];
|
|
211
|
+
return methods.map((method)=>({
|
|
212
|
+
path: `${basePath}/:path*`,
|
|
213
|
+
method,
|
|
214
|
+
handler
|
|
215
|
+
}));
|
|
182
216
|
}
|
|
183
217
|
/**
|
|
184
218
|
* Injects admin components into the Payload config when disableLocalStrategy is detected.
|
|
185
|
-
*/
|
|
186
|
-
function injectAdminComponents(config, options) {
|
|
219
|
+
*/ function injectAdminComponents(config, options) {
|
|
187
220
|
const authDetection = detectAuthConfig(config);
|
|
188
221
|
// Skip if not using disableLocalStrategy or auto-injection is disabled
|
|
189
|
-
if (!authDetection.hasDisableLocalStrategy ||
|
|
190
|
-
options.autoInjectAdminComponents === false) {
|
|
222
|
+
if (!authDetection.hasDisableLocalStrategy || options.autoInjectAdminComponents === false) {
|
|
191
223
|
return config;
|
|
192
224
|
}
|
|
193
225
|
const adminOptions = options.admin ?? {};
|
|
194
226
|
const existingComponents = config.admin?.components ?? {};
|
|
195
227
|
// Build logout button config
|
|
196
|
-
const logoutButton = adminOptions.disableLogoutButton
|
|
197
|
-
? existingComponents.logout?.Button
|
|
198
|
-
: adminOptions.logoutButtonComponent ??
|
|
199
|
-
'@delmaredigital/payload-better-auth/components#LogoutButton';
|
|
228
|
+
const logoutButton = adminOptions.disableLogoutButton ? existingComponents.logout?.Button : adminOptions.logoutButtonComponent ?? '@delmaredigital/payload-better-auth/components#LogoutButton';
|
|
200
229
|
// Build beforeLogin config
|
|
201
230
|
const existingBeforeLogin = existingComponents.beforeLogin ?? [];
|
|
202
|
-
const beforeLogin = adminOptions.disableBeforeLogin
|
|
203
|
-
? existingBeforeLogin
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
adminOptions.beforeLoginComponent ??
|
|
209
|
-
'@delmaredigital/payload-better-auth/components#BeforeLogin',
|
|
210
|
-
];
|
|
231
|
+
const beforeLogin = adminOptions.disableBeforeLogin ? existingBeforeLogin : [
|
|
232
|
+
...Array.isArray(existingBeforeLogin) ? existingBeforeLogin : [
|
|
233
|
+
existingBeforeLogin
|
|
234
|
+
],
|
|
235
|
+
adminOptions.beforeLoginComponent ?? '@delmaredigital/payload-better-auth/components#BeforeLogin'
|
|
236
|
+
];
|
|
211
237
|
// Build login view config
|
|
212
238
|
const existingViews = existingComponents.views ?? {};
|
|
213
|
-
const newLoginView = adminOptions.disableLoginView
|
|
214
|
-
|
|
215
|
-
:
|
|
216
|
-
|
|
217
|
-
'@delmaredigital/payload-better-auth/rsc#LoginViewWrapper',
|
|
218
|
-
path: '/login',
|
|
219
|
-
};
|
|
239
|
+
const newLoginView = adminOptions.disableLoginView ? undefined : {
|
|
240
|
+
Component: adminOptions.loginViewComponent ?? '@delmaredigital/payload-better-auth/rsc#LoginViewWrapper',
|
|
241
|
+
path: '/login'
|
|
242
|
+
};
|
|
220
243
|
const views = {
|
|
221
244
|
...existingViews,
|
|
222
|
-
...
|
|
245
|
+
...newLoginView ? {
|
|
246
|
+
login: newLoginView
|
|
247
|
+
} : {}
|
|
223
248
|
};
|
|
224
249
|
// Store login config in config.custom for the RSC wrapper to read
|
|
225
250
|
const loginConfig = adminOptions.login ?? {};
|
|
@@ -230,31 +255,26 @@ function injectAdminComponents(config, options) {
|
|
|
230
255
|
...config.custom,
|
|
231
256
|
betterAuth: {
|
|
232
257
|
...config.custom?.betterAuth,
|
|
233
|
-
login: loginConfig
|
|
234
|
-
}
|
|
258
|
+
login: loginConfig
|
|
259
|
+
}
|
|
235
260
|
},
|
|
236
261
|
admin: {
|
|
237
262
|
...config.admin,
|
|
238
263
|
components: {
|
|
239
264
|
...existingComponents,
|
|
240
|
-
logout: logoutButton
|
|
241
|
-
? {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
: {}),
|
|
245
|
-
Button: logoutButton,
|
|
246
|
-
}
|
|
247
|
-
: existingComponents.logout,
|
|
265
|
+
logout: logoutButton ? {
|
|
266
|
+
...typeof existingComponents.logout === 'object' ? existingComponents.logout : {},
|
|
267
|
+
Button: logoutButton
|
|
268
|
+
} : existingComponents.logout,
|
|
248
269
|
beforeLogin,
|
|
249
|
-
views
|
|
250
|
-
}
|
|
251
|
-
}
|
|
270
|
+
views
|
|
271
|
+
}
|
|
272
|
+
}
|
|
252
273
|
};
|
|
253
274
|
}
|
|
254
275
|
/**
|
|
255
276
|
* Injects management UI components into the Payload config based on enabled plugins.
|
|
256
|
-
*/
|
|
257
|
-
function injectManagementComponents(config, options) {
|
|
277
|
+
*/ function injectManagementComponents(config, options) {
|
|
258
278
|
const adminOptions = options.admin ?? {};
|
|
259
279
|
// Skip if management UI is disabled
|
|
260
280
|
if (adminOptions.enableManagementUI === false) {
|
|
@@ -266,7 +286,7 @@ function injectManagementComponents(config, options) {
|
|
|
266
286
|
const paths = {
|
|
267
287
|
twoFactor: adminOptions.managementPaths?.twoFactor ?? '/security/two-factor',
|
|
268
288
|
apiKeys: adminOptions.managementPaths?.apiKeys ?? '/security/api-keys',
|
|
269
|
-
passkeys: adminOptions.managementPaths?.passkeys ?? '/security/passkeys'
|
|
289
|
+
passkeys: adminOptions.managementPaths?.passkeys ?? '/security/passkeys'
|
|
270
290
|
};
|
|
271
291
|
const existingComponents = config.admin?.components ?? {};
|
|
272
292
|
const existingViews = existingComponents.views ?? {};
|
|
@@ -278,41 +298,39 @@ function injectManagementComponents(config, options) {
|
|
|
278
298
|
if (enabledPlugins.hasTwoFactor) {
|
|
279
299
|
managementViews.securityTwoFactor = {
|
|
280
300
|
Component: '@delmaredigital/payload-better-auth/rsc#TwoFactorView',
|
|
281
|
-
path: paths.twoFactor
|
|
301
|
+
path: paths.twoFactor
|
|
282
302
|
};
|
|
283
303
|
}
|
|
284
304
|
// API keys (if enabled)
|
|
285
305
|
if (enabledPlugins.hasApiKey) {
|
|
286
306
|
managementViews.securityApiKeys = {
|
|
287
307
|
Component: '@delmaredigital/payload-better-auth/rsc#ApiKeysView',
|
|
288
|
-
path: paths.apiKeys
|
|
308
|
+
path: paths.apiKeys
|
|
289
309
|
};
|
|
290
310
|
}
|
|
291
311
|
// Passkeys (if enabled)
|
|
292
312
|
if (enabledPlugins.hasPasskey) {
|
|
293
313
|
managementViews.securityPasskeys = {
|
|
294
314
|
Component: '@delmaredigital/payload-better-auth/rsc#PasskeysView',
|
|
295
|
-
path: paths.passkeys
|
|
315
|
+
path: paths.passkeys
|
|
296
316
|
};
|
|
297
317
|
}
|
|
298
318
|
// Only add nav links if at least one plugin is enabled
|
|
299
319
|
const hasAnyPlugin = enabledPlugins.hasTwoFactor || enabledPlugins.hasApiKey || enabledPlugins.hasPasskey;
|
|
300
320
|
// Add SecurityNavLinks to afterNavLinks with clientProps for enabled plugins
|
|
301
|
-
const afterNavLinks = hasAnyPlugin
|
|
302
|
-
? [
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
]
|
|
315
|
-
: existingAfterNavLinks;
|
|
321
|
+
const afterNavLinks = hasAnyPlugin ? [
|
|
322
|
+
...Array.isArray(existingAfterNavLinks) ? existingAfterNavLinks : [
|
|
323
|
+
existingAfterNavLinks
|
|
324
|
+
],
|
|
325
|
+
{
|
|
326
|
+
path: '@delmaredigital/payload-better-auth/components/management#SecurityNavLinks',
|
|
327
|
+
clientProps: {
|
|
328
|
+
showTwoFactor: enabledPlugins.hasTwoFactor,
|
|
329
|
+
showApiKeys: enabledPlugins.hasApiKey,
|
|
330
|
+
showPasskeys: enabledPlugins.hasPasskey
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
] : existingAfterNavLinks;
|
|
316
334
|
return {
|
|
317
335
|
...config,
|
|
318
336
|
admin: {
|
|
@@ -321,11 +339,11 @@ function injectManagementComponents(config, options) {
|
|
|
321
339
|
...existingComponents,
|
|
322
340
|
views: {
|
|
323
341
|
...existingViews,
|
|
324
|
-
...managementViews
|
|
342
|
+
...managementViews
|
|
325
343
|
},
|
|
326
|
-
afterNavLinks
|
|
327
|
-
}
|
|
328
|
-
}
|
|
344
|
+
afterNavLinks
|
|
345
|
+
}
|
|
346
|
+
}
|
|
329
347
|
};
|
|
330
348
|
}
|
|
331
349
|
/**
|
|
@@ -356,30 +374,28 @@ function injectManagementComponents(config, options) {
|
|
|
356
374
|
* ],
|
|
357
375
|
* })
|
|
358
376
|
* ```
|
|
359
|
-
*/
|
|
360
|
-
|
|
361
|
-
const { createAuth, authBasePath = '/auth', autoRegisterEndpoints = true, autoInjectAdminComponents = true, } = options;
|
|
377
|
+
*/ export function createBetterAuthPlugin(options) {
|
|
378
|
+
const { createAuth, authBasePath = '/auth', autoRegisterEndpoints = true, autoInjectAdminComponents = true } = options;
|
|
362
379
|
// Store API key scopes config for access by management views
|
|
363
380
|
apiKeyScopesConfig = options.admin?.apiKey;
|
|
364
|
-
return (incomingConfig)
|
|
381
|
+
return (incomingConfig)=>{
|
|
365
382
|
// Inject admin components if enabled
|
|
366
|
-
let config = autoInjectAdminComponents
|
|
367
|
-
? injectAdminComponents(incomingConfig, options)
|
|
368
|
-
: incomingConfig;
|
|
383
|
+
let config = autoInjectAdminComponents ? injectAdminComponents(incomingConfig, options) : incomingConfig;
|
|
369
384
|
// Inject management UI components
|
|
370
385
|
config = injectManagementComponents(config, options);
|
|
371
386
|
// Generate auth endpoints if enabled
|
|
372
|
-
const authEndpoints = autoRegisterEndpoints
|
|
373
|
-
? generateAuthEndpoints(authBasePath)
|
|
374
|
-
: [];
|
|
387
|
+
const authEndpoints = autoRegisterEndpoints ? generateAuthEndpoints(authBasePath) : [];
|
|
375
388
|
// Merge endpoints
|
|
376
389
|
const existingEndpoints = config.endpoints ?? [];
|
|
377
390
|
// Get existing onInit
|
|
378
391
|
const existingOnInit = config.onInit;
|
|
379
392
|
return {
|
|
380
393
|
...config,
|
|
381
|
-
endpoints: [
|
|
382
|
-
|
|
394
|
+
endpoints: [
|
|
395
|
+
...existingEndpoints,
|
|
396
|
+
...authEndpoints
|
|
397
|
+
],
|
|
398
|
+
onInit: async (payload)=>{
|
|
383
399
|
if (existingOnInit) {
|
|
384
400
|
await existingOnInit(payload);
|
|
385
401
|
}
|
|
@@ -391,8 +407,7 @@ export function createBetterAuthPlugin(options) {
|
|
|
391
407
|
if (!authInstance) {
|
|
392
408
|
try {
|
|
393
409
|
authInstance = createAuth(payload);
|
|
394
|
-
}
|
|
395
|
-
catch (error) {
|
|
410
|
+
} catch (error) {
|
|
396
411
|
console.error('[better-auth] Failed to create auth:', error);
|
|
397
412
|
throw error;
|
|
398
413
|
}
|
|
@@ -402,9 +417,9 @@ export function createBetterAuthPlugin(options) {
|
|
|
402
417
|
value: authInstance,
|
|
403
418
|
writable: false,
|
|
404
419
|
enumerable: false,
|
|
405
|
-
configurable: false
|
|
420
|
+
configurable: false
|
|
406
421
|
});
|
|
407
|
-
}
|
|
422
|
+
}
|
|
408
423
|
};
|
|
409
424
|
};
|
|
410
425
|
}
|
|
@@ -443,31 +458,42 @@ export function createBetterAuthPlugin(options) {
|
|
|
443
458
|
* }
|
|
444
459
|
* }
|
|
445
460
|
* ```
|
|
446
|
-
*/
|
|
447
|
-
export function betterAuthStrategy(options = {}) {
|
|
461
|
+
*/ export function betterAuthStrategy(options = {}) {
|
|
448
462
|
const { usersCollection = 'users', membersCollection = 'members' } = options;
|
|
449
463
|
return {
|
|
450
464
|
name: 'better-auth',
|
|
451
|
-
authenticate: async ({ payload, headers
|
|
465
|
+
authenticate: async ({ payload, headers })=>{
|
|
452
466
|
try {
|
|
453
467
|
const payloadWithAuth = payload;
|
|
454
468
|
const auth = payloadWithAuth.betterAuth;
|
|
455
469
|
if (!auth) {
|
|
456
470
|
console.error('Better Auth not initialized on payload instance');
|
|
457
|
-
return {
|
|
471
|
+
return {
|
|
472
|
+
user: null
|
|
473
|
+
};
|
|
458
474
|
}
|
|
459
|
-
const sessionData = await auth.api.getSession({
|
|
475
|
+
const sessionData = await auth.api.getSession({
|
|
476
|
+
headers
|
|
477
|
+
});
|
|
460
478
|
if (!sessionData?.user?.id) {
|
|
461
|
-
return {
|
|
479
|
+
return {
|
|
480
|
+
user: null
|
|
481
|
+
};
|
|
462
482
|
}
|
|
463
483
|
const users = await payload.find({
|
|
464
484
|
collection: usersCollection,
|
|
465
|
-
where: {
|
|
485
|
+
where: {
|
|
486
|
+
id: {
|
|
487
|
+
equals: sessionData.user.id
|
|
488
|
+
}
|
|
489
|
+
},
|
|
466
490
|
limit: 1,
|
|
467
|
-
depth: 0
|
|
491
|
+
depth: 0
|
|
468
492
|
});
|
|
469
493
|
if (users.docs.length === 0) {
|
|
470
|
-
return {
|
|
494
|
+
return {
|
|
495
|
+
user: null
|
|
496
|
+
};
|
|
471
497
|
}
|
|
472
498
|
// Extract session fields to merge onto user (e.g., activeOrganizationId from org plugin)
|
|
473
499
|
// Exclude fields that might conflict with user fields
|
|
@@ -480,42 +506,52 @@ export function betterAuthStrategy(options = {}) {
|
|
|
480
506
|
collection: membersCollection,
|
|
481
507
|
where: {
|
|
482
508
|
and: [
|
|
483
|
-
{
|
|
484
|
-
|
|
485
|
-
|
|
509
|
+
{
|
|
510
|
+
user: {
|
|
511
|
+
equals: sessionData.user.id
|
|
512
|
+
}
|
|
513
|
+
},
|
|
514
|
+
{
|
|
515
|
+
organization: {
|
|
516
|
+
equals: sessionFields.activeOrganizationId
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
]
|
|
486
520
|
},
|
|
487
521
|
limit: 1,
|
|
488
|
-
depth: 0
|
|
522
|
+
depth: 0
|
|
489
523
|
});
|
|
490
524
|
if (memberships.docs.length > 0) {
|
|
491
525
|
organizationRole = memberships.docs[0].role;
|
|
492
526
|
}
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
// Members collection might not exist (org plugin not used), silently ignore
|
|
527
|
+
} catch {
|
|
528
|
+
// Members collection might not exist (org plugin not used), silently ignore
|
|
496
529
|
}
|
|
497
530
|
}
|
|
498
531
|
return {
|
|
499
532
|
user: {
|
|
500
533
|
...users.docs[0],
|
|
501
|
-
...sessionFields,
|
|
502
|
-
...
|
|
534
|
+
...sessionFields,
|
|
535
|
+
...organizationRole && {
|
|
536
|
+
organizationRole
|
|
537
|
+
},
|
|
503
538
|
collection: usersCollection,
|
|
504
|
-
_strategy: 'better-auth'
|
|
505
|
-
}
|
|
539
|
+
_strategy: 'better-auth'
|
|
540
|
+
}
|
|
506
541
|
};
|
|
507
|
-
}
|
|
508
|
-
catch (error) {
|
|
542
|
+
} catch (error) {
|
|
509
543
|
console.error('Better Auth strategy error:', error);
|
|
510
|
-
return {
|
|
544
|
+
return {
|
|
545
|
+
user: null
|
|
546
|
+
};
|
|
511
547
|
}
|
|
512
|
-
}
|
|
548
|
+
}
|
|
513
549
|
};
|
|
514
550
|
}
|
|
515
551
|
/**
|
|
516
552
|
* Reset the auth instance (useful for testing)
|
|
517
|
-
*/
|
|
518
|
-
export function resetAuthInstance() {
|
|
553
|
+
*/ export function resetAuthInstance() {
|
|
519
554
|
authInstance = null;
|
|
520
555
|
}
|
|
556
|
+
|
|
521
557
|
//# sourceMappingURL=index.js.map
|