feat: rotate api key

This commit is contained in:
Nevo David 2026-02-17 10:05:12 +07:00
parent f7f5899d01
commit 13104962c6
2 changed files with 33 additions and 0 deletions

View file

@ -140,6 +140,12 @@ export class UsersController {
return this._userService.updateEmailNotifications(user.id, body);
}
@Post('/api-key/rotate')
@CheckPolicies([AuthorizationActions.Create, Sections.ADMIN])
async rotateApiKey(@GetOrgFromRequest() organization: Organization) {
return this._orgService.updateApiKey(organization.id);
}
@Get('/subscription')
@CheckPolicies([AuthorizationActions.Create, Sections.ADMIN])
async getSubscription(@GetOrgFromRequest() organization: Organization) {

View file

@ -1,16 +1,22 @@
'use client';
import { useState, useCallback } from 'react';
import { useSWRConfig } from 'swr';
import { useUser } from '../layout/user.context';
import { Button } from '@gitroom/react/form/button';
import copy from 'copy-to-clipboard';
import { useToaster } from '@gitroom/react/toaster/toaster';
import { useVariables } from '@gitroom/react/helpers/variable.context';
import { useT } from '@gitroom/react/translation/get.transation.service.client';
import { useFetch } from '@gitroom/helpers/utils/custom.fetch';
import { useDecisionModal } from '@gitroom/frontend/components/layout/new-modal';
export const PublicComponent = () => {
const user = useUser();
const { backendUrl, frontEndUrl } = useVariables();
const toaster = useToaster();
const fetch = useFetch();
const decision = useDecisionModal();
const { mutate } = useSWRConfig();
const [reveal, setReveal] = useState(false);
const [reveal2, setReveal2] = useState(false);
const copyToClipboard = useCallback(() => {
@ -22,6 +28,22 @@ export const PublicComponent = () => {
copy(`${backendUrl}/mcp/` + user?.publicApi);
}, [user]);
const rotateKey = useCallback(async () => {
const approved = await decision.open({
title: 'Rotate API Key?',
description:
'This will generate a new API key and invalidate the current one. Any integrations using the old key will stop working.',
approveLabel: 'Rotate',
cancelLabel: 'Cancel',
});
if (!approved) return;
await fetch('/user/api-key/rotate', { method: 'POST' });
await mutate('/user/self');
setReveal(false);
setReveal2(false);
toaster.show('API Key rotated successfully', 'success');
}, [decision, fetch, mutate, toaster]);
const t = useT();
if (!user || !user.publicApi) {
@ -80,6 +102,11 @@ export const PublicComponent = () => {
)}
</div>
</div>
<div>
<Button onClick={rotateKey}>
{t('rotate_key', 'Rotate Key')}
</Button>
</div>
</div>
</div>