Single-Sign-On mit Keycloak und Cordova

Anmelden in hybriden Apps

Photo by James Sutton on Unsplash

Wenn es ums Anmelden im Internet geht, ist heute fast immer OAuth im Spiel. OAuth ist die Technologie hinter den „Login mit Google/Facebook/Twitter“-Buttons, und selbst wenn eine Webanwendung eine eigene Nutzerverwaltung verwendet, ist sie immer öfter das Mittel der Wahl. Macht Sinn, denn Benutzer schätzen es, bequem zwischen Webseiten ohne lästiges Anmelden hin-und-her-navigieren zu können.

Wenn es aber um Apps geht, tun sich viele noch schwer — vielleicht auch, weil die Unterstützung durch die Bibliotheken und Frameworks fehlt. In meinem Fall schlummerte die Umsetzung als Ticket im Issue-Tracker von Keycloak, dem OAuth-Server meiner Wahl. Glücklicherweise ist der Open-Source, also Ärmel hoch und ran!

OAuth mit Keycloak

Keycloak ist ein Open-Source OAuth-Server und wird von Red Hat vorangetrieben. Neben dem eigentlichen Server gehört auch eine große Zahl von Adaptern zum Projekt, mit denen sich Login und Registrierung in die eigene Anwendung integrieren lassen. Hier steht Java im Vordergrund, es gibt aber auch Adapter für Node.js, Javascript, oder (ganz generisch) einen HTTP-Proxy. Da Keycloak für die Integration auf den Internet-Standard OpenID-Connect setzt, gibt es zahlreiche weitere Bibliotheken für jede erdenkliche andere Plattform (C#, Python, iOS/Android…).

Hybride-Apps mit Cordova

Neben nativen Apps erfreuen sich hybride-Apps großer Beliebtheit: sie sind eigentlich Webanwendungen, die in einem als App verpackten Browser ablaufen. Technologien wie Cordova erlauben ihnen, auf Gerätefunktionen wie die Kamera, GPS oder Notifications zuzugreifen, sodass sie sich wie „echte“ Apps anfühlen. Entwickler schätzen, dass sie Know-How und leibgewonnene Bibliotheken aus Webframeworks wie Angular auch für die Appentwicklung, und denselben Code für Android und iOS nutzen können. Allerdings können native Bibliotheken nicht ohne weiteres genutzt werden.

Keycloak unterstützt Cordova über den JavaScript-Adapter. Hierfür verwendet es das Cordova-Plugin „InAppBrowser“, welches die Login-Seite in einem eigenen Browser-Fenster öffnet. Da die Webanwendung selbst schon ein Browser ist und die Login-Seite nicht im gewohnten Systembrowser lädt, fühlt sich das manchmal komisch an — die Seite ruckelt beim Scrollen, die Sprache passt nicht, und gespeicherte Zugangsdaten stehen nicht zu Verfügung. Auch aus Sicherheitsaspekten ist diese Lösung nicht optimal — eine Kernidee hinter OAuth ist, dass die Anwendungen nicht an die Zugangsdaten der Benutzer kommen, da diese nur am Authentifizierungsserver eingegeben — wenn der Browser Teil der App ist, ist dieser Schutzmechanismus ausgehebelt.

Daher wäre es schöner, wenn die App die Anmeldung über den Systembrowser abwickeln würde, der danach wieder in die App weiterleitet.

Auth-Flow

Der Auth-Flow sollte wie folgt aussehen: über die App wird der Login ausgelöst. Dabei öffnet sich die Login-Seite im Systembrowser. Hier authentifiziert sich der Benutzer und anschließend leitet ihn Keycloak zurück in die App weiter. Beim Open-ID Code-Flow generiert der Auth-Server nach einem Login einen Code, den es der App bei der Weiterleitung übergibt. Damit kann die App den Login abschließen, und sich die passenden Zugangstokens vom Auth-Server holen.

App Authentication-Flow

Cordova Browsertab

Zum Öffnen von Seiten im Systembrowser gibt in Android und iOS passende APIs (Chrome Custom Tabs auf Android, SFSafariViewController auf iOS). Für Cordova gibt es ein passendes Plugin, das diese APIs für Hybride-Apps bereitstellt: Cordova-plugin-browsertab. Es ersetzt damit die etwas wacklige Browser-In-Browser-Lösung mit dem InAppBrowser. Schritt 1 geschafft!

Universal Links

Damit der Auth-Server direkt in eine App weiterleiten kann, muss diese über eine URL aufrufbar sein. Hier gibt es zwei Varianten:

  • custom-urls wie z.B. meineapp://login: hier registriert die App auf dem gerät ein eigenes URL-Schema
  • oder universal-links (auch „deeplinks“) wie z.B: https://cofinpro.de/app/login. Das sind reguläre Webseiten, die auch im Browser aufgerufen werden können. Die App registriert sich jedoch als Handler für diese URLs sodass der Browser weiß, dass diese Seite mit der App geöffnet werden soll.

Custom-URLs sind einfach und funkionieren zuverlässig, werden aber seit iOS 9 nicht mehr unterstützt. Das Problem: jede App kann die URL-Schemas beliebig registrieren, sodass mehrere Apps auf meineapp://login hören — im Falle einer Anmeldung sehr schlecht, da dadurch die Zugangsdaten in falsche Hände gelangen können.

Universal-Links sind an die Domain gebunden (hier cofinpro.de), wodurch nur der Domain-Inhaber sie nutzen kann. Um sicherzustellen, dass die App diese Domain verwenden darf, muss eine spezielle Datei auf der Webseite hinterlegt werden, welche das Betriebssystem bei der Installation der App prüft.

Hier sieht es in der Cordova-Welt ein bisschen düster aus: Zwar gibt es einige Plugins zur Auswahl, die meisten unterstützen aber entweder nur custom-urls, oder funktionieren nicht mit neueren Cordova-Versionen. Das offizielle Cordova-Plugin hierfür ist seit geraumer Zeit eingestellt. Damit bleiben eigentlich nur zwei Kandidaten übrig:

Das hinterlässt erstmal einen Beigeschmack, auch da demnächst wieder Anpassungen für iOS notwendig werden — aber grundsätzlich gibt es ein Plugin, mit dem wir weitermachen können.

Keycloak-Adapter

Nun bleibt noch der Keycloak-JS-Adapter. Bisher wird dort für Cordova der InAppBrowser verwendet — allerdings ist der Adapter so aufgebaut, dass sich alternative Verfahren als Plugin nachrüsten lassen. Daher habe ich einen solchen geschrieben, der auf den beiden oben erwähnten Plugins aufbaut: cordova-native . Der passende Pull-Request ist mittlerweile gemerged und wird offizieller Bestandteil von Keycloak 4.2.0 sein. Wer neugierig ist, kann schonmal einen Blick in die Dokumentation werfen.

Bestehende Apps lassen sich recht leicht umrüsten. Im Wesentlichen läuft es hierauf hinaus:

  1. Plugin installieren und einrichten
  2. Adapter beim Initialisieren auswählen.
  3. Redirect-URLs anpassen
  4. die Domains oder Custom-URLs konfigurieren

Der letzte Schritt ist vermutlich der schwerste — die Links zu registrieren kann schwierig sein. Hier sollte insbesondere die Anleitung in der Readme des Universal-Links-Plugins genau befolgt werden.

Für noch mehr Starthilfe gibt es im Keycloak-Repository ein kleines Beispielprojekt.

Ergebnis

Bei Keycloak gibt es damit ein offenes Ticket weniger, und der „ordentlichen“ OAuth-Integration eurer App steht nichts mehr im Weg. Der neue Adapter eröffnet auch neue Möglichkeiten, wie z.B. Magic-Links, wie ihr sie vielleicht von Slack kennt: man bekommt einen Link per Email und per Klick ist man eingeloggt.

Ein anderes Szenario zeigt Stian Thorgersen in einem Screencast: Singe-Sign-On über mehrere Apps

Single-Sign-On über mehrere Apps hinweg

Nur das etwas wacklige Plugin für Universal Links in Cordova macht nicht 100% glücklich, und die nächsten Änderungen stehen schon vor der Tür — mit iOS 11 und 12 kommen neue Privacy-Einstellungen, die Anpassungen an den Plugins erfordern. Vielleicht müssen wir da ja nochmal ran…