{"id":2559,"date":"2022-01-03T10:41:23","date_gmt":"2022-01-03T10:41:23","guid":{"rendered":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/?p=2559"},"modified":"2022-06-16T12:33:52","modified_gmt":"2022-06-16T12:33:52","slug":"oauth-in-single-page-apps","status":"publish","type":"post","link":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/oauth-in-single-page-apps\/","title":{"rendered":"OAuth in Single-Page-Apps"},"content":{"rendered":"\n<p>Ein gro\u00dfer Teil der Apps, die wir regelm\u00e4\u00dfig benutzen, stellen f\u00fcr verschiedene Benutzerinnen und Benutzer individuelle Daten und Dienste bereit und m\u00fcssen daher ihre Anwenderinnen und Anwender eindeutig identifizieren k\u00f6nnen.<\/p>\n\n\n\n<p>Die klassische Herangehensweise w\u00e4re es hier, ein Login-Formular zu bauen und mit einer eigenen Nutzerdatenbank zu verwalten, was jedoch einige Nachteile mit sich bringen kann. Dieser Artikel stellt die alternative Herangehensweise mit den Protokollen &#8222;OAuth&#8220; und &#8222;OpenID Connect&#8220; vor, die f\u00fcr den Zweck der sicheren Authentifizierung und Autorisierung entwickelt wurden.<\/p>\n\n\n\n<figure class=\"wp-block-image size-medium\"><img loading=\"lazy\" decoding=\"async\" width=\"600\" height=\"400\" src=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/12\/202112_OAuth_1-600x400.jpg\" alt=\"Symbol-Bild: L\u00e4chelnde Frau am Rechner loggt sich mit Zwei-Faktor-Authentifizierung ein\" class=\"wp-image-2783\" srcset=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/12\/202112_OAuth_1-600x400.jpg 600w, https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/12\/202112_OAuth_1-1024x683.jpg 1024w, https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/12\/202112_OAuth_1-768x512.jpg 768w, https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/12\/202112_OAuth_1-1536x1024.jpg 1536w, https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/12\/202112_OAuth_1-640x427.jpg 640w, https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/12\/202112_OAuth_1-1200x800.jpg 1200w, https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/12\/202112_OAuth_1.jpg 1920w\" sizes=\"auto, (max-width: 639px) 98vw, (max-width: 1199px) 64vw, 600px\" \/><\/figure>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Nachteile der klassischen Login-Formulare<\/strong><\/h2>\n\n\n\n<p>Die eingangs beschriebene, klassische Variante der User-Authentifizierung hat einige Nachteile:<\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Security<\/strong><\/h3>\n\n\n\n<p>Sicherheitskritische Funktionen selbst zu bauen, ist immer mit einem gewissen Risiko verbunden. Bei Passw\u00f6rtern reicht es beispielsweise nicht aus, einfach nur Hash-Werte abzuspeichern. Denn die Passw\u00f6rter m\u00fcssen selbst dann sicher sein, wenn der ung\u00fcnstigste Fall eintritt und die Datenbank in die H\u00e4nde von Hackern gelangt. Daf\u00fcr stehen spezielle Verfahren zur Verf\u00fcgung, jedoch m\u00fcssen diese eben auch richtig implementiert sein. Im Zweifel bietet es sich daher in aller Regel an, lieber auf etablierte und durch Expertinnen und Experten begutachtete freie Produkte zu setzen, als diese selbst nachzubauen.&nbsp;&nbsp;<\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Aufwand<\/strong><\/h3>\n\n\n\n<p>Mit einer einfachen Login-Maske ist es nicht getan. Auch weitere Prozesse wie Registrierung, Passwort \u00e4ndern, Passwort vergessen usw. m\u00fcssen bedacht und implementiert werden. Und nat\u00fcrlich gibt es auch hier Best Practices, beispielsweise hinsichtlich Usability, die beachtet werden sollten. Der Aufwand, um alle diese Aspekte in hoher Qualit\u00e4t umzusetzen, sollte nicht untersch\u00e4tzt werden.&nbsp;&nbsp;<\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Zwei-Faktor-Authentifizierung<\/strong><\/h3>\n\n\n\n<p>Um die Sicherheit weiter zu erh\u00f6hen, sollte den Usern die M\u00f6glichkeit gegeben werden, f\u00fcr den Login einen zweiten Faktor zu benutzen. Das kann z. B. ein Einmal-Code sein, der per SMS versandt oder durch eine Authenticator App generiert wird. Aber auch Hardware Token werden gern benutzt. Die Sicherheit wird dadurch enorm gesteigert, da es nun nicht mehr ausreicht, das Passwort zu erraten. Angreiferinnen und Angreifer m\u00fcssen stattdessen zus\u00e4tzlich im Besitz des Smartphones oder Hardware Token sein. Diese zus\u00e4tzlichen Sicherheitsfeatures selbst zu implementieren, ist aber nicht nur fehleranf\u00e4llig, sondern, siehe vorherigen Punkt, auch aufw\u00e4ndig.&nbsp;&nbsp;<\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Zentrale Account-Verwaltung<\/strong><\/h3>\n\n\n\n<p>Insbesondere im Firmenkontext ist es h\u00e4ufig eine wichtige Anforderung, dass die Account-Informationen aus einer zentralen Verwaltung (z. B. LDAP, Active-Directory) genutzt werden k\u00f6nnen. Wenn Mitarbeiterinnen und Mitarbeiter sowieso einen Firmen-Account haben, warum sollten sie dann f\u00fcr jede firmeninterne Anwendung einen zus\u00e4tzlichen Account mit (hoffentlich) individuellen Passwort anlegen? Die M\u00f6glichkeit f\u00fcr Single-Sign-On erh\u00f6ht zus\u00e4tzlich den Nutzerkomfort. Und auch au\u00dferhalb des Firmenkontexts m\u00f6chten viele eben nicht f\u00fcr jede App und jede Webseite einen eigenen Account anlegen und sich die Zugangsdaten merken, sondern nutzen lieber einen zentralen Identit\u00e4ts-Provider.<\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\"><strong><strong>&#8222;OAuth&#8220; und &#8222;OpenID Connect&#8220; als L\u00f6sungsansatz<\/strong><\/strong><\/h2>\n\n\n\n<p>Mit den Protokollen <strong>&#8222;OAuth&#8220;<\/strong> und <strong>&#8222;OpenID Connect&#8220;<\/strong> stehen zwei Protokolle bereit, die genau f\u00fcr diesen Zweck entwickelt wurden.<\/p>\n\n\n\n<p>Die tats\u00e4chliche Implementierung dieser Standards stellt in der Praxis dann aber meist doch eine gewisse H\u00fcrde dar, insbesondere wenn man das erste Mal mit diesen Verfahren in Ber\u00fchrung kommt. Dies liegt einerseits daran, dass die Abl\u00e4ufe eben doch etwas komplexer sind als ein simpler Abgleich mit einem gespeicherten Passwort-Hash. Ein anderer Grund d\u00fcrfte sein, dass die Standards mehrere Varianten (sogenannte Flows) vorsehen, die in unterschiedlichen Situationen zum Einsatz kommen. Als Neuling steht man schnell vor der Frage, welche Variante f\u00fcr die eigene Anwendung die beste ist und wie es dann ganz konkret umzusetzen ist. Die Antwort auf diese Frage ist insbesondere von der Art der Anwendung abh\u00e4ngig, d. h. ob es sich z. B. um eine native Mobile-App, eine klassische serverseitig gerenderte Web-Anwendung oder eine Single-Page-App handelt.<\/p>\n\n\n\n<p>In diesem Artikel wollen wir nicht zu sehr in die Tiefe der beiden Protokolle gehen (wer mehr \u00fcber OAuth und OpenID Connect lernen m\u00f6chte, dem sei dieser sehr gute Vortrag auf Youtube empfohlen: <a href=\"https:\/\/www.youtube.com\/watch?v=996OiexHze0\">https:\/\/www.youtube.com\/watch?v=996OiexHze0<\/a>).<\/p>\n\n\n\n<p>Stattdessen wollen wir einen konkreten Anwendungsfall herausgreifen, der bei uns in Projekten relativ h\u00e4ufig vorkommt: Wir bauen eine Single-Page-App (SPA), die statisch ausgeliefert wird. Das hei\u00dft, dass sich auf dem Server keine Frontend-Logik befindet, sondern lediglich JavaScript- und HTML-Dateien bereitgestellt werden. Stattdessen stellt der Server lediglich eine API zur Benutzung durch die SPA (und andere Clients) bereit, mit der sich Daten holen und Operationen ausf\u00fchren lassen. Diese API k\u00f6nnte mittels REST oder GraphQL implementiert sein.<br>Wie bei OAuth \u00fcblich, kommt hierbei ein separater Authentication-Service zum Einsatz, wir wollen daher die Benutzerverwaltung nicht selbst implementieren. Dies k\u00f6nnte z. B. ein Cloud-Anbieter sein oder eine selbst gehostete Software, beispielsweise der freie Open-Source-Authentication-Server &#8222;Keycloak&#8220;. Wichtig ist lediglich, dass der Authentication-Dienst OAuth2\/OpenID Connect &#8222;spricht&#8220;.<\/p>\n\n\n\n<p>Das spannende an dieser Konstellation ist, dass anders als bei einem serverseitig verarbeiteten Web-Frontend, die Authentifizierung zun\u00e4chst au\u00dferhalb der Einflusssph\u00e4re des Servers stattfindet (n\u00e4mlich rein clientseitig in der SPA bzw. im Browser des Nutzers). Die SPA muss anschlie\u00dfend aber Requests gegen die Server-API absenden, wobei der Server der Glaubw\u00fcrdigkeit der Requests zun\u00e4chst mal misstrauen und die Authentifizierung nochmal selbstst\u00e4ndig \u00fcberpr\u00fcfen muss.<\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Arbeiten mit OAuth: Implicit Flow und Authorization Code Flow<\/strong><\/h2>\n\n\n\n<p>Die OAuth-Spezifikation gibt mehrere Flows vor, f\u00fcr unseren Zweck wollen wir uns aber nur zwei genauer anschauen: Den sogenannten &#8222;Implicit Flow&#8220; und den &#8222;Authorization Code Flow&#8220;. Letztlich geht es bei beiden Varianten darum, dass der Auth Provider der Anwendung einen sogenannten &#8222;Access Token&#8220; ausstellt, den die Anwendung anschlie\u00dfend bei allen Requests an den API-Server mitschickt. Der API-Server wiederum kann anhand des Access Token die Authentizit\u00e4t des Requests feststellen. Die Flows unterscheiden sich lediglich darin, wie genau die Ausstellung des Access Token vonstattengeht.&nbsp;&nbsp;<\/p>\n\n\n\n<p>Der <strong>Implicit Flow<\/strong> war jahrelang die Empfehlung f\u00fcr den Einsatz in JavaScript-Anwendungen im Browser. Zun\u00e4chst leitet die Anwendung den User auf eine Login-Seite des Auth-Providers weiter. Nach erfolgtem Login leitet der Auth-Provider den Browser wieder auf die urspr\u00fcngliche Seite zur\u00fcck und \u00fcbergibt der Anwendung den Access Token als Teil der Response. Genau hier liegen aber auch die Probleme bei dieser Variante. \u00dcber verschiedene Wege ist es f\u00fcr einen Angreifer oder eine Angreiferin m\u00f6glich, an den Access Token zu gelangen, beispielsweise indem die Redirects manipuliert werden und damit der Access Token nicht mehr an die eigentliche App, sondern an den Angreifer oder die Angreiferin geschickt wird.&nbsp;&nbsp;<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"938\" height=\"504\" src=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/09\/202109_OAuth_1-e1632220461477.png\" alt=\"Schematische Abbildung eines Implicit Flow\" class=\"wp-image-2632\" srcset=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/09\/202109_OAuth_1-e1632220461477.png 938w, https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/09\/202109_OAuth_1-e1632220461477-600x322.png 600w, https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/09\/202109_OAuth_1-e1632220461477-768x413.png 768w, https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/09\/202109_OAuth_1-e1632220461477-640x344.png 640w\" sizes=\"auto, (max-width: 639px) 98vw, (max-width: 1199px) 64vw, 770px\" \/><figcaption><em>Abbildung 1: Implicit Flow<\/em><\/figcaption><\/figure>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Der Implicit Flow war von Anfang an eine Notl\u00f6sung f\u00fcr JavaScript-Anwendungen im Browser. Zum Zeitpunkt der Standardisierung gab es f\u00fcr Browser-Scripts keine M\u00f6glichkeit, Requests auf andere Server als den eigenen auszuf\u00fchren (sogenannte Same-Origin-Policy). Damit war die Ausf\u00fchrung des eigentlich besseren Authorization Code Flow nicht m\u00f6glich. In der Zwischenzeit wurde mit dem sogenannten CORS-Mechanismus (f\u00fcr Cross-Origin Resource Sharing) ein System eingef\u00fchrt, welches genau diese L\u00fccke schlie\u00dft und Requests auch auf andere Server erm\u00f6glicht, sofern diese den Zugriff erlauben.<\/p>\n\n\n\n<p>Beim <strong>Authorization Code Flow<\/strong> findet ebenfalls ein Redirect auf die Login-Seite des Auth Providers statt. Anstelle eines Access Token schickt der Auth Provider aber lediglich einen sogenannten &#8222;Authorization Code&#8220; an den Client. In einem separaten Request muss dieser Authorization Code zusammen mit der &#8222;Client ID&#8220; und dem &#8222;Client Secret&#8220; an den Auth Provider geschickt und gegen das Access Token eingetauscht werden. Die Client-ID kennzeichnet den Client (in unserem Fall die Single-Page-App) und erm\u00f6glicht dem Auth-Server, f\u00fcr verschiedene Clients verschiedene Regeln anzuwenden. Die Client-ID ist im Prinzip \u00f6ffentlich bekannt und taucht bei einigen Apps\/Diensten als Teil der URL auf.<\/p>\n\n\n\n<p>Das Client Secret dagegen ist ein geheimer Code, den nur dieser eine Client verwenden darf, um sich gegen\u00fcber dem Auth Server auszuweisen (wir kommen gleich noch einmal darauf zur\u00fcck). Der entscheidende Punkt ist hier, dass dieser zweite Request nicht als GET-Request sondern als POST-Request implementiert wird. Damit sind die \u00fcbermittelten Informationen nicht Teil der URL und sind mittels HTTPS (welches selbstverst\u00e4ndlich verwendet werden muss) vor den Blicken von Hackern gesch\u00fctzt.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"926\" height=\"506\" src=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/09\/202109_OAuth_2-e1632220499290.png\" alt=\"Schematische Abbildung eines Authorization Code Flow\" class=\"wp-image-2630\" srcset=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/09\/202109_OAuth_2-e1632220499290.png 926w, https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/09\/202109_OAuth_2-e1632220499290-600x328.png 600w, https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/09\/202109_OAuth_2-e1632220499290-768x420.png 768w, https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/09\/202109_OAuth_2-e1632220499290-640x350.png 640w\" sizes=\"auto, (max-width: 639px) 98vw, (max-width: 1199px) 64vw, 770px\" \/><figcaption><em>Abbildung 2: Authorization Code Flow<\/em><\/figcaption><\/figure>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Das Problem mit der browserbasierten Single-Page-App<\/strong><\/h2>\n\n\n\n<p>Eigentlich ist dieser Flow aber vor allem f\u00fcr serverseitig gerenderte Web-Anwendungen gedacht, so dass der Austausch des Authorization Codes gegen den Access Token auf dem Server stattfindet. In dem Fall kann insbesondere das Client Secret auf der Serverseite verbleiben und muss nicht an den Browser \u00fcbermittelt werden. Bei Single-Page-Apps muss aber der gesamte Prozess im Browser stattfinden und daher ben\u00f6tigt die App auch das Client Secret. Die Schwierigkeit ist somit, das Client Secret &#8222;geheim&#8220; zu halten. In der Praxis stellt sich dies als praktisch unm\u00f6glich heraus, denn letztlich muss das Client Secret als Teil des Anwendungscodes gebundelt und an den Browser ausgeliefert werden. Das Bundling bei modernen SPA-Frameworks produziert zwar unlesbaren JavaScript-Code, aber es bleibt eben JavaScript und ein Angreifer oder eine Angreiferin k\u00f6nnte sich diesen Code anschauen, das Client Secret extrahieren und damit die Anwendung kompromittieren. Die L\u00f6sung hierf\u00fcr lautet &#8222;PKCE&#8220;.&nbsp;&nbsp;<\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\"><strong><strong>Authorization Code Flow mit PKCE<\/strong><\/strong><\/h2>\n\n\n\n<p>PKCE steht f\u00fcr &#8222;Proof Key for Code Exchange&#8220; und ist eine Erweiterung des Authorization Code Flows. Hierbei wird auf das statische Client Secret verzichtet und stattdessen im Prinzip bei jedem Authentifizierungsvorgang ein neues Secret dynamisch generiert.<\/p>\n\n\n\n<p>Dazu wird ganz am Anfang ein sogenannter &#8222;Code Verifier&#8220; generiert. Dabei handelt es sich um eine Zeichenkette aus Zufallszahlen. Aus dem Code Verifier wird die &#8222;Code Challenge&#8220; berechnet, in dem der Code Verifier mit dem Hash-Verfahren SHA256 gehasht wird.<\/p>\n\n\n\n<p>Beim initialen Login-Vorgang zum Anfragen des Authorization Codes schickt die Anwendung die Code Challenge mit zum Auth Provider. Der Auth Provider merkt sich die Code Challenge und antwortet wie bisher mit dem Authorization Code.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"924\" height=\"504\" src=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/09\/202109_OAuth_3-e1632220439762.png\" alt=\"Schematische Abbildung eines Authorization Code Flow mit PKCE\" class=\"wp-image-2631\" srcset=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/09\/202109_OAuth_3-e1632220439762.png 924w, https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/09\/202109_OAuth_3-e1632220439762-600x327.png 600w, https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/09\/202109_OAuth_3-e1632220439762-768x419.png 768w, https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/09\/202109_OAuth_3-e1632220439762-640x349.png 640w\" sizes=\"auto, (max-width: 639px) 98vw, (max-width: 1199px) 64vw, 770px\" \/><figcaption><em>Abbildung 3: Authorization Code Flow mit PKCE<\/em><\/figcaption><\/figure>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Beim anschlie\u00dfenden Request f\u00fcr den Austausch des Authorization Codes gegen den Access Token schickt der Client nun den Code Verifier mit. Der Auth Provider kann nun pr\u00fcfen, ob der Code Verifier und die Code Challenge zusammenpassen, indem er seinerseits das Hashing mit SHA256 durchf\u00fchrt.<\/p>\n\n\n\n<p>Ein Angreifer kann bei diesem Verfahren nicht mehr das Client Secret extrahieren, da kein solches Client Secret mehr existiert. Von au\u00dfen k\u00f6nnte ein Angreifer oder eine Angreiferin h\u00f6chstens die Code Challenge abgreifen, da diese beim initialen Request \u00fcber einen Browser Redirect an den Auth Provider \u00fcbermittelt wird. Der Angreifer oder die Angreiferin hat aber keine Kenntnis vom Code Verifier und kann diesen auch nicht anhand der Code Challenge ableiten. Ohne den Code Verifier stellt der Auth Provider aber kein Access Token aus, womit ein Angreifer oder eine Angreiferin erfolgreich ausgesperrt ist.<\/p>\n\n\n\n<p>Urspr\u00fcnglich wurde das PKCE-Verfahren vor allem f\u00fcr native Mobile-Apps entwickelt, es lassen sich damit aber auch im Quellcode \u00f6ffentlich einsehbare Single-Page-Apps sicher umsetzen. Und nicht nur das: Mittlerweile wird das Verfahren sogar f\u00fcr weitere Anwendungsarten wie serverseitige Anwendungen empfohlen, f\u00fcr die bisher der normale Authorization Code Flow mit Client Secret vorgesehen war.<\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">PKCE im Detail&nbsp;&nbsp;<\/h2>\n\n\n\n<p>Da der Authorization Code Flow mit PKCE das Mittel der Wahl f\u00fcr Single-Page-Apps ist, wollen wir die einzelnen Schritte etwas genauer anschauen.<\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<ol class=\"wp-block-list\"><li>Code&nbsp;Verifier&nbsp;und Code&nbsp;Challenge&nbsp;&nbsp;<\/li><\/ol>\n\n\n\n<p>Zun\u00e4chst wird der Code&nbsp;Verifier&nbsp;und die Code&nbsp;Challenge berechnet:&nbsp;&nbsp;<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">const code_verifier = \"fkljl34l5jksdlf\" \/\/ generate random string\nconst code_challenge = sha256(code_verifier)<\/pre>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>In diesem und den folgenden Beispielen verwende ich verk\u00fcrzte Zufallswerte, um die einzelnen Schritte und Parameter besser darstellen zu k\u00f6nnen. In einer realen Anwendung m\u00fcssen hier nat\u00fcrlich echte Zufallswerte generiert werden.<\/p>\n\n\n\n<p>Zufallswerte im Security-Kontext sind aber ein eigenes Thema f\u00fcr sich und daher wollen wir an dieser Stelle nicht im Detail darauf eingehen, wie genau der Code Verifier generiert wird. Als Stichwort sei aber die relativ neue <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Web_Crypto_API\">Web-Crypto-API<\/a> genannt, die unter anderem Funktionen zur Generierung von sicheren Zufallszahlen bereitstellt. Auch f\u00fcr das Hashing mittels SHA256 stellt die Web-Crypto-API die <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/SubtleCrypto\/digest\">richtigen Hilfsmittel<\/a> bereit.&nbsp;&nbsp;<\/p>\n\n\n\n<ol class=\"wp-block-list\" start=\"2\"><li>Request Token&nbsp;&nbsp;<\/li><\/ol>\n\n\n\n<p>Nun wird ein Redirect bzw. GET-Request ausgef\u00fchrt, um den Authorization Code zu erhalten:&nbsp;&nbsp;<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">GET &lt;auth-server>\/openid-connect\/auth?\n&amp; response_type=code\n&amp; client_id=oauth-demo\n&amp; scope=openid\n&amp; state=hkjshkdwe\n&amp; redirect_uri=https:\/\/&lt;app-url>\/callback\n&amp; code_challenge=shkjhek34hk2lhkds\n&amp; code_challenge_method=S256<\/pre>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Dem Request werden die Code Challenge und die Methode, die zum Berechnen der Code Challenge benutzt wurde (in unserem Fall also SHA256), mitgegeben.&nbsp;&nbsp;<\/p>\n\n\n\n<p>Zus\u00e4tzlich wird noch ein sogenannter &#8222;State&#8220;-Parameter mitgegeben, der ebenfalls aus einem Zufallswert besteht. Auf diesen werden wir gleich noch genauer eingehen.<\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<ol class=\"wp-block-list\" start=\"3\"><li>Login und Redirect&nbsp;&nbsp;<\/li><\/ol>\n\n\n\n<p>Der Browser wird zur Login-Seite beim Auth Provider weitergeleitet, auf der sich die User einloggen und die App autorisieren k\u00f6nnen. Anschlie\u00dfend leitet der Auth Provider wieder zur App zur\u00fcck und nutzt daf\u00fcr den beim ersten Request \u00fcbergebenen &#8222;request_uri&#8220;-Parameter. In der Regel konfiguriert man im Auth Provider eine oder mehrere g\u00fcltige Redirect-URIs, um zu verhindern, dass ein Angreifer oder eine Angreiferin den Request manipuliert und eine gef\u00e4lschte Redirect-URI unterschieben will.<\/p>\n\n\n\n<p>Die Redirect-URI muss nat\u00fcrlich im Router der Single-Page-App konfiguriert sein und dort die Parameter entgegennehmen, die der Auth Provider dem Client mitteilen m\u00f6chte. Der Request dazu sieht in etwa so aus:&nbsp;&nbsp;<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">https:\/\/&lt;app-url>\/callback?\n&amp; code=jehrejkjhsad223ndskj2\n&amp; state=hkjshkdwe<\/pre>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Der Authorization Code ist ein Token, den wir im n\u00e4chsten Schritt gegen den eigentlichen Access Token eintauschen wollen (auch hier nochmal der Hinweis, dass ich zur vereinfachten Darstellung hier ausgedachte und verk\u00fcrzte Zufallswerte benutze. Ein echter Authorization Code sieht anders aus).<\/p>\n\n\n\n<p>Au\u00dferdem taucht wieder der State-Parameter auf. Diesen haben wir im vorherigen Schritt als Zufallswert generiert und dem Auth Provider mitgeschickt. Der Auth Provider schickt den State unver\u00e4ndert wieder zur\u00fcck. Auf diese Weise kann unsere Client App herausfinden, ob der Antwort-Request tats\u00e4chlich auf einen eigenen Token Request folgt oder nicht. Sollte ein Angreifer einen Token Request initiiert haben, w\u00e4re der dazugeh\u00f6rige State-Parameter bei der App unbekannt und der Request damit direkt als unsicher entlarvt. Dieses Verfahren sch\u00fctzt insbesondere gegen sogenannte CSRF-Attacken (Cross Site Request Forgery, weitergehende Erkl\u00e4rung u. a. hier: <a href=\"https:\/\/security.stackexchange.com\/questions\/20187\/oauth2-cross-site-request-forgery-and-stateparameter\">https:\/\/security.stackexchange.com\/questions\/20187\/oauth2-cross-site-request-forgery-and-stateparameter<\/a>).<\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<ol class=\"wp-block-list\" start=\"4\"><li>Exchange Code for Access&nbsp;Token&nbsp;&nbsp;<\/li><\/ol>\n\n\n\n<p>Nun k\u00f6nnen wir unseren Authorization Code gegen den eigentlichen Access Token austauschen. Dazu starten wir einen POST-Request:&nbsp;&nbsp;&nbsp;<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">POST &lt;auth-server>\/openid-connect\/auth\/token?\n&amp; grant_type=authorization_code\n&amp; code=jehrejkjhsad223ndskj2\n&amp; client_id=oauth-demo\n&amp; redirect_uri=https:\/\/&lt;app-url>\/callback\n&amp; code_verifier=fkljl34l5jksdlf<\/pre>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Als Parameter \u00fcbergeben wir u. a. den Authorization Code und den Code Verifier. Als Antwort erhalten wir nun endlich den Access Token, den wir anschlie\u00dfend f\u00fcr Requests gegen den API-Server verwenden k\u00f6nnen. Die Antwort sieht in etwa so aus:&nbsp;&nbsp;<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">HTTP\/1.1 200 OK\nContent-Type: application\/json\n{\n\"access_token\": \"&lt;jwt token>\",\n\"token_type\": \"bearer\",\n\"expires_in\": 3600,\n\"refresh_token\": \"&lt;jwt token>\",\n\"scope\": \"tasks\"\n}<\/pre>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Wir erhalten den Access Token und einige weitere Informationen zum Token.&nbsp;&nbsp;<\/p>\n\n\n\n<p>Wie sieht so ein Access Token genau aus? Als Format hat sich der <a href=\"https:\/\/jwt.io\/\">&#8222;JSON Web Token&#8220; Standard<\/a>, kurz JWT, etabliert. Dieser erm\u00f6glicht nicht nur den standardisierten Austausch von Authentication-\/Authorization-Daten, sondern auch die Verifizierung der Token. Zur Verifizierung steht dabei sowohl eine symmetrische als auch asymmetrische Verifikation zur Verf\u00fcgung. Damit kann unser API-Server die G\u00fcltigkeit der Access Token pr\u00fcfen, ohne den Auth Provider bei jedem Request kontaktieren zu m\u00fcssen.&nbsp;&nbsp;<\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>User-Freundlichkeit steigern mit dem Refresh Token<\/strong>&nbsp;&nbsp;<\/h2>\n\n\n\n<p>Ein weiterer Aspekt von OAuth sind sogenannte &#8222;Refresh Token&#8220;. Im vorherigen Beispiel haben wir einen solchen Token zusammen mit dem Access Token erhalten. Die Idee ist, die G\u00fcltigkeit von Access Token m\u00f6glichst kurz zu halten (im Bereich von einigen Minuten bis wenige Stunden). Nach Ablauf des Access Token muss dieser erneuert werden. Dies hat den Vorteil, dass eventuell kompromittierte Access Token nur begrenzten Schaden anrichten k\u00f6nnen. Au\u00dferdem haben User bei OAuth die M\u00f6glichkeit, ihre Autorisierung r\u00fcckg\u00e4ngig zu machen, d. h. beispielsweise die Berechtigung einer App, auf die eigenen Daten zugreifen zu d\u00fcrfen, beim Auth Provider wieder zu entziehen. Da zur Verifikation von Access Token auf Seiten des API-Servers aber keine Kommunikation mit dem Auth Provider vorgesehen ist, bekommt der API-Server von diesem Rechte-Entzug nichts mit.<\/p>\n\n\n\n<p>Sobald jedoch der alte Access Token abgelaufen ist und ein neuer besorgt werden muss, greifen die neuen Berechtigungen. Allerdings m\u00f6chte man aus Komfortgr\u00fcnden die eigenen Anwenderinnen und Anwender ungern alle paar Minuten erneut zum Einloggen auffordern. Aus diesem Grund \u00fcbermittelt der Auth Provider einen l\u00e4nger g\u00fcltigen Refresh Token. Dieser wird in der Client App gespeichert und bei Ablauf des Access Token benutzt, um sich bei beim Auth Provider einen neuen Access Token zu holen. Der Auth Provider fordert in diesem Fall keinen neuen Login vom Nutzer oder der Nutzerin. Sollte dieser aber zuvor die Berechtigungen f\u00fcr die App entzogen haben, stellt er keine neuen Access Token mehr aus. Wichtig ist: Der Refresh Token ist noch wertvoller als der Access Token und muss daher um jeden Preis vor dem Zugriff von unberechtigten Dritten gesch\u00fctzt werden!&nbsp;&nbsp;<\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Fazit&nbsp;&nbsp;<\/h2>\n\n\n\n<p>OAuth ist ein spannendes Protokoll, das die meisten Fragen rund um Authentifizierung und Autorisierung sicher l\u00f6sen kann. Allerdings ist das Thema nicht gerade einsteigerfreundlich und am Anfang k\u00f6nnen einen die vielen Begriffe und Abl\u00e4ufe schnell \u00fcberfordern.<\/p>\n\n\n\n<p>Hat man sich dann endlich in die Thematik eingedacht, stellt sich die Frage nach der Umsetzung. Insbesondere bei Single-Page-Anwendungen existieren im Netz noch viele Anleitungen, die auf den mittlerweile nicht mehr empfohlenen Implicit Flow verweisen. Mit PKCE steht aber eine Erweiterung bereit, die auch den besseren Authorization Code Flow f\u00fcr JavaScript-Anwendungen erm\u00f6glicht.<\/p>\n\n\n\n<p>Um die Umsetzung zu vereinfachen, existieren zahlreiche Bibliotheken. Zum einen bieten Cloud-Anbieter, die OAuth nutzen, h\u00e4ufig eigene Hilfsbibliotheken an. Empfehlenswert ist aber auch ein Blick auf die Bibliothek &#8222;OIDC-Client&#8220; (<a href=\"https:\/\/github.com\/IdentityModel\/oidc-client-js\">https:\/\/github.com\/IdentityModel\/oidc-client-js<\/a>), die eine anbieterunabh\u00e4ngige L\u00f6sung bietet. Neben dem reinen OAuth unterst\u00fctzt diese Bibliothek auch die Erweiterung &#8222;OpenID Connect&#8220;, die OAuth um Funktionen f\u00fcr User-Profile und Authentifizierung erg\u00e4nzt. Die Bibliothek abstrahiert zwar die einzelnen Schritte der OAuth Flows, so dass man sich nicht mehr mit den einzelnen Requests und deren Parametern &#8222;herumschlagen&#8220; muss. Ein gewisses Grundverst\u00e4ndnis der Abl\u00e4ufe ist aber dennoch n\u00fctzlich und hilft bei der sinnvollen Verwendung der Bibliothek.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Ein gro\u00dfer Teil der Apps, die wir regelm\u00e4\u00dfig benutzen, stellen f\u00fcr verschiedene Benutzerinnen und Benutzer individuelle Daten und Dienste bereit und m\u00fcssen daher ihre Anwenderinnen und Anwender eindeutig identifizieren k\u00f6nnen. Die klassische Herangehensweise w\u00e4re es hier, ein Login-Formular zu bauen und mit einer eigenen Nutzerdatenbank zu verwalten, was jedoch einige Nachteile mit sich bringen kann. Dieser Artikel stellt die alternative Herangehensweise mit den Protokollen &#8222;OAuth&#8220; und &#8222;OpenID Connect&#8220; vor, die f\u00fcr den Zweck der sicheren Authentifizierung und Autorisierung entwickelt wurden.<\/p>\n","protected":false},"author":18,"featured_media":2783,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"advgb_blocks_editor_width":"","advgb_blocks_columns_visual_guide":"","footnotes":""},"categories":[11],"tags":[607,608,609,680,681,570,602,603,606],"topics":[226],"class_list":["post-2559","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-web","tag-authorization-code-flow","tag-pkce","tag-login-formulare","tag-openid-connect","tag-zwei-faktor-authentifizierung","tag-zeiss-digital-innovation","tag-oauth","tag-single-page-app","tag-implicit-flow","topics-security"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v24.0 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>OAuth in Single-Page-Apps - ZEISS Digital Innovation Blog<\/title>\n<meta name=\"description\" content=\"Dieser Artikel zeigt, wie App-Nutzer mit den Protokollen &quot;OAuth&quot; und &quot;OpenID Connect&quot; sicher und eindeutig identifiziert werden k\u00f6nnen.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/oauth-in-single-page-apps\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"OAuth in Single-Page-Apps - ZEISS Digital Innovation Blog\" \/>\n<meta property=\"og:description\" content=\"Dieser Artikel zeigt, wie App-Nutzer mit den Protokollen &quot;OAuth&quot; und &quot;OpenID Connect&quot; sicher und eindeutig identifiziert werden k\u00f6nnen.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/oauth-in-single-page-apps\/\" \/>\n<meta property=\"og:site_name\" content=\"Digital Innovation Blog\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/ZEISSDigitalInnovation\/\" \/>\n<meta property=\"article:published_time\" content=\"2022-01-03T10:41:23+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2022-06-16T12:33:52+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/12\/202112_OAuth_1.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1920\" \/>\n\t<meta property=\"og:image:height\" content=\"1280\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Manuel Mauky\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:title\" content=\"OAuth in Single-Page-Apps - ZEISS Digital Innovation Blog\" \/>\n<meta name=\"twitter:description\" content=\"Dieser Artikel zeigt, wie App-Nutzer mit den Protokollen &quot;OAuth&quot; und &quot;OpenID Connect&quot; sicher und eindeutig identifiziert werden k\u00f6nnen.\" \/>\n<meta name=\"twitter:creator\" content=\"@ZEISS_di\" \/>\n<meta name=\"twitter:site\" content=\"@ZEISS_di\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"Manuel Mauky\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"17\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/oauth-in-single-page-apps\/\",\"url\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/oauth-in-single-page-apps\/\",\"name\":\"OAuth in Single-Page-Apps - ZEISS Digital Innovation Blog\",\"isPartOf\":{\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/oauth-in-single-page-apps\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/oauth-in-single-page-apps\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/12\/202112_OAuth_1.jpg\",\"datePublished\":\"2022-01-03T10:41:23+00:00\",\"dateModified\":\"2022-06-16T12:33:52+00:00\",\"author\":{\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/#\/schema\/person\/d7a29c5e55882a2841cfd79b4118132f\"},\"description\":\"Dieser Artikel zeigt, wie App-Nutzer mit den Protokollen \\\"OAuth\\\" und \\\"OpenID Connect\\\" sicher und eindeutig identifiziert werden k\u00f6nnen.\",\"breadcrumb\":{\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/oauth-in-single-page-apps\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/oauth-in-single-page-apps\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/oauth-in-single-page-apps\/#primaryimage\",\"url\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/12\/202112_OAuth_1.jpg\",\"contentUrl\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/12\/202112_OAuth_1.jpg\",\"width\":1920,\"height\":1280},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/oauth-in-single-page-apps\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"OAuth in Single-Page-Apps\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/#website\",\"url\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/\",\"name\":\"Digital Innovation Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"de\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/#\/schema\/person\/d7a29c5e55882a2841cfd79b4118132f\",\"name\":\"Manuel Mauky\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2024\/06\/Mauky_Manuel_Profilbild_300x300px-150x150.jpg\",\"contentUrl\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2024\/06\/Mauky_Manuel_Profilbild_300x300px-150x150.jpg\",\"caption\":\"Manuel Mauky\"},\"description\":\"Manuel arbeitet seit 2010 als Softwareentwickler bei der ZEISS Digital Innovation in G\u00f6rlitz. Neben Java besch\u00e4ftigt er sich vor allem mit JavaScript und TypeScript und der Entwicklung von modernen Webanwendungen. Au\u00dferdem interessiert er sich f\u00fcr Funktionale Programmierung und h\u00e4lt regelm\u00e4\u00dfig Vortr\u00e4ge zu diesen Themen. Manuel hat in G\u00f6rlitz Informatik studiert und organisiert die Java-User-Group G\u00f6rlitz.\",\"url\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/author\/manuelmauky\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"OAuth in Single-Page-Apps - ZEISS Digital Innovation Blog","description":"Dieser Artikel zeigt, wie App-Nutzer mit den Protokollen \"OAuth\" und \"OpenID Connect\" sicher und eindeutig identifiziert werden k\u00f6nnen.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/oauth-in-single-page-apps\/","og_locale":"de_DE","og_type":"article","og_title":"OAuth in Single-Page-Apps - ZEISS Digital Innovation Blog","og_description":"Dieser Artikel zeigt, wie App-Nutzer mit den Protokollen \"OAuth\" und \"OpenID Connect\" sicher und eindeutig identifiziert werden k\u00f6nnen.","og_url":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/oauth-in-single-page-apps\/","og_site_name":"Digital Innovation Blog","article_publisher":"https:\/\/www.facebook.com\/ZEISSDigitalInnovation\/","article_published_time":"2022-01-03T10:41:23+00:00","article_modified_time":"2022-06-16T12:33:52+00:00","og_image":[{"width":1920,"height":1280,"url":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/12\/202112_OAuth_1.jpg","type":"image\/jpeg"}],"author":"Manuel Mauky","twitter_card":"summary_large_image","twitter_title":"OAuth in Single-Page-Apps - ZEISS Digital Innovation Blog","twitter_description":"Dieser Artikel zeigt, wie App-Nutzer mit den Protokollen \"OAuth\" und \"OpenID Connect\" sicher und eindeutig identifiziert werden k\u00f6nnen.","twitter_creator":"@ZEISS_di","twitter_site":"@ZEISS_di","twitter_misc":{"Verfasst von":"Manuel Mauky","Gesch\u00e4tzte Lesezeit":"17\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/oauth-in-single-page-apps\/","url":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/oauth-in-single-page-apps\/","name":"OAuth in Single-Page-Apps - ZEISS Digital Innovation Blog","isPartOf":{"@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/oauth-in-single-page-apps\/#primaryimage"},"image":{"@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/oauth-in-single-page-apps\/#primaryimage"},"thumbnailUrl":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/12\/202112_OAuth_1.jpg","datePublished":"2022-01-03T10:41:23+00:00","dateModified":"2022-06-16T12:33:52+00:00","author":{"@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/#\/schema\/person\/d7a29c5e55882a2841cfd79b4118132f"},"description":"Dieser Artikel zeigt, wie App-Nutzer mit den Protokollen \"OAuth\" und \"OpenID Connect\" sicher und eindeutig identifiziert werden k\u00f6nnen.","breadcrumb":{"@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/oauth-in-single-page-apps\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/blogs.zeiss.com\/digital-innovation\/de\/oauth-in-single-page-apps\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/oauth-in-single-page-apps\/#primaryimage","url":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/12\/202112_OAuth_1.jpg","contentUrl":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/12\/202112_OAuth_1.jpg","width":1920,"height":1280},{"@type":"BreadcrumbList","@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/oauth-in-single-page-apps\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/"},{"@type":"ListItem","position":2,"name":"OAuth in Single-Page-Apps"}]},{"@type":"WebSite","@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/#website","url":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/","name":"Digital Innovation Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"de"},{"@type":"Person","@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/#\/schema\/person\/d7a29c5e55882a2841cfd79b4118132f","name":"Manuel Mauky","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/#\/schema\/person\/image\/","url":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2024\/06\/Mauky_Manuel_Profilbild_300x300px-150x150.jpg","contentUrl":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2024\/06\/Mauky_Manuel_Profilbild_300x300px-150x150.jpg","caption":"Manuel Mauky"},"description":"Manuel arbeitet seit 2010 als Softwareentwickler bei der ZEISS Digital Innovation in G\u00f6rlitz. Neben Java besch\u00e4ftigt er sich vor allem mit JavaScript und TypeScript und der Entwicklung von modernen Webanwendungen. Au\u00dferdem interessiert er sich f\u00fcr Funktionale Programmierung und h\u00e4lt regelm\u00e4\u00dfig Vortr\u00e4ge zu diesen Themen. Manuel hat in G\u00f6rlitz Informatik studiert und organisiert die Java-User-Group G\u00f6rlitz.","url":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/author\/manuelmauky\/"}]}},"author_meta":{"display_name":"Manuel Mauky","author_link":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/author\/manuelmauky\/"},"featured_img":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/12\/202112_OAuth_1-600x400.jpg","coauthors":[],"tax_additional":{"categories":{"linked":["<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/web\/\" class=\"advgb-post-tax-term\">Web<\/a>"],"unlinked":["<span class=\"advgb-post-tax-term\">Web<\/span>"]},"tags":{"linked":["<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/web\/\" class=\"advgb-post-tax-term\">Authorization Code Flow<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/web\/\" class=\"advgb-post-tax-term\">PKCE<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/web\/\" class=\"advgb-post-tax-term\">Login-Formulare<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/web\/\" class=\"advgb-post-tax-term\">OpenID Connect<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/web\/\" class=\"advgb-post-tax-term\">Zwei-Faktor-Authentifizierung<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/web\/\" class=\"advgb-post-tax-term\">ZEISS Digital Innovation<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/web\/\" class=\"advgb-post-tax-term\">OAuth<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/web\/\" class=\"advgb-post-tax-term\">Single-Page-App<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/web\/\" class=\"advgb-post-tax-term\">Implicit Flow<\/a>"],"unlinked":["<span class=\"advgb-post-tax-term\">Authorization Code Flow<\/span>","<span class=\"advgb-post-tax-term\">PKCE<\/span>","<span class=\"advgb-post-tax-term\">Login-Formulare<\/span>","<span class=\"advgb-post-tax-term\">OpenID Connect<\/span>","<span class=\"advgb-post-tax-term\">Zwei-Faktor-Authentifizierung<\/span>","<span class=\"advgb-post-tax-term\">ZEISS Digital Innovation<\/span>","<span class=\"advgb-post-tax-term\">OAuth<\/span>","<span class=\"advgb-post-tax-term\">Single-Page-App<\/span>","<span class=\"advgb-post-tax-term\">Implicit Flow<\/span>"]}},"comment_count":"0","relative_dates":{"created":"Posted 4\u00a0Jahren ago","modified":"Updated 4\u00a0Jahren ago"},"absolute_dates":{"created":"Posted on Januar 3, 2022","modified":"Updated on Juni 16, 2022"},"absolute_dates_time":{"created":"Posted on Januar 3, 2022 10:41 a.m.","modified":"Updated on Juni 16, 2022 12:33 p.m."},"featured_img_caption":"","series_order":"","_links":{"self":[{"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/posts\/2559","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/users\/18"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/comments?post=2559"}],"version-history":[{"count":16,"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/posts\/2559\/revisions"}],"predecessor-version":[{"id":3025,"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/posts\/2559\/revisions\/3025"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/media\/2783"}],"wp:attachment":[{"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/media?parent=2559"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/categories?post=2559"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/tags?post=2559"},{"taxonomy":"topics","embeddable":true,"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/topics?post=2559"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}