Teil 2: So funktioniert OAuth2
Kommentare

OAuth1 bringt aber auch ein paar Probleme mit. Das Größte ist, dass es sich nur für Standardwebanwendungen wirklich eignet. In den letzten Jahren sind aber mobile Anwendungen immer wichtiger geworden.

Da OAuth, wie zuvor beschrieben, zum Teil auf Browser Redirects beruht, hat man hier bei nativen Anwendungen für mobile Geräte ein Problem, da es oft nicht einfach ist, aus einer nativen, mobilen Anwendung heraus ein Browserfenster zu öffnen und dann auf den ankommenden Redirect wieder zu reagieren. Auch bei Desktopanwendungen ist das oft problematisch. Das konnte man zum Beispiel an der OAuth-Einführung von Twitter gut sehen. Es gibt hier zwar verschiedene Lösungsmöglichkeiten (mehr dazu später), aber keine ist in OAuth spezifiziert und funktioniert auf allen Systemen oder mit allen API-Anbietern, was zu vielen unterschiedlichen, proprietären Lösungen führt. Zudem werden mittlerweile immer mehr Webanwendungen in JavaScript geschrieben, die nur noch über APIs und Ajax mit Backends sprechen. Hier ist OAuth sogar gar nicht einsetzbar, da das notwendige Client Secret mit einfachsten Mitteln im offenen JavaScript-Code einsehbar ist. Auch ist die kryptographische Erstellung der Signaturen mit JavaScript-Board-Mitteln schwierig. Diese Probleme führten dazu, dass sich die Entwickler von OAuth 2010 mit Vertretern zahlreicher anderer Firmen in der IETF OAuth Working Group zusammengeschlossen haben, um die nächste Version von OAuth, OAuth2, zu entwickeln.

OAuth2

OAuth2 wurde von Grund auf neu geschrieben und ist nicht abwärtskompatibel zu OAuth1. Besonderes Augenmerk wurde dabei auf die einfache Erweiterbarkeit der Spezifikation gelegt, was zusätzlich dazu geführt hat, dass sie nun aufgeräumter und leichter zu verstehen ist.
Der modulare Ansatz von OAuth2

Um den zahlreichen Anforderungen an OAuth2 gerecht zu werden, entschied man sich dazu, einen modularen Ansatz zu wählen. Hierbei wurde eine Basisspezifikation definiert, die an mehreren Stellen durch andere Spezifikationen erweitert werden kann und zum Teil auch muss. Hierdurch lässt sich OAuth flexibel auf die unterschiedlichen Bedürfnisse und Anforderungen anpassen. Beispiele für solche Erweiterungspunkte sind zum Beispiel verschiedene so genannte Client Profiles, die die einzelnen Anwendungsszenarien (Web-, Mobile-, Desktop-, JavaScript App) beschreiben und spezielle Protokollflüsse oder unterschiedliche Request-Autorisierungsmechanismen definieren, zum Beispiel Bearer Tokens über TLS/SSL, HMAC-Signaturen oder SAML Assertions.

Im Folgenden wird nun zuerst auf die wichtigsten Clientprofile unter Nutzung von Bearer Tokens eingegangen. Grundsätzlich muss sich der Client bei OAuth2 weiterhin initial beim Anbieter registrieren, um eine Client-ID und ein Client Secret zu erhalten (analog zu Consumer Key und Consumer Secret bei OAuth1). Das Secret darf Dritten nicht zugänglich gemacht werden. Wichtig ist, dass zusätzlich der Callback URL, zu dem der Authorization-Server nach der Autorisierung zurückleiten soll, bei der Registrierung mit angegeben wird und nicht mehr bei jedem Request geändert werden kann. Diese Änderung erlaubt es, die Anzahl der notwendigen Requests zu minimieren und ermöglicht erst die Nutzung von OAuth in JavaScript-Anwendungen. Dazu gleich mehr.

Web Profile

Das Web Profile von OAuth2 ist für klassische Webanwendungen gedacht und ähnelt der OAuth1-Spezifikation, wurde aber wesentlich vereinfacht. Der Schritt zur Beschaffung eines Request Tokens entfällt komplett und der Server der Clientanwendung leitet den User im Browser direkt zum OAuth2-Authorization-Endpunkt des Providers. In diesem Redirect werden dabei die Client-ID und optional ein Scope und State sowie der response_type code als Query-Parameter an den URL angehängt. Der Callback URL kann, muss aber nicht, mit angegeben werden. Wird er angegeben, muss er aber in jedem Fall mit dem vorregistrierten Callback URL übereinstimmen. Der Scope-Parameter kann für providerabhängige Implementierung genutzt werden, so können über den Scope vom Provider verschiedene Access Control Level definiert werden, zum Beispiel ein Scope read, der gesetzt werden muss, wenn der Client lesenden Zugriff auf das API haben möchte, und ein Scope write bei schreibenden Zugriff. Das kann vom Provider natürlich noch beliebig verfeinert werden. Über den State-Parameter kann man zusätzliche Informationen definieren, die beim Redirect zurück zum Callback URL wieder als Query-Parameter angehängt werden. Das können zum Beispiel intern vom Client benötigte Sessioninformationen sein:

HTTP/1.1 302 Found
Location: https://api.twitter.com/oauth2/authorize?response_type=code&client_id=abcdefg&state=xyz&scope=write

Hat der User den Client zum API-Zugriff autorisiert, wird er danach zum Callback URL zurückgeleitet, neben dem State-Parameter wird vom Provider auch noch ein Authorization-Code angehängt, der beim Anbieter an die Client-ID und den autorisierenden Nutzer gebunden wird (ähnlich dem Verifier in OAuth1):

HTTP/1.1 302 Found
Location: https://example.com/callback?code=ghijkl&state=xyz

Im nächsten Schritt kann der Client dann mit diesem Code und seinem Client Secret im Authorization Header per Server-zu-Server-Kommunikation am Token-Endpunkt des Providers ein Access Token abholen, wie in Listing 4 zu sehen. Eine Darstellung des Web-Profile-Protokollflusses zeigt Abbildung 3. Dieses Access Token kann genutzt werden, um Requests gegen das API zu schicken. Das Access Token wird hierzu im Authorization Header des Requests hinterlegt:

Listing 4

//Beispiel
POST /oauth2/token HTTP/1.1
Host: api.twitter.com
Authorization: Basic mnopqrs
Content-Type: application/x-www-form-urlencoded;charset=UTF-8

grant_type=authorization_code&code=ghijkl
//Antwort
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8

{
  "access_token": "jklmno",
  "expires_in": 3600,
  "refresh_token": "qrstuvq"
}
Abb. 3: Der OAuth2 Web-Profile-Protokollfluss

Abb. 3: Der OAuth2 Web-Profile-Protokollfluss

GET /1/statuses/home_timeline HTTP/1.1
Host: api.twitter.com
Authorization: Bearer jklmno

Optional kann der Access-Token-Endpunkt auch noch ein Refresh Token bereitstellen. Ein Refresh Token ermöglicht es, das Access Token nur eine kurze Zeit gültig zu halten. Damit nun der Client nicht ständig den Nutzer zum Autorisierungsendpunkt schicken muss, kann der Client dann das Refresh Token benutzen, um beim Token-Endpunkt ein neues Access Token und ein neues Refresh Token zu erhalten. Das Request Token wird dabei immer nur zwischen Client und Token-Endpunkt übertragen (Listing 5).

Listing 5

//Beispiel
POST /oauth2/token HTTP/1.1
Host: api.twitter.com
Authorization: Basic mnopqrs
Content-Type: application/x-www-form-urlencoded;charset=UTF-8

grant_type=refresh_token&code=qrstuvq
//Antwort
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8

{
  "access_token": "ghoeahrga",
  "expires_in": 3600,
  "refresh_token": "breaghiouar"
}

Bei der Bearer-Token-Autorisierung müssen die Requests nicht mehr signiert werden, wobei die Nutzung von TSL/SSL zwingend notwendig ist. Außerdem muss der Client auch die Echtheit der TLS/SSL-Zertifikate und die Korrektheit des zugeordneten Hosts überprüfen. Achtung: Manche Libraries wie CURL machen das nicht automatisch (Kasten: „TLS/SSL und CURL“).

TLS/SSL und CURL

Wenn man mit der CURL-Bibliothek in PHP Requests an eine über TSL/SSL gesicherte HTTPS-Adresse schicken möchte, muss man ein paar Dinge beachten, damit das Zertifikat der Gegenstelle auch wirklich korrekt verifiziert wird. Wichtig ist, dass man die CURL-Optionen SSL_VERIFYPEER und SSL_VERIFYHOST setzt. SSL_VERIFYHOST sollte dabei den Wert 2 haben, was bedeutet, dass geprüft wird, ob ein Name im Zertifikat existiert und dieser mit dem Hostnamen des Servers übereinstimmt:

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
$response = curl_exec($ch);
curl_close($ch);

Je nach Systemkonfiguration kann es nun passieren, das CURL folgenden Fehler zurückgibt, anstatt den Request auszuführen:

Failed: Error Number: 60. Reason: SSL certificate problem, verify that the CA cert is OK.
Details:
error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
Abb. 4: Anzeige des TSL/SSL-Zertifikats in Google Chrome

Abb. 4: Anzeige des TSL/SSL-Zertifikats in Google Chrome

Der Fehler bedeutet, dass CURL keinen Zugriff auf ein gültiges Zertifikat der vom Server genutzten Certification Authority (CA) hat. Dieses muss nun noch für CURL lokal hinterlegt werden. Am einfachsten ruft man dazu den Hostnamen (zum Beispiel https://api.twitter.com) in einen Browser auf und lädt sich das CA-Root-Zertifikat von dort herunter. In Google Chrome klickt man dazu auf das Schlosssymbol in der Adressleiste und dann auf Zertifikatinformationen (Abb. 4). Im sich öffnenden Fenster wählt man dann das oberste Zertifikat aus und zieht das große Zertifikatsymbol aus der Dateiansicht in einen Ordner seines PHP-Projekts (Abb. 5). Das heruntergeladene Zertifikat kann man dann per curl_setopt($ch, CURLOPT_CAINFO, ‚/path/to/certificate.cer‘); in CURL konfigurieren.

Abb. 5: Zertifikatssymbol

Abb. 5: Zertifikatssymbol

Weiter mit: Teil 3

Alle Teile: Teil 1, Teil 2, Teil 3, Teil 4, Teil 5

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -