Keycloak: Passkey Auto-Login mit Passwort-Fallback
Keycloak 25.x Passkey-Login beschleunigen ohne die Passwort-Option zu verlieren. Theme-Override mit sessionStorage für den perfekten Kompromiss.
- Das Problem
- Die Lösung: sessionStorage-Flag
- Voraussetzungen
- Das Theme-Override
- Wie es funktioniert
- Deployment
- Testen
- Alternative Ansätze
- Keycloak 26.3+ : Conditional UI
- Troubleshooting
- Zusammenfassung
- Weiterführende Links
Passkeys sind die Zukunft der Authentifizierung: Kein Passwort merken, kein Phishing möglich, ein Fingerabdruck oder Face-ID und du bist drin. Aber was wenn der Hardware-Key gerade nicht griffbereit ist? Oder der Bluetooth-Dongle spinnt? Dann willst du auf Passwort-Login zurückfallen können — und genau hier hat Keycloak 25.x ein UX-Problem.
Das Problem#
Keycloak 25.x zeigt bei Usern mit registriertem Passkey eine Authenticator-Auswahl:
- Passkey (WebAuthn)
- Passwort
Um den Login-Flow zu beschleunigen, implementieren viele Admins ein Theme-Override das automatisch die Passkey-Option wählt. Das funktioniert — bis der User den Passkey-Dialog abbricht (ESC, “Abbrechen”, Hardware-Key nicht zur Hand).
Das Ergebnis: Der User landet wieder auf der Auswahl-Seite, aber das JavaScript klickt sofort wieder Passkey an. Eine Endlosschleife ohne Ausweg zum Passwort-Login.
Die Lösung: sessionStorage-Flag#
Wir nutzen sessionStorage, um zu merken ob der Auto-Select bereits einmal ausgeführt wurde. Beim zweiten Besuch der Seite (nach Abbruch) bleibt die Auswahl sichtbar.
Szenario Verhalten
Erster Login Passkey wird automatisch gewählt Nach Passkey-Abbruch Auswahl bleibt sichtbar, User kann Passwort wählen Neuer Browser-Tab Auto-Select wieder aktiv Browser geschlossen Auto-Select wieder aktiv
Voraussetzungen#
- Keycloak 25.x (getestet mit 25.0.6)
- Custom Theme mit Login-Overrides
- Authentication Flow mit Passkey + Password Alternative
Falls du noch kein Custom Theme hast, hier die minimale Struktur:
themes/
└── mytheme/
└── login/
├── theme.properties
└── select-authenticator.ftl
theme.properties:
parent=keycloak.v2
Das Theme-Override#
Erstelle oder bearbeite select-authenticator.ftl in deinem Theme:
<#import "template.ftl" as layout>
<@layout.registrationLayout displayInfo=false; section>
<#if section = "header" || section = "show-username">
<#if section = "header">
$
</#if>
<#elseif section = "form">
<form id="kc-select-credential-form" class="$" action="$" method="post">
<div class="$">
<#list auth.authenticationSelections as authenticationSelection>
<button class="$" type="submit"
name="authenticationExecution" value="$"
data-icon-css="$">
<div class="$">
<i class="$']!authenticationSelection.iconCssClass} $"></i>
</div>
<div class="$">
<div class="$">
$')}
</div>
<div class="$">
$')}
</div>
</div>
<div class="$"></div>
<div class="$">
<i class="$"></i>
</div>
</button>
</#list>
</div>
</form>
<script>
// Auto-select Passkey option to skip redundant method selector page.
// Only auto-select ONCE per session - if user returns (e.g. cancelled Passkey),
// they can manually choose Password.
(function() {
var STORAGE_KEY = 'kc-passkey-auto-selected';
// Check if we already auto-selected in this session
if (sessionStorage.getItem(STORAGE_KEY)) {
// User returned to this page - let them choose manually
return;
}
var buttons = document.querySelectorAll('#kc-select-credential-form button[name="authenticationExecution"]');
for (var i = 0; i < buttons.length; i++) {
var iconCss = buttons[i].getAttribute('data-icon-css') || '';
if (iconCss.indexOf('WebAuthn') !== -1 || iconCss.indexOf('Passkey') !== -1) {
// Mark that we auto-selected, so next visit shows the selector
sessionStorage.setItem(STORAGE_KEY, 'true');
buttons[i].click();
return;
}
}
})();
</script>
</#if>
</@layout.registrationLayout>
Wie es funktioniert#
Das JavaScript macht folgendes:
- Prüft sessionStorage auf das Flag
kc-passkey-auto-selected - Falls nicht gesetzt: Sucht den Passkey-Button anhand
data-icon-css, setzt das Flag, klickt den Button - Falls gesetzt: Tut nichts — User sieht die Auswahl und kann manuell wählen
Warum sessionStorage statt localStorage?#
- localStorage würde das Flag permanent speichern — User müssten immer manuell wählen
- sessionStorage ist tab-spezifisch und wird beim Schließen gelöscht — perfekte Balance
Deployment#
# Theme-Dateien auf Server kopieren
scp -r themes/mytheme/login/* root@keycloak-server:/path/to/themes/mytheme/login/
# Keycloak restarten (Theme-Cache leeren!)
ssh root@keycloak-server "cd /path/to/keycloak && docker compose restart keycloak"
Wichtig: Keycloak cached Themes aggressiv. Ohne Restart siehst du keine Änderungen.
Testen#
- Login mit Passkey-Account → Passkey-Dialog sollte automatisch erscheinen
- Passkey abbrechen (ESC oder “Abbrechen”)
- Du landest auf der Auswahl → Jetzt kannst du “Passwort” wählen
- Neuer Tab öffnen → Auto-Select wieder aktiv
Alternative Ansätze#
Option A: Kein Auto-Select#
Einfachste Lösung: Das JavaScript komplett weglassen. User müssen immer klicken, haben aber volle Kontrolle.
Pro: Keine Überraschungen Contra: Ein Klick mehr für Passkey-User
Option B: Timeout mit Abbruch-Möglichkeit#
Auto-Select nach 2-3 Sekunden mit sichtbarem Countdown. User kann während des Countdowns “Passwort” wählen.
Pro: Visuelles Feedback Contra: Komplexer, langsamer
Option C: URL-Parameter#
?method=password in der URL überspringt Auto-Select. Nützlich für Bookmarks.
if (window.location.search.indexOf('method=password') !== -1) {
return; // Kein Auto-Select
}
Keycloak 26.3+ : Conditional UI#
Ab Keycloak 26.3 ist das Problem nativ gelöst durch “Conditional UI” — der Browser fragt automatisch nach verfügbaren Passkeys ohne dass Keycloak einen Zwischenschritt zeigt.
Wenn du auf 26.3+ upgradest, kannst du die Theme-Overrides entfernen und die native Implementierung nutzen.
Troubleshooting#
Auto-Select funktioniert nicht#
- Browser-DevTools öffnen (F12)
- Console prüfen auf JavaScript-Fehler
- Network-Tab: Wird
select-authenticator.ftlgeladen? - Keycloak restartet? Theme-Cache ist hartnäckig
User bleibt in Endlosschleife#
- sessionStorage wird nicht gesetzt → JavaScript-Fehler prüfen
- Falsches Template wird geladen → Theme-Zuordnung in Realm-Settings prüfen
Passkey-Dialog erscheint zweimal#
Das ist ein anderes Keycloak 25.x Problem. Dafür brauchst du zusätzlich ein Override für webauthn-authenticate.ftl das den Dialog automatisch triggert.
Zusammenfassung#
Mit diesem sessionStorage-Trick bekommst du das Beste aus beiden Welten:
- Passkey-User: Schneller Login ohne extra Klicks
- Passwort-Fallback: Jederzeit verfügbar nach Passkey-Abbruch
- Neue Sessions: Auto-Select wieder aktiv
Ein kleines JavaScript-Snippet, großer UX-Gewinn.
Weiterführende Links#
- Keycloak WebAuthn Dokumentation
- WebAuthn Specification
- Passkeys.dev — Ressourcen für Passkey-Implementierung
Fragen oder Probleme? Schreib mir oder hinterlasse einen Kommentar!
Einige Links auf dieser Seite sind Affiliate-Links. Wenn du über diese Links einkaufst, erhalte ich eine kleine Provision — für dich ändert sich am Preis nichts. So unterstützt du diesen Blog und ermöglichst weitere kostenlose Tutorials. Danke!
[« Vorherige]
Die 15 besten Self-Hosted Dienste für dein Homelab (2026)