diff --git a/packages/@n8n/api-types/src/api-keys.ts b/packages/@n8n/api-types/src/api-keys.ts
index e812786e78..a805d898f2 100644
--- a/packages/@n8n/api-types/src/api-keys.ts
+++ b/packages/@n8n/api-types/src/api-keys.ts
@@ -1,9 +1,14 @@
+/** Unix timestamp. Seconds since epoch */
+export type UnixTimestamp = number | null;
+
export type ApiKey = {
id: string;
label: string;
apiKey: string;
createdAt: string;
updatedAt: string;
+ /** Null if API key never expires */
+ expiresAt: UnixTimestamp | null;
};
export type ApiKeyWithRawValue = ApiKey & { rawApiKey: string };
diff --git a/packages/@n8n/api-types/src/dto/api-keys/__tests__/create-api-key-request.dto.test.ts b/packages/@n8n/api-types/src/dto/api-keys/__tests__/create-api-key-request.dto.test.ts
new file mode 100644
index 0000000000..923e0462bb
--- /dev/null
+++ b/packages/@n8n/api-types/src/dto/api-keys/__tests__/create-api-key-request.dto.test.ts
@@ -0,0 +1,53 @@
+import { CreateApiKeyRequestDto } from '../create-api-key-request.dto';
+
+describe('CreateApiKeyRequestDto', () => {
+ describe('Valid requests', () => {
+ test.each([
+ {
+ name: 'expiresAt in the future',
+ expiresAt: Date.now() / 1000 + 1000,
+ },
+ {
+ name: 'expiresAt null',
+ expiresAt: null,
+ },
+ ])('should succeed validation for $name', ({ expiresAt }) => {
+ const result = CreateApiKeyRequestDto.safeParse({ label: 'valid', expiresAt });
+
+ expect(result.success).toBe(true);
+ });
+ });
+
+ describe('Invalid requests', () => {
+ test.each([
+ {
+ name: 'expiresAt in the past',
+ expiresAt: Date.now() / 1000 - 1000,
+ expectedErrorPath: ['expiresAt'],
+ },
+ {
+ name: 'expiresAt with string',
+ expiresAt: 'invalid',
+ expectedErrorPath: ['expiresAt'],
+ },
+ {
+ name: 'expiresAt with []',
+ expiresAt: [],
+ expectedErrorPath: ['expiresAt'],
+ },
+ {
+ name: 'expiresAt with {}',
+ expiresAt: {},
+ expectedErrorPath: ['expiresAt'],
+ },
+ ])('should fail validation for $name', ({ expiresAt, expectedErrorPath }) => {
+ const result = CreateApiKeyRequestDto.safeParse({ label: 'valid', expiresAt });
+
+ expect(result.success).toBe(false);
+
+ if (expectedErrorPath) {
+ expect(result.error?.issues[0].path).toEqual(expectedErrorPath);
+ }
+ });
+ });
+});
diff --git a/packages/@n8n/api-types/src/dto/api-keys/__tests__/create-or-update.dto.test.ts b/packages/@n8n/api-types/src/dto/api-keys/__tests__/update-api-key-request.dto.test.ts
similarity index 75%
rename from packages/@n8n/api-types/src/dto/api-keys/__tests__/create-or-update.dto.test.ts
rename to packages/@n8n/api-types/src/dto/api-keys/__tests__/update-api-key-request.dto.test.ts
index beb7ebcf0d..10d6b0c31f 100644
--- a/packages/@n8n/api-types/src/dto/api-keys/__tests__/create-or-update.dto.test.ts
+++ b/packages/@n8n/api-types/src/dto/api-keys/__tests__/update-api-key-request.dto.test.ts
@@ -1,9 +1,9 @@
-import { CreateOrUpdateApiKeyRequestDto } from '../create-or-update-api-key-request.dto';
+import { UpdateApiKeyRequestDto } from '../update-api-key-request.dto';
-describe('CreateOrUpdateApiKeyRequestDto', () => {
+describe('UpdateApiKeyRequestDto', () => {
describe('Valid requests', () => {
test('should allow valid label', () => {
- const result = CreateOrUpdateApiKeyRequestDto.safeParse({
+ const result = UpdateApiKeyRequestDto.safeParse({
label: 'valid label',
});
expect(result.success).toBe(true);
@@ -28,7 +28,7 @@ describe('CreateOrUpdateApiKeyRequestDto', () => {
expectedErrorPath: ['label'],
},
])('should fail validation for $name', ({ label, expectedErrorPath }) => {
- const result = CreateOrUpdateApiKeyRequestDto.safeParse({ label });
+ const result = UpdateApiKeyRequestDto.safeParse({ label });
expect(result.success).toBe(false);
diff --git a/packages/@n8n/api-types/src/dto/api-keys/create-api-key-request.dto.ts b/packages/@n8n/api-types/src/dto/api-keys/create-api-key-request.dto.ts
new file mode 100644
index 0000000000..f5e66b0d62
--- /dev/null
+++ b/packages/@n8n/api-types/src/dto/api-keys/create-api-key-request.dto.ts
@@ -0,0 +1,15 @@
+import { z } from 'zod';
+
+import { UpdateApiKeyRequestDto } from './update-api-key-request.dto';
+
+const isTimeNullOrInFuture = (value: number | null) => {
+ if (!value) return true;
+ return value > Date.now() / 1000;
+};
+
+export class CreateApiKeyRequestDto extends UpdateApiKeyRequestDto.extend({
+ expiresAt: z
+ .number()
+ .nullable()
+ .refine(isTimeNullOrInFuture, { message: 'Expiration date must be in the future or null' }),
+}) {}
diff --git a/packages/@n8n/api-types/src/dto/api-keys/create-or-update-api-key-request.dto.ts b/packages/@n8n/api-types/src/dto/api-keys/update-api-key-request.dto.ts
similarity index 78%
rename from packages/@n8n/api-types/src/dto/api-keys/create-or-update-api-key-request.dto.ts
rename to packages/@n8n/api-types/src/dto/api-keys/update-api-key-request.dto.ts
index 168c28c2fa..9cb1b73fa5 100644
--- a/packages/@n8n/api-types/src/dto/api-keys/create-or-update-api-key-request.dto.ts
+++ b/packages/@n8n/api-types/src/dto/api-keys/update-api-key-request.dto.ts
@@ -8,6 +8,6 @@ const xssCheck = (value: string) =>
whiteList: {},
});
-export class CreateOrUpdateApiKeyRequestDto extends Z.class({
+export class UpdateApiKeyRequestDto extends Z.class({
label: z.string().max(50).min(1).refine(xssCheck),
}) {}
diff --git a/packages/@n8n/api-types/src/dto/index.ts b/packages/@n8n/api-types/src/dto/index.ts
index 3c6db394c2..ad695f0bb2 100644
--- a/packages/@n8n/api-types/src/dto/index.ts
+++ b/packages/@n8n/api-types/src/dto/index.ts
@@ -49,4 +49,5 @@ export { ManualRunQueryDto } from './workflows/manual-run-query.dto';
export { CreateOrUpdateTagRequestDto } from './tag/create-or-update-tag-request.dto';
export { RetrieveTagQueryDto } from './tag/retrieve-tag-query.dto';
-export { CreateOrUpdateApiKeyRequestDto } from './api-keys/create-or-update-api-key-request.dto';
+export { UpdateApiKeyRequestDto } from './api-keys/update-api-key-request.dto';
+export { CreateApiKeyRequestDto } from './api-keys/create-api-key-request.dto';
diff --git a/packages/cli/src/controllers/__tests__/api-keys.controller.test.ts b/packages/cli/src/controllers/__tests__/api-keys.controller.test.ts
index aaa530a39b..eb13081b48 100644
--- a/packages/cli/src/controllers/__tests__/api-keys.controller.test.ts
+++ b/packages/cli/src/controllers/__tests__/api-keys.controller.test.ts
@@ -79,7 +79,9 @@ describe('ApiKeysController', () => {
updatedAt: new Date(),
} as ApiKey;
- publicApiKeyService.getRedactedApiKeysForUser.mockResolvedValue([apiKeyData]);
+ publicApiKeyService.getRedactedApiKeysForUser.mockResolvedValue([
+ { ...apiKeyData, expiresAt: null },
+ ]);
// Act
@@ -87,7 +89,7 @@ describe('ApiKeysController', () => {
// Assert
- expect(apiKeys).toEqual([apiKeyData]);
+ expect(apiKeys).toEqual([{ ...apiKeyData, expiresAt: null }]);
expect(publicApiKeyService.getRedactedApiKeysForUser).toHaveBeenCalledWith(
expect.objectContaining({ id: req.user.id }),
);
diff --git a/packages/cli/src/controllers/api-keys.controller.ts b/packages/cli/src/controllers/api-keys.controller.ts
index 17ed524b82..e2a824068a 100644
--- a/packages/cli/src/controllers/api-keys.controller.ts
+++ b/packages/cli/src/controllers/api-keys.controller.ts
@@ -1,4 +1,4 @@
-import { CreateOrUpdateApiKeyRequestDto } from '@n8n/api-types';
+import { CreateApiKeyRequestDto, UpdateApiKeyRequestDto } from '@n8n/api-types';
import type { RequestHandler } from 'express';
import { ApiKeyRepository } from '@/databases/repositories/api-key.repository';
@@ -34,7 +34,7 @@ export class ApiKeysController {
async createAPIKey(
req: AuthenticatedRequest,
_res: Response,
- @Body payload: CreateOrUpdateApiKeyRequestDto,
+ @Body { label, expiresAt }: CreateApiKeyRequestDto,
) {
const currentNumberOfApiKeys = await this.apiKeysRepository.countBy({ userId: req.user.id });
@@ -43,7 +43,8 @@ export class ApiKeysController {
}
const newApiKey = await this.publicApiKeyService.createPublicApiKeyForUser(req.user, {
- label: payload.label,
+ label,
+ expiresAt,
});
this.eventService.emit('public-api-key-created', { user: req.user, publicApi: false });
@@ -52,6 +53,7 @@ export class ApiKeysController {
...newApiKey,
apiKey: this.publicApiKeyService.redactApiKey(newApiKey.apiKey),
rawApiKey: newApiKey.apiKey,
+ expiresAt,
};
}
@@ -84,10 +86,10 @@ export class ApiKeysController {
req: AuthenticatedRequest,
_res: Response,
@Param('id') apiKeyId: string,
- @Body payload: CreateOrUpdateApiKeyRequestDto,
+ @Body { label }: UpdateApiKeyRequestDto,
) {
await this.publicApiKeyService.updateApiKeyForUser(req.user, apiKeyId, {
- label: payload.label,
+ label,
});
return { success: true };
diff --git a/packages/cli/src/services/public-api-key.service.ts b/packages/cli/src/services/public-api-key.service.ts
index f2e43c3181..719f922fb2 100644
--- a/packages/cli/src/services/public-api-key.service.ts
+++ b/packages/cli/src/services/public-api-key.service.ts
@@ -1,4 +1,7 @@
+import type { UnixTimestamp, UpdateApiKeyRequestDto } from '@n8n/api-types';
+import type { CreateApiKeyRequestDto } from '@n8n/api-types/src/dto/api-keys/create-api-key-request.dto';
import { Service } from '@n8n/di';
+import { TokenExpiredError } from 'jsonwebtoken';
import type { OpenAPIV3 } from 'openapi-types';
import { ApiKey } from '@/databases/entities/api-key';
@@ -28,15 +31,14 @@ export class PublicApiKeyService {
* Creates a new public API key for the specified user.
* @param user - The user for whom the API key is being created.
*/
- async createPublicApiKeyForUser(user: User, { label }: { label: string }) {
- const apiKey = this.generateApiKey(user);
- await this.apiKeyRepository.upsert(
+ async createPublicApiKeyForUser(user: User, { label, expiresAt }: CreateApiKeyRequestDto) {
+ const apiKey = this.generateApiKey(user, expiresAt);
+ await this.apiKeyRepository.insert(
this.apiKeyRepository.create({
userId: user.id,
apiKey,
label,
}),
- ['apiKey'],
);
return await this.apiKeyRepository.findOneByOrFail({ apiKey });
@@ -45,13 +47,13 @@ export class PublicApiKeyService {
/**
* Retrieves and redacts API keys for a given user.
* @param user - The user for whom to retrieve and redact API keys.
- * @returns A promise that resolves to an array of objects containing redacted API keys.
*/
async getRedactedApiKeysForUser(user: User) {
const apiKeys = await this.apiKeyRepository.findBy({ userId: user.id });
return apiKeys.map((apiKeyRecord) => ({
...apiKeyRecord,
apiKey: this.redactApiKey(apiKeyRecord.apiKey),
+ expiresAt: this.getApiKeyExpiration(apiKeyRecord.apiKey),
}));
}
@@ -59,7 +61,7 @@ export class PublicApiKeyService {
await this.apiKeyRepository.delete({ userId: user.id, id: apiKeyId });
}
- async updateApiKeyForUser(user: User, apiKeyId: string, { label }: { label?: string } = {}) {
+ async updateApiKeyForUser(user: User, apiKeyId: string, { label }: UpdateApiKeyRequestDto) {
await this.apiKeyRepository.update({ id: apiKeyId, userId: user.id }, { label });
}
@@ -105,6 +107,16 @@ export class PublicApiKeyService {
if (!user) return false;
+ try {
+ this.jwtService.verify(providedApiKey, {
+ issuer: API_KEY_ISSUER,
+ audience: API_KEY_AUDIENCE,
+ });
+ } catch (e) {
+ if (e instanceof TokenExpiredError) return false;
+ throw e;
+ }
+
this.eventService.emit('public-api-invoked', {
userId: user.id,
path: req.path,
@@ -118,6 +130,17 @@ export class PublicApiKeyService {
};
}
- private generateApiKey = (user: User) =>
- this.jwtService.sign({ sub: user.id, iss: API_KEY_ISSUER, aud: API_KEY_AUDIENCE });
+ private generateApiKey = (user: User, expiresAt: UnixTimestamp) => {
+ const nowInSeconds = Math.floor(Date.now() / 1000);
+
+ return this.jwtService.sign(
+ { sub: user.id, iss: API_KEY_ISSUER, aud: API_KEY_AUDIENCE },
+ { ...(expiresAt && { expiresIn: expiresAt - nowInSeconds }) },
+ );
+ };
+
+ private getApiKeyExpiration = (apiKey: string) => {
+ const decoded = this.jwtService.decode(apiKey);
+ return decoded?.exp ?? null;
+ };
}
diff --git a/packages/cli/test/integration/api-keys.api.test.ts b/packages/cli/test/integration/api-keys.api.test.ts
index e1649d4b0b..0f0dbf4e9e 100644
--- a/packages/cli/test/integration/api-keys.api.test.ts
+++ b/packages/cli/test/integration/api-keys.api.test.ts
@@ -4,6 +4,7 @@ import { Container } from '@n8n/di';
import type { User } from '@/databases/entities/user';
import { ApiKeyRepository } from '@/databases/repositories/api-key.repository';
+import { License } from '@/license';
import { PublicApiKeyService } from '@/services/public-api-key.service';
import { mockInstance } from '@test/mocking';
@@ -13,6 +14,10 @@ import * as testDb from './shared/test-db';
import type { SuperAgentTest } from './shared/types';
import * as utils from './shared/utils/';
+const license = mockInstance(License);
+
+license.getApiKeysPerUserLimit.mockImplementation(() => 2);
+
const testServer = utils.setupTestServer({ endpointGroups: ['apiKeys'] });
let publicApiKeyService: PublicApiKeyService;
@@ -56,11 +61,11 @@ describe('Owner shell', () => {
ownerShell = await createUserShell('global:owner');
});
- test('POST /api-keys should create an api key', async () => {
+ test('POST /api-keys should create an api key with no expiration', async () => {
const newApiKeyResponse = await testServer
.authAgentFor(ownerShell)
.post('/api-keys')
- .send({ label: 'My API Key' });
+ .send({ label: 'My API Key', expiresAt: null });
const newApiKey = newApiKeyResponse.body.data as ApiKeyWithRawValue;
@@ -79,6 +84,39 @@ describe('Owner shell', () => {
createdAt: expect.any(Date),
updatedAt: expect.any(Date),
});
+
+ expect(newApiKey.expiresAt).toBeNull();
+ expect(newApiKey.rawApiKey).toBeDefined();
+ });
+
+ test('POST /api-keys should create an api key with expiration', async () => {
+ const expiresAt = Date.now() + 1000;
+
+ const newApiKeyResponse = await testServer
+ .authAgentFor(ownerShell)
+ .post('/api-keys')
+ .send({ label: 'My API Key', expiresAt });
+
+ const newApiKey = newApiKeyResponse.body.data as ApiKeyWithRawValue;
+
+ expect(newApiKeyResponse.statusCode).toBe(200);
+ expect(newApiKey).toBeDefined();
+
+ const newStoredApiKey = await Container.get(ApiKeyRepository).findOneByOrFail({
+ userId: ownerShell.id,
+ });
+
+ expect(newStoredApiKey).toEqual({
+ id: expect.any(String),
+ label: 'My API Key',
+ userId: ownerShell.id,
+ apiKey: newApiKey.rawApiKey,
+ createdAt: expect.any(Date),
+ updatedAt: expect.any(Date),
+ });
+
+ expect(newApiKey.expiresAt).toBe(expiresAt);
+ expect(newApiKey.rawApiKey).toBeDefined();
});
test('POST /api-keys should fail if max number of API keys reached', async () => {
@@ -93,24 +131,40 @@ describe('Owner shell', () => {
});
test('GET /api-keys should fetch the api key redacted', async () => {
- const newApiKeyResponse = await testServer
+ const expirationDateInTheFuture = Date.now() + 1000;
+
+ const apiKeyWithNoExpiration = await testServer
.authAgentFor(ownerShell)
.post('/api-keys')
- .send({ label: 'My API Key' });
+ .send({ label: 'My API Key', expiresAt: null });
+
+ const apiKeyWithExpiration = await testServer
+ .authAgentFor(ownerShell)
+ .post('/api-keys')
+ .send({ label: 'My API Key 2', expiresAt: expirationDateInTheFuture });
const retrieveAllApiKeysResponse = await testServer.authAgentFor(ownerShell).get('/api-keys');
expect(retrieveAllApiKeysResponse.statusCode).toBe(200);
- const redactedApiKey = publicApiKeyService.redactApiKey(newApiKeyResponse.body.data.rawApiKey);
-
- expect(retrieveAllApiKeysResponse.body.data[0]).toEqual({
- id: newApiKeyResponse.body.data.id,
- label: 'My API Key',
+ expect(retrieveAllApiKeysResponse.body.data[1]).toEqual({
+ id: apiKeyWithExpiration.body.data.id,
+ label: 'My API Key 2',
userId: ownerShell.id,
- apiKey: redactedApiKey,
+ apiKey: publicApiKeyService.redactApiKey(apiKeyWithExpiration.body.data.rawApiKey),
createdAt: expect.any(String),
updatedAt: expect.any(String),
+ expiresAt: expirationDateInTheFuture,
+ });
+
+ expect(retrieveAllApiKeysResponse.body.data[0]).toEqual({
+ id: apiKeyWithNoExpiration.body.data.id,
+ label: 'My API Key',
+ userId: ownerShell.id,
+ apiKey: publicApiKeyService.redactApiKey(apiKeyWithNoExpiration.body.data.rawApiKey),
+ createdAt: expect.any(String),
+ updatedAt: expect.any(String),
+ expiresAt: null,
});
});
@@ -118,7 +172,7 @@ describe('Owner shell', () => {
const newApiKeyResponse = await testServer
.authAgentFor(ownerShell)
.post('/api-keys')
- .send({ label: 'My API Key' });
+ .send({ label: 'My API Key', expiresAt: null });
const deleteApiKeyResponse = await testServer
.authAgentFor(ownerShell)
@@ -143,11 +197,11 @@ describe('Member', () => {
await utils.setInstanceOwnerSetUp(true);
});
- test('POST /api-keys should create an api key', async () => {
+ test('POST /api-keys should create an api key with no expiration', async () => {
const newApiKeyResponse = await testServer
.authAgentFor(member)
.post('/api-keys')
- .send({ label: 'My API Key' });
+ .send({ label: 'My API Key', expiresAt: null });
expect(newApiKeyResponse.statusCode).toBe(200);
expect(newApiKeyResponse.body.data.apiKey).toBeDefined();
@@ -165,6 +219,39 @@ describe('Member', () => {
createdAt: expect.any(Date),
updatedAt: expect.any(Date),
});
+
+ expect(newApiKeyResponse.body.data.expiresAt).toBeNull();
+ expect(newApiKeyResponse.body.data.rawApiKey).toBeDefined();
+ });
+
+ test('POST /api-keys should create an api key with expiration', async () => {
+ const expiresAt = Date.now() + 1000;
+
+ const newApiKeyResponse = await testServer
+ .authAgentFor(member)
+ .post('/api-keys')
+ .send({ label: 'My API Key', expiresAt });
+
+ const newApiKey = newApiKeyResponse.body.data as ApiKeyWithRawValue;
+
+ expect(newApiKeyResponse.statusCode).toBe(200);
+ expect(newApiKey).toBeDefined();
+
+ const newStoredApiKey = await Container.get(ApiKeyRepository).findOneByOrFail({
+ userId: member.id,
+ });
+
+ expect(newStoredApiKey).toEqual({
+ id: expect.any(String),
+ label: 'My API Key',
+ userId: member.id,
+ apiKey: newApiKey.rawApiKey,
+ createdAt: expect.any(Date),
+ updatedAt: expect.any(Date),
+ });
+
+ expect(newApiKey.expiresAt).toBe(expiresAt);
+ expect(newApiKey.rawApiKey).toBeDefined();
});
test('POST /api-keys should fail if max number of API keys reached', async () => {
@@ -179,36 +266,48 @@ describe('Member', () => {
});
test('GET /api-keys should fetch the api key redacted', async () => {
- const newApiKeyResponse = await testServer
+ const expirationDateInTheFuture = Date.now() + 1000;
+
+ const apiKeyWithNoExpiration = await testServer
.authAgentFor(member)
.post('/api-keys')
- .send({ label: 'My API Key' });
+ .send({ label: 'My API Key', expiresAt: null });
+
+ const apiKeyWithExpiration = await testServer
+ .authAgentFor(member)
+ .post('/api-keys')
+ .send({ label: 'My API Key 2', expiresAt: expirationDateInTheFuture });
const retrieveAllApiKeysResponse = await testServer.authAgentFor(member).get('/api-keys');
expect(retrieveAllApiKeysResponse.statusCode).toBe(200);
- const redactedApiKey = publicApiKeyService.redactApiKey(newApiKeyResponse.body.data.rawApiKey);
-
- expect(retrieveAllApiKeysResponse.body.data[0]).toEqual({
- id: newApiKeyResponse.body.data.id,
- label: 'My API Key',
+ expect(retrieveAllApiKeysResponse.body.data[1]).toEqual({
+ id: apiKeyWithExpiration.body.data.id,
+ label: 'My API Key 2',
userId: member.id,
- apiKey: redactedApiKey,
+ apiKey: publicApiKeyService.redactApiKey(apiKeyWithExpiration.body.data.rawApiKey),
createdAt: expect.any(String),
updatedAt: expect.any(String),
+ expiresAt: expirationDateInTheFuture,
});
- expect(newApiKeyResponse.body.data.rawApiKey).not.toEqual(
- retrieveAllApiKeysResponse.body.data[0].apiKey,
- );
+ expect(retrieveAllApiKeysResponse.body.data[0]).toEqual({
+ id: apiKeyWithNoExpiration.body.data.id,
+ label: 'My API Key',
+ userId: member.id,
+ apiKey: publicApiKeyService.redactApiKey(apiKeyWithNoExpiration.body.data.rawApiKey),
+ createdAt: expect.any(String),
+ updatedAt: expect.any(String),
+ expiresAt: null,
+ });
});
test('DELETE /api-keys/:id should delete the api key', async () => {
const newApiKeyResponse = await testServer
.authAgentFor(member)
.post('/api-keys')
- .send({ label: 'My API Key' });
+ .send({ label: 'My API Key', expiresAt: null });
const deleteApiKeyResponse = await testServer
.authAgentFor(member)
diff --git a/packages/cli/test/integration/shared/db/users.ts b/packages/cli/test/integration/shared/db/users.ts
index 88751fd727..af0cf99820 100644
--- a/packages/cli/test/integration/shared/db/users.ts
+++ b/packages/cli/test/integration/shared/db/users.ts
@@ -83,6 +83,7 @@ export async function createUserWithMfaEnabled(
export const addApiKey = async (user: User) => {
return await Container.get(PublicApiKeyService).createPublicApiKeyForUser(user, {
label: randomName(),
+ expiresAt: null,
});
};
diff --git a/packages/editor-ui/src/api/api-keys.ts b/packages/editor-ui/src/api/api-keys.ts
index 5ea2f593b7..c9af96f136 100644
--- a/packages/editor-ui/src/api/api-keys.ts
+++ b/packages/editor-ui/src/api/api-keys.ts
@@ -1,6 +1,11 @@
import type { IRestApiContext } from '@/Interface';
import { makeRestApiRequest } from '@/utils/apiUtils';
-import type { CreateOrUpdateApiKeyRequestDto, ApiKey, ApiKeyWithRawValue } from '@n8n/api-types';
+import type {
+ CreateApiKeyRequestDto,
+ UpdateApiKeyRequestDto,
+ ApiKey,
+ ApiKeyWithRawValue,
+} from '@n8n/api-types';
export async function getApiKeys(context: IRestApiContext): Promise