diff --git a/frontend/i18n/locales/fr.json b/frontend/i18n/locales/fr.json
index 859608b..b30adc6 100644
--- a/frontend/i18n/locales/fr.json
+++ b/frontend/i18n/locales/fr.json
@@ -393,7 +393,21 @@
"title": "Mon profil",
"changeAvatar": "Changer l'avatar",
"removeAvatar": "Supprimer l'avatar",
- "cropAvatar": "Recadrer l'avatar"
+ "cropAvatar": "Recadrer l'avatar",
+ "apiToken": {
+ "title": "Token API MCP",
+ "help": "Utilisé pour authentifier le serveur MCP HTTP (à coller dans le header Authorization: Bearer …). Ne pas partager.",
+ "label": "Token",
+ "empty": "Aucun token généré pour le moment.",
+ "generate": "Générer un token",
+ "regenerate": "Régénérer",
+ "copy": "Copier",
+ "copied": "Token copié dans le presse-papiers.",
+ "copyFailed": "Impossible de copier le token.",
+ "regenerated": "Nouveau token généré. L'ancien token est désormais invalide.",
+ "confirmTitle": "Régénérer le token MCP ?",
+ "confirmMessage": "L'ancien token sera immédiatement invalidé. Tous les clients MCP utilisant ce token devront être reconfigurés."
+ }
},
"bookstack": {
"settings": {
diff --git a/frontend/pages/profile.vue b/frontend/pages/profile.vue
index bb3b081..93ed090 100644
--- a/frontend/pages/profile.vue
+++ b/frontend/pages/profile.vue
@@ -37,6 +37,56 @@
+
+
+
{{ $t('profile.apiToken.title') }}
+
{{ $t('profile.apiToken.help') }}
+
+
+
+
+
{{ $t('profile.apiToken.empty') }}
+
+
+
+
+
+
+
+
+
+
+
{{ $t('profile.apiToken.confirmTitle') }}
+
+ {{ $t('profile.apiToken.confirmMessage') }}
+
+
+
+
+
+
+
+
diff --git a/frontend/services/api-token.ts b/frontend/services/api-token.ts
new file mode 100644
index 0000000..7a304de
--- /dev/null
+++ b/frontend/services/api-token.ts
@@ -0,0 +1,12 @@
+export function useApiTokenService() {
+ const api = useApi()
+
+ async function regenerate(): Promise {
+ const data = await api.post<{ apiToken: string }>('/me/regenerate-api-token', {}, {
+ toast: false,
+ })
+ return data.apiToken
+ }
+
+ return { regenerate }
+}
diff --git a/frontend/services/dto/user-data.ts b/frontend/services/dto/user-data.ts
index 987af19..bddd1d5 100644
--- a/frontend/services/dto/user-data.ts
+++ b/frontend/services/dto/user-data.ts
@@ -8,6 +8,7 @@ export type UserData = {
client?: { id: number; name: string } | null
allowedProjects?: Project[]
avatarUrl?: string | null
+ apiToken?: string | null
}
export type UserWrite = {
diff --git a/src/Controller/RegenerateApiTokenController.php b/src/Controller/RegenerateApiTokenController.php
new file mode 100644
index 0000000..ca209de
--- /dev/null
+++ b/src/Controller/RegenerateApiTokenController.php
@@ -0,0 +1,36 @@
+getUser();
+
+ $token = bin2hex(random_bytes(32));
+ $user->setApiToken($token);
+ $this->entityManager->flush();
+
+ return new JsonResponse(['apiToken' => $token]);
+ }
+}
diff --git a/src/Entity/User.php b/src/Entity/User.php
index c85b9cf..11067e0 100644
--- a/src/Entity/User.php
+++ b/src/Entity/User.php
@@ -70,6 +70,7 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
private ?DateTimeImmutable $createdAt = null;
#[ORM\Column(length: 64, unique: true, nullable: true)]
+ #[Groups(['me:read'])]
private ?string $apiToken = null;
#[ORM\Column(length: 255, nullable: true)]