Keycloak Workflows: Inaktive Benutzer automatisch benachrichtigen, deaktivieren und löschen
September 22, 2026
Tags: #keycloak #workflows #iga #lifecycle-management #identity-governance
Benutzerkonten anzulegen ist einfach. Sie wieder loszuwerden, wenn sie niemand mehr braucht, ist es nicht. In vielen Umgebungen sammeln sich über die Jahre Konten an, die seit Monaten oder Jahren niemand mehr benutzt hat. Jedes dieser Konten ist ein potenzielles Einfallstor, und das Aufräumen bleibt meist an einem Admin hängen, der es “irgendwann mal” von Hand macht. Oder eben nicht.
Keycloak bringt mit den Workflows ein Feature mit, das genau solche Aufgaben automatisiert. In diesem Artikel zeige ich, was hinter dem Begriff IGA steckt, wie ein Workflow aufgebaut ist und wie ich damit inaktive Benutzer erst per Mail informiere, dann deaktiviere und schließlich lösche.
Was ist IGA?
IGA steht für Identity Governance and Administration. Gemeint ist ein Zusammenspiel aus Richtlinien, Prozessen und Technik, mit dem eine Organisation ihre Benutzerkonten verwaltet und steuert, wer worauf Zugriff hat.
Zwei Bereiche gehören dazu:
- Administration, also das Lifecycle Management: Konten anlegen, ändern und wieder entfernen.
- Governance, also z. B. regelmäßige Überprüfungen und Bestätigungen von Zugriffsrechten (Access Certification).
Für die Workflows in Keycloak ist der erste Teil der entscheidende: den Lebenszyklus der Benutzer in der eigenen Umgebung im Griff zu haben, und zwar automatisiert.
Workflows in Keycloak: ein kurzer Rückblick
Die Workflows kamen mit Keycloak 26.4 als experimentelles Feature. Mit 26.5 wurden sie zum Preview-Feature, mit 26.6 dann offiziell supported. Dieser Artikel basiert auf Version 26.7.
Wer tiefer einsteigen möchte, findet zwei gute Quellen:
- den Blogpost “Automating Administrative Tasks with Workflows in Keycloak 26.4 (experimental)” vom Oktober 2025, mit dem das Feature vorgestellt wurde,
- das Kapitel Managing workflows im Server Administration Guide, das alle Konfigurationsmöglichkeiten im Detail beschreibt.
Workflows in der Admin Console
In der Admin Console sind die Workflows der letzte Eintrag im linken Menü. Das Feature ist standardmäßig aktiviert, ich muss es also nicht erst über ein Feature-Flag einschalten. In einem neuen Realm ist die Liste natürlich leer.
Wer nach einem Klick auf Create workflow einen grafischen Editor mit Kästchen und Pfeilen erwartet, wird enttäuscht. Der Workflow-Editor ist schlicht ein Textfeld, in das ich eine Definition in YAML eintrage.
Eine kleine Randnotiz, weil ich es einfach witzig finde: Die UI wandelt das YAML in JSON um und schickt es an den Server. Der Server serialisiert das JSON zu einem String und speichert diesen in der Datenbank. Auf dem Rückweg liest der Server den String, macht daraus wieder ein Objekt, schickt es als JSON an die UI, und die UI wandelt es wieder in YAML um. Passend dazu steht über dem Feld “Workflow YAML” in der Oberfläche auch “Create a new workflow by providing its JSON representation”.
Anatomie eines Workflows
Mein Beispiel ist aus meiner Sicht der interessanteste Anwendungsfall: Benutzer, die sich eine gewisse Zeit lang nicht angemeldet haben, sollen erst informiert, dann deaktiviert und schließlich gelöscht werden.
Die vollständige Definition sieht so aus:
name: Disable inactive users
enabled: true
on: user_authenticated
concurrency:
restart-in-progress: "true"
if: has-identity-provider-link(oidc)
steps:
- uses: notify-user
after: 20s
with:
subject: Please be aware of this!
message: If you don't login again in the next time, your account will be deleted!
- uses: disable-user
after: 20s
- uses: delete-user
after: 20s
Schauen wir uns die einzelnen Teile an.
name und enabled
name ist einfach der Name des Workflows, unter dem er in der Übersicht auftaucht.
enabled: true sorgt dafür, dass der Workflow direkt nach dem Speichern aktiv ist.
Das Flag kann ich auch weglassen, denn ohne Angabe ist ein Workflow standardmäßig aktiviert.
on: das auslösende Ereignis
Mit on lege ich fest, auf welches Ereignis der Workflow reagiert.
In meinem Fall ist das user_authenticated, also die erfolgreiche Anmeldung eines Benutzers.
Hier steckt ein wichtiger Punkt, den man verstanden haben muss: Ein Workflow läuft nach dem Anlegen nicht sofort für alle Benutzer im Realm los. Er wird erst gestartet, wenn das definierte Ereignis eintritt, und dann genau für den Benutzer, der das Ereignis ausgelöst hat. Solange sich niemand anmeldet, passiert also nichts.
if: die Bedingung
Mit if schränke ich ein, für welche Benutzer der Workflow überhaupt gilt.
In meinem Beispiel sollen das nur Benutzer sein, die über einen bestimmten externen Identity Provider kommen:
if: has-identity-provider-link(oidc)
oidc ist dabei der Alias der Identity-Provider-Konfiguration in meinem Realm.
So kann ich den Workflow exakt auf die Benutzer dieses einen IdPs zuschneiden.
Daneben gibt es weitere Bedingungen, z. B. ob ein Benutzer ein bestimmtes Attribut hat, Mitglied einer Gruppe ist oder eine Rolle zugewiesen bekommen hat.
Lasse ich if komplett weg, gilt der Workflow für alle Benutzer, die das Ereignis auslösen.
steps: die Schrittkette
Unter steps definiere ich die Schritte, die nacheinander ausgeführt werden, optional mit einer zeitlichen Verzögerung.
Jeder Schritt besteht aus:
uses: dem Namen des Schritts,after: der Zeitspanne, nach der der Schritt ausgeführt wird, gerechnet ab dem vorherigen Schritt,with: optionalen Parametern als Key-Value-Paare.
In meinem Beispiel heißt das:
notify-user: 20 Sekunden nach der Anmeldung bekommt der Benutzer eine Mail mit dem Hinweis, dass sein Konto gelöscht wird, wenn er sich nicht demnächst wieder anmeldet. Mitsubjectsetze ich einen eigenen Betreff. Ohnesubjectverwendet Keycloak den Standard-Betreff “Account Disable Warning”.disable-user: 20 Sekunden nach der Mail wird der Benutzer deaktiviert.delete-user: Weitere 20 Sekunden später wird der Benutzer gelöscht.
Die 20 Sekunden sind natürlich nur für die Demo gewählt, ich möchte im Video ja nicht mehrere Tage warten. In Produktion reden wir hier eher über Tage oder Wochen als über Sekunden.
Für den Versand der Mail muss im Realm natürlich ein SMTP-Server konfiguriert sein.
concurrency: was passiert, wenn der Benutzer sich wieder anmeldet?
Bleibt noch dieser Teil:
concurrency:
restart-in-progress: "true"
Er regelt, was passiert, wenn das auslösende Ereignis erneut eintritt, während der Workflow für diesen Benutzer noch läuft.
Mit restart-in-progress: "true" beginnt der Workflow dann wieder von vorne.
Für mein Szenario ist genau das gewünscht: Bekommt ein Benutzer die Info-Mail und meldet sich daraufhin wieder an, wird er nicht 20 Sekunden später deaktiviert. Stattdessen startet der Workflow neu, und der Benutzer bekommt erst nach Ablauf der ersten Frist wieder eine Mail. Die Anmeldung setzt die “Inaktivitätsuhr” also zurück.
Ist der Benutzer allerdings bereits deaktiviert, kann er sich nicht mehr anmelden und den Workflow damit auch nicht mehr selbst zurücksetzen. Die Zeit zwischen Deaktivieren und Löschen ist das Zeitfenster, in dem ein Admin noch eingreifen, den Benutzer wieder aktivieren und den aktiven Workflow löschen kann.
Vorsicht mit delete-user
delete-user bedeutet wirklich löschen.
Der Benutzer wird nicht in einen Status “gelöscht” versetzt, sondern aus der Datenbank entfernt.
Er ist danach nicht mehr verfügbar.
Diesen Schritt sollte man also mit Bedacht und mit ausreichend großzügigen Fristen einsetzen.
Speichern und Bearbeiten
Nach einem Klick auf Create erscheint der Workflow in der Übersicht und ist aktiv. Über den Namen komme ich jederzeit wieder in die Definition und kann sie bearbeiten.
Der Workflow in Aktion
Mein Testbenutzer jane.doe kommt aus einem externen Identity Provider mit dem Alias oidc.
Vor dem ersten Login existiert er in Keycloak noch nicht, eine Suche nach “doe” in den Benutzern liefert also kein Ergebnis.
Nach der Anmeldung über den externen IdP legt Keycloak den Benutzer an, und das Ereignis user_authenticated startet den Workflow für jane.doe.
Das sehe ich in den Benutzerdetails im Tab Workflows:
Dort steht der Workflow “Disable inactive users” mit dem nächsten Schritt und darunter alle Schritte mit dem Zeitpunkt, zu dem sie geplant sind.
Nach 20 Sekunden ist notify-user erledigt, der nächste Schritt ist disable-user.
Im Postfach liegt die Mail mit meinem eigenen Betreff “Please be aware of this!” und dem Text aus der Workflow-Definition.
Zum Vergleich: Eine Mail aus einem früheren Test ohne subject kommt mit dem Standard-Betreff “Account Disable Warning”.
Weitere 20 Sekunden später ist jane.doe deaktiviert und kann sich nicht mehr anmelden.
Der Benutzer existiert aber noch, der nächste Schritt ist delete-user.
Nach noch einmal 20 Sekunden ist der Benutzer weg. Ein Reload der Benutzerdetails endet mit der Fehlermeldung “user not found”, und auch die Suche nach “doe” findet niemanden mehr.
Der Neustart bei erneutem Login
Im zweiten Durchlauf melde ich mich wieder mit jane.doe an.
Nachdem die Info-Mail angekommen ist und als nächster Schritt disable-user ansteht, melde ich mich noch einmal an.
Durch restart-in-progress wird der laufende Workflow zurückgesetzt, und als nächster Schritt steht wieder notify-user an, 20 Sekunden später kommt erneut eine Mail.
Lasse ich den Benutzer danach in Ruhe, läuft der Workflow wie gehabt bis zum Deaktivieren und Löschen durch.
Zur Gegenprobe ein Blick auf meinen regulären Benutzer dasniko:
Der hat sich seit dem Anlegen des Workflows nicht angemeldet, im Tab Workflows steht deshalb auch nichts.
Der Workflow startet eben nur über das Ereignis, das ich in der Definition festgelegt habe.
Was Workflows sonst noch können
Mein Beispiel deckt nur einen kleinen Teil ab. Die Dokumentation beschreibt alle Möglichkeiten im Detail, hier die wichtigsten im Überblick.
Ereignisse
Neben user_authenticated stehen weitere Ereignisse zur Verfügung:
| Ereignis | Wann | Parameter |
|---|---|---|
user_created |
Benutzer wird im Realm angelegt | – |
user_authenticated |
Benutzer meldet sich am Realm an | Client-ID des Clients, über den die Anmeldung erfolgt |
user_federated_identity_added |
Benutzer wird föderiert bzw. mit einem IdP verknüpft | Alias des Identity Providers |
user_federated_identity_removed |
Verknüpfung mit einem IdP wird entfernt | Alias des Identity Providers |
user_role_granted |
Benutzer bekommt eine Rolle | Rollenname |
user_role_revoked |
Rolle wird entzogen | Rollenname |
user_group_membership_added |
Benutzer tritt einer Gruppe bei | Gruppenname oder -pfad |
user_group_membership_removed |
Benutzer wird aus einer Gruppe entfernt | Gruppenname oder -pfad |
client_created |
Client wird im Realm angelegt | – |
client_authenticated |
Client authentifiziert sich (z. B. Client Credentials Grant) | – |
Ereignisse sind Funktionen in einem Ausdruck und können deshalb Parameter haben. Ein Workflow, der nur beim Beitritt zu einer bestimmten Gruppe startet, sieht z. B. so aus:
on: user_group_membership_added(/mygroup)
Damit könnte ich einem Benutzer etwa eine Mail schicken, sobald er einer neuen Gruppe hinzugefügt wurde.
Mehrere Ereignisse lassen sich auch logisch verknüpfen:
on: user_created or user_authenticated
Zeitgesteuerte Workflows
Statt auf ein Ereignis zu reagieren, kann ein Workflow auch periodisch laufen.
Dafür gibt es die Einstellung schedule:
name: Track inactive users
schedule:
after: 5s
batch-size: 100
after gibt das Intervall zwischen zwei Läufen an, batch-size die maximale Anzahl an Realm-Ressourcen, die pro Lauf verarbeitet werden.
Bei jedem Lauf sucht die Workflow-Engine nach den Ressourcen, auf die die Bedingung zutrifft, und startet für sie den Workflow.
Ohne Bedingung gilt das für alle Ressourcen.
Das ist auch die Antwort auf eine naheliegende Frage zu meinem Beispiel:
Ein ereignisbasierter Workflow erfasst nur Benutzer, die das Ereignis auslösen.
Wer sich nach dem Anlegen des Workflows nie wieder anmeldet, bekommt von einem user_authenticated-Workflow nichts mit, denn ein Ereignis für “hat sich nicht angemeldet” gibt es nicht.
Mit schedule kann ich dagegen auch Benutzer erfassen und bearbeiten, für die gar kein Ereignis eintritt.
Bedingungen
Für if stehen u. a. diese Bedingungen zur Verfügung:
has-user-attribute: Der Benutzer hat ein bestimmtes Attribut, optional mit einem bestimmten Wert.has-role: Der Benutzer hat eine bestimmte Rolle.has-identity-provider-link: Der Benutzer ist mit einem Identity Provider verknüpft (Parameter: Alias).is-member-of: Der Benutzer ist Mitglied einer bestimmten Gruppe (Parameter: Name oder Pfad).
Schritte
Die eingebauten Schritte beziehen sich jeweils auf die Ressource, die mit dem Ereignis verknüpft ist. Für Benutzer gibt es:
add-required-action/remove-required-action: Required Action hinzufügen oder entfernen. Wird ein Benutzer z. B. einer Gruppe hinzugefügt, kann ich ihm damit automatisch eine Required Action zuweisen.grant-role/revoke-role: eine oder mehrere Rollen zuweisen oder entziehenjoin-group/leave-group: einer oder mehreren Gruppen hinzufügen oder daraus entfernenset-user-attribute/remove-user-attribute: Attribute setzen oder entfernennotify-user: Mail an den Benutzer, mitsubject,messageund optionaltoals Empfänger; ohnetogeht die Mail an den Benutzer selbstunlink-user: Verknüpfung zu einem oder mehreren externen Identity Providern entfernendisable-user/delete-user: Benutzer deaktivieren bzw. löschen
Für Clients gibt es entsprechend disable-client und delete-client zum Deaktivieren und Löschen.
Sofortige und geplante Schritte
after akzeptiert Zeitangaben in Millisekunden, Sekunden, Minuten, Stunden oder Tagen, also z. B. 20s oder 7d.
Lasse ich after weg, wird der Schritt sofort ausgeführt.
Hier laufen beide Schritte direkt nacheinander:
steps:
- uses: notify-user
- uses: disable-user
Und hier wird der Benutzer sieben Tage nach der Benachrichtigung deaktiviert:
steps:
- uses: notify-user
- uses: disable-user
after: 7d
Ausgeführt werden die Schritte von der Workflow-Engine asynchron und losgelöst von dem Request, der den Workflow ausgelöst hat. Eine Anmeldung wird also nicht dadurch langsamer, dass im Hintergrund ein Workflow startet.
Fazit
Workflows sind ein einfaches, aber wirkungsvolles Werkzeug, um den Lebenszyklus von Benutzern in Keycloak zu automatisieren. Ereignis, Bedingung, Schrittkette: Mehr braucht es nicht, um Aufgaben zu erledigen, die sonst manuell und damit oft gar nicht passieren.
Mein Tipp: Lest das Kapitel in der Dokumentation in Ruhe durch, spielt mit den Ereignissen, Bedingungen und Schritten in einer Testumgebung und konfiguriert dann die Workflows, die zu eurer Umgebung passen. Und haltet eure Keycloak-Installation aktuell, das Feature entwickelt sich gerade noch weiter.
Alle Schritte aus diesem Artikel zeige ich auch im Video auf meinem YouTube-Kanal.
Wenn ihr Workflows oder andere Aspekte des Identity Lifecycle Managements mit Keycloak in eurer Organisation einführen wollt, unterstütze ich euch gerne mit Beratung und Trainings.
Du bist auf der Suche nach Keycloak Beratung, Unterstützung, Workshops oder Trainings?
Nimm Kontakt mit mir auf!« Delegated User Management with Keycloak: Fine-Grained Admin Permissions (FGAP v2) in Practice Keycloak Workflows: Automatically Notify, Disable and Delete Inactive Users »