diff --git a/src/main/java/net/siegeln/cameleer/saas/identity/LogtoManagementClient.java b/src/main/java/net/siegeln/cameleer/saas/identity/LogtoManagementClient.java index 79806fc..26a91f4 100644 --- a/src/main/java/net/siegeln/cameleer/saas/identity/LogtoManagementClient.java +++ b/src/main/java/net/siegeln/cameleer/saas/identity/LogtoManagementClient.java @@ -604,6 +604,47 @@ public class LogtoManagementClient { } } + /** List WebAuthn credentials for a user (filtered from all MFA verifications). */ + @SuppressWarnings("unchecked") + public List> getWebAuthnCredentials(String userId) { + var all = getUserMfaVerifications(userId); + return all.stream() + .filter(v -> "WebAuthn".equals(String.valueOf(v.get("type")))) + .toList(); + } + + /** Rename a WebAuthn credential. Uses PATCH on the MFA verification. */ + public void renameMfaVerification(String userId, String verificationId, String name) { + if (!isAvailable()) return; + try { + restClient.patch() + .uri(config.getLogtoEndpoint() + "/api/users/" + userId + "/mfa-verifications/" + verificationId) + .header("Authorization", "Bearer " + getAccessToken()) + .contentType(MediaType.APPLICATION_JSON) + .body(Map.of("name", name)) + .retrieve() + .toBodilessEntity(); + } catch (Exception e) { + log.warn("Failed to rename MFA verification {} for user {}: {}", verificationId, userId, e.getMessage()); + } + } + + /** Update user custom data (partial merge). Used for mfa_method_preference. */ + public void updateUserCustomData(String userId, Map customData) { + if (!isAvailable()) return; + try { + restClient.patch() + .uri(config.getLogtoEndpoint() + "/api/users/" + userId + "/custom-data") + .header("Authorization", "Bearer " + getAccessToken()) + .contentType(MediaType.APPLICATION_JSON) + .body(customData) + .retrieve() + .toBodilessEntity(); + } catch (Exception e) { + log.warn("Failed to update custom data for user {}: {}", userId, e.getMessage()); + } + } + /** Update a user's profile fields (e.g. name). */ public void updateUserProfile(String userId, Map profile) { if (!isAvailable()) throw new IllegalStateException("Logto not configured");