feat(core): Add scopes to API Keys (#14176)

Co-authored-by: Charlie Kolb <charlie@n8n.io>
Co-authored-by: Danny Martini <danny@n8n.io>
This commit is contained in:
Ricardo Espinoza
2025-04-16 09:03:16 -04:00
committed by GitHub
parent bc12f662e7
commit e1b9407fe9
65 changed files with 3216 additions and 125 deletions

View File

@@ -2,8 +2,10 @@ import { CreateApiKeyRequestDto, UpdateApiKeyRequestDto } from '@n8n/api-types';
import type { RequestHandler } from 'express';
import { Body, Delete, Get, Param, Patch, Post, RestController } from '@/decorators';
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
import { EventService } from '@/events/event.service';
import { isApiEnabled } from '@/public-api';
import { getApiKeyScopesForRole } from '@/public-api/permissions.ee';
import { AuthenticatedRequest } from '@/requests';
import { PublicApiKeyService } from '@/services/public-api-key.service';
@@ -26,15 +28,16 @@ export class ApiKeysController {
* Create an API Key
*/
@Post('/', { middlewares: [isApiEnabledMiddleware] })
async createAPIKey(
async createApiKey(
req: AuthenticatedRequest,
_res: Response,
@Body { label, expiresAt }: CreateApiKeyRequestDto,
@Body body: CreateApiKeyRequestDto,
) {
const newApiKey = await this.publicApiKeyService.createPublicApiKeyForUser(req.user, {
label,
expiresAt,
});
if (!this.publicApiKeyService.apiKeyHasValidScopesForRole(req.user.role, body.scopes)) {
throw new BadRequestError('Invalid scopes for user role');
}
const newApiKey = await this.publicApiKeyService.createPublicApiKeyForUser(req.user, body);
this.eventService.emit('public-api-key-created', { user: req.user, publicApi: false });
@@ -42,7 +45,7 @@ export class ApiKeysController {
...newApiKey,
apiKey: this.publicApiKeyService.redactApiKey(newApiKey.apiKey),
rawApiKey: newApiKey.apiKey,
expiresAt,
expiresAt: body.expiresAt,
};
}
@@ -50,7 +53,7 @@ export class ApiKeysController {
* Get API keys
*/
@Get('/', { middlewares: [isApiEnabledMiddleware] })
async getAPIKeys(req: AuthenticatedRequest) {
async getApiKeys(req: AuthenticatedRequest) {
const apiKeys = await this.publicApiKeyService.getRedactedApiKeysForUser(req.user);
return apiKeys;
}
@@ -59,7 +62,7 @@ export class ApiKeysController {
* Delete an API Key
*/
@Delete('/:id', { middlewares: [isApiEnabledMiddleware] })
async deleteAPIKey(req: AuthenticatedRequest, _res: Response, @Param('id') apiKeyId: string) {
async deleteApiKey(req: AuthenticatedRequest, _res: Response, @Param('id') apiKeyId: string) {
await this.publicApiKeyService.deleteApiKeyForUser(req.user, apiKeyId);
this.eventService.emit('public-api-key-deleted', { user: req.user, publicApi: false });
@@ -71,16 +74,25 @@ export class ApiKeysController {
* Patch an API Key
*/
@Patch('/:id', { middlewares: [isApiEnabledMiddleware] })
async updateAPIKey(
async updateApiKey(
req: AuthenticatedRequest,
_res: Response,
@Param('id') apiKeyId: string,
@Body { label }: UpdateApiKeyRequestDto,
@Body body: UpdateApiKeyRequestDto,
) {
await this.publicApiKeyService.updateApiKeyForUser(req.user, apiKeyId, {
label,
});
if (!this.publicApiKeyService.apiKeyHasValidScopesForRole(req.user.role, body.scopes)) {
throw new BadRequestError('Invalid scopes for user role');
}
await this.publicApiKeyService.updateApiKeyForUser(req.user, apiKeyId, body);
return { success: true };
}
@Get('/scopes', { middlewares: [isApiEnabledMiddleware] })
async getApiKeyScopes(req: AuthenticatedRequest, _res: Response) {
const { role } = req.user;
const scopes = getApiKeyScopesForRole(role);
return scopes;
}
}