@delmaredigital/payload-better-auth 0.4.0 → 0.4.1
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 +21 -0
- package/dist/plugin/index.js +44 -4
- package/dist/types/apiKey.d.ts +8 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -494,6 +494,27 @@ API keys can have granular permission scopes. By default, scopes are auto-genera
|
|
|
494
494
|
| `includeCollectionScopes` | `boolean` | `true` when no custom scopes, `false` when custom scopes provided | Include auto-generated collection scopes |
|
|
495
495
|
| `excludeCollections` | `string[]` | `['sessions', 'verifications', 'accounts', 'twoFactors', 'apikeys']` | Collections to exclude from auto-generated scopes |
|
|
496
496
|
| `defaultScopes` | `string[]` | `[]` | Default scopes pre-selected when creating a key |
|
|
497
|
+
| `requiredRole` | `string \| string[] \| null` | Inherits from `admin.login.requiredRole` or `'admin'` | Role(s) required to create/update/delete API keys. Set to `null` to allow any authenticated user (not recommended) |
|
|
498
|
+
|
|
499
|
+
**Restricting API key management to admins:**
|
|
500
|
+
|
|
501
|
+
If your `admin.login.requiredRole` includes non-admin roles (e.g., editors who need admin panel access but shouldn't manage API keys), set `requiredRole` explicitly:
|
|
502
|
+
|
|
503
|
+
```typescript
|
|
504
|
+
createBetterAuthPlugin({
|
|
505
|
+
createAuth,
|
|
506
|
+
admin: {
|
|
507
|
+
login: {
|
|
508
|
+
requiredRole: ['admin', 'content_editor'], // both can access admin panel
|
|
509
|
+
},
|
|
510
|
+
apiKey: {
|
|
511
|
+
requiredRole: 'admin', // only admins can create/update/delete API keys
|
|
512
|
+
},
|
|
513
|
+
},
|
|
514
|
+
})
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
> **Note:** API key **verification** is not affected by this setting — existing keys continue to work regardless of who created them. This only restricts key management (create, update, delete).
|
|
497
518
|
|
|
498
519
|
**Zero Config (recommended):**
|
|
499
520
|
```typescript
|
package/dist/plugin/index.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/ import { detectAuthConfig } from '../utils/detectAuthConfig.js';
|
|
6
6
|
import { detectEnabledPlugins } from '../utils/detectEnabledPlugins.js';
|
|
7
7
|
import { buildAvailableScopes, scopesToPermissions } from '../utils/generateScopes.js';
|
|
8
|
+
import { hasAnyRole, normalizeRoles } from '../utils/access.js';
|
|
8
9
|
// Track auth instance for HMR
|
|
9
10
|
let authInstance = null;
|
|
10
11
|
// Store API key scopes config for access by management views
|
|
@@ -115,7 +116,7 @@ let apiKeyScopesConfig = undefined;
|
|
|
115
116
|
}
|
|
116
117
|
/**
|
|
117
118
|
* Creates the auth endpoint handler that proxies requests to Better Auth.
|
|
118
|
-
*/ function createAuthEndpointHandler() {
|
|
119
|
+
*/ function createAuthEndpointHandler(adminOptions) {
|
|
119
120
|
return async (req)=>{
|
|
120
121
|
const payloadWithAuth = req.payload;
|
|
121
122
|
const auth = payloadWithAuth.betterAuth;
|
|
@@ -170,6 +171,45 @@ let apiKeyScopesConfig = undefined;
|
|
|
170
171
|
}
|
|
171
172
|
}
|
|
172
173
|
}
|
|
174
|
+
// Guard API key mutation endpoints — require admin role
|
|
175
|
+
const isApiKeyMutation = req.method === 'POST' && (pathname.endsWith('/api-key/create') || pathname.endsWith('/api-key/update') || pathname.endsWith('/api-key/delete'));
|
|
176
|
+
if (isApiKeyMutation) {
|
|
177
|
+
const session = await auth.api.getSession({
|
|
178
|
+
headers: req.headers
|
|
179
|
+
});
|
|
180
|
+
if (!session?.user?.id) {
|
|
181
|
+
return new Response(JSON.stringify({
|
|
182
|
+
error: 'Unauthorized'
|
|
183
|
+
}), {
|
|
184
|
+
status: 401,
|
|
185
|
+
headers: {
|
|
186
|
+
'Content-Type': 'application/json'
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
// Resolve required role: apiKey config > login config > default 'admin'
|
|
191
|
+
const requiredRole = apiKeyScopesConfig?.requiredRole ?? adminOptions?.login?.requiredRole ?? 'admin';
|
|
192
|
+
if (requiredRole !== null) {
|
|
193
|
+
// Find the auth collection slug from Payload's config
|
|
194
|
+
const authSlug = req.payload.config.collections.find((c)=>typeof c.auth === 'object' || c.auth === true)?.slug ?? 'users';
|
|
195
|
+
const user = await req.payload.findByID({
|
|
196
|
+
collection: authSlug,
|
|
197
|
+
id: session.user.id,
|
|
198
|
+
depth: 0,
|
|
199
|
+
overrideAccess: true
|
|
200
|
+
});
|
|
201
|
+
if (!hasAnyRole(user, normalizeRoles(requiredRole))) {
|
|
202
|
+
return new Response(JSON.stringify({
|
|
203
|
+
error: 'Forbidden: insufficient permissions to manage API keys'
|
|
204
|
+
}), {
|
|
205
|
+
status: 403,
|
|
206
|
+
headers: {
|
|
207
|
+
'Content-Type': 'application/json'
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
173
213
|
// Intercept API key creation requests with scopes
|
|
174
214
|
// Better Auth's API key create endpoint is POST /api-key/create
|
|
175
215
|
const isApiKeyCreate = req.method === 'POST' && pathname.endsWith('/api-key/create') && parsedBody?.scopes && Array.isArray(parsedBody.scopes);
|
|
@@ -199,8 +239,8 @@ let apiKeyScopesConfig = undefined;
|
|
|
199
239
|
}
|
|
200
240
|
/**
|
|
201
241
|
* Generates Payload endpoints for Better Auth.
|
|
202
|
-
*/ function generateAuthEndpoints(basePath) {
|
|
203
|
-
const handler = createAuthEndpointHandler();
|
|
242
|
+
*/ function generateAuthEndpoints(basePath, adminOptions) {
|
|
243
|
+
const handler = createAuthEndpointHandler(adminOptions);
|
|
204
244
|
const methods = [
|
|
205
245
|
'get',
|
|
206
246
|
'post',
|
|
@@ -384,7 +424,7 @@ let apiKeyScopesConfig = undefined;
|
|
|
384
424
|
// Inject management UI components
|
|
385
425
|
config = injectManagementComponents(config, options);
|
|
386
426
|
// Generate auth endpoints if enabled
|
|
387
|
-
const authEndpoints = autoRegisterEndpoints ? generateAuthEndpoints(authBasePath) : [];
|
|
427
|
+
const authEndpoints = autoRegisterEndpoints ? generateAuthEndpoints(authBasePath, options.admin) : [];
|
|
388
428
|
// Merge endpoints
|
|
389
429
|
const existingEndpoints = config.endpoints ?? [];
|
|
390
430
|
// Get existing onInit
|
package/dist/types/apiKey.d.ts
CHANGED
|
@@ -50,6 +50,14 @@ export type ApiKeyScopesConfig = {
|
|
|
50
50
|
* If not provided, keys without scopes will have no permissions.
|
|
51
51
|
*/
|
|
52
52
|
defaultScopes?: string[];
|
|
53
|
+
/**
|
|
54
|
+
* Role(s) required to create, update, and delete API keys.
|
|
55
|
+
* - string: Single role required (e.g., 'admin')
|
|
56
|
+
* - string[]: Any matching role grants access
|
|
57
|
+
* - null: Allow any authenticated user (not recommended)
|
|
58
|
+
* @default Inherits from admin.login.requiredRole, or 'admin' if unset
|
|
59
|
+
*/
|
|
60
|
+
requiredRole?: string | string[] | null;
|
|
53
61
|
};
|
|
54
62
|
/**
|
|
55
63
|
* Scope data passed to the API keys management client component.
|