From 06134d6e6797774aaa68f33a8173c39792b00f02 Mon Sep 17 00:00:00 2001 From: hsiegeln <37154749+hsiegeln@users.noreply.github.com> Date: Mon, 27 Apr 2026 22:53:05 +0200 Subject: [PATCH] fix: TOTP label includes org name, passkeys show device as default name - TOTP otpauth URI issuer changed from "Cameleer" to "Cameleer - " so authenticator apps display the organization name - Passkeys without a custom name now show parsed device info (e.g. "Chrome on Windows") instead of "Unnamed passkey" Co-Authored-By: Claude Opus 4.6 (1M context) --- .../cameleer/saas/account/AccountService.java | 16 +++++++++++++--- ui/src/components/account/PasskeySection.tsx | 4 ++-- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/main/java/net/siegeln/cameleer/saas/account/AccountService.java b/src/main/java/net/siegeln/cameleer/saas/account/AccountService.java index 669c621..3d27d08 100644 --- a/src/main/java/net/siegeln/cameleer/saas/account/AccountService.java +++ b/src/main/java/net/siegeln/cameleer/saas/account/AccountService.java @@ -114,10 +114,20 @@ public class AccountService { // The secret is only registered after the user verifies the 6-digit code. var user = logtoClient.getUser(userId); String email = user != null ? String.valueOf(user.getOrDefault("primaryEmail", "")) : ""; - String label = email.isBlank() ? userId : email; + String account = email.isBlank() ? userId : email; + + // Include org name in issuer so authenticator apps show "Cameleer - OrgName" + String issuer = "Cameleer"; + var orgs = logtoClient.getUserOrganizations(userId); + if (!orgs.isEmpty()) { + issuer = "Cameleer - " + orgs.getFirst().get("name"); + } + + String encodedIssuer = java.net.URLEncoder.encode(issuer, java.nio.charset.StandardCharsets.UTF_8); + String encodedAccount = java.net.URLEncoder.encode(account, java.nio.charset.StandardCharsets.UTF_8); String otpauthUri = String.format( - "otpauth://totp/Cameleer:%s?secret=%s&issuer=Cameleer&algorithm=SHA1&digits=6&period=30", - label, secret); + "otpauth://totp/%s:%s?secret=%s&issuer=%s&algorithm=SHA1&digits=6&period=30", + encodedIssuer, encodedAccount, secret, encodedIssuer); return new MfaSetupData(secret, otpauthUri); } diff --git a/ui/src/components/account/PasskeySection.tsx b/ui/src/components/account/PasskeySection.tsx index 26c9334..8aaa448 100644 --- a/ui/src/components/account/PasskeySection.tsx +++ b/ui/src/components/account/PasskeySection.tsx @@ -107,9 +107,9 @@ export function PasskeySection({ bare }: { bare?: boolean }) { ) : ( <> -
{pk.name || 'Unnamed passkey'}
+
{pk.name || parseAgent(pk.agent)}
- {parseAgent(pk.agent)} · Added {pk.createdAt ? new Date(pk.createdAt).toLocaleDateString() : 'unknown'} + Added {pk.createdAt ? new Date(pk.createdAt).toLocaleDateString() : 'unknown'}
)}