Ich baue ein System auf, das aus einer Angular2-App für einzelne Seiten und einer REST-API besteht, die auf ECS ausgeführt wird. Die API läuft auf .Net / Nancy , aber das könnte sich ändern.
Ich möchte Cognito ausprobieren und so stellte ich mir den Authentifizierungsworkflow vor:
- SPA meldet sich beim Benutzer an und erhält eine JWT
- SPA sendet JWT bei jeder Anforderung an die REST-API
- Die REST-API überprüft, ob das JWT authentisch ist
Meine Frage bezieht sich auf Schritt 3. Wie kann mein Server (oder besser gesagt: meine zustandslosen, automatisch skalierten Docker-Container mit Lastenausgleich) überprüfen, ob das Token authentisch ist? Da der "Server" das JWT selbst nicht ausgegeben hat, kann er kein eigenes Geheimnis verwenden (wie im grundlegenden JWT-Beispiel hier beschrieben ).
Ich habe die Cognito-Dokumente gelesen und viel gegoogelt, aber ich kann keine gute Richtlinie darüber finden, was mit dem JWT auf der Serverseite zu tun ist.
quelle
Antworten:
Es stellte sich heraus, dass ich die Dokumente nicht richtig gelesen habe. Dies wird hier erklärt (scrollen Sie nach unten zu "Verwenden von ID-Token und Zugriffstoken in Ihren Web-APIs").
Der API-Dienst kann die Geheimnisse von Cognito herunterladen und zur Überprüfung der empfangenen JWTs verwenden. Perfekt.
Bearbeiten
@ Groadys Kommentar ist auf den Punkt gebracht: Aber wie validieren Sie die Token? Ich würde sagen, verwenden Sie dafür eine kampferprobte Bibliothek wie jose4j oder nimbus (beide Java) und implementieren Sie die Überprüfung nicht von Grund auf selbst.
Hier ist eine Beispielimplementierung für Spring Boot mit nimbus, mit der ich angefangen habe, als ich dies kürzlich im Java / Dropwizard-Dienst implementieren musste.
quelle
Hier ist eine Möglichkeit, die Signatur auf NodeJS zu überprüfen:
quelle
Führen Sie einen Berechtigungscode-Grant-Flow aus
Angenommen, Sie:
können sich anmelden / anmelden und erhalten einen Zugangscode über:
Ihr Browser sollte zu umleiten
<your-redirect-uri>?code=4dd94e4f-3323-471e-af0f-dc52a8fe98a0
Jetzt müssen Sie diesen Code an Ihr Back-End übergeben und ein Token für Sie anfordern lassen.
POST https://<your-domain>.auth.us-west-2.amazoncognito.com/oauth2/token
Authorization
KopfBasic
und Verwendungusername=<app client id>
undpassword=<app client secret>
pro App - Client konfiguriert in AWS Cognitogrant_type=authorization_code
code=<your-code>
client_id=<your-client-id>
redirect_uri=<your-redirect-uri>
Bei Erfolg sollte Ihr Back-End einen Satz von Base64-codierten Token erhalten.
Gemäß der Dokumentation sollte Ihr Back-End nun die JWT-Signatur überprüfen durch:
Da AWS Cognito für jeden Benutzerpool zwei Paare von RSA-Kryptografieschlüsseln generiert, müssen Sie herausfinden, welcher Schlüssel zum Verschlüsseln des Tokens verwendet wurde.
Hier ist ein NodeJS- Snippet, das die Überprüfung eines JWT demonstriert.
import jsonwebtoken from 'jsonwebtoken' import jwkToPem from 'jwk-to-pem' const jsonWebKeys = [ // from https://cognito-idp.us-west-2.amazonaws.com/<UserPoolId>/.well-known/jwks.json { "alg": "RS256", "e": "AQAB", "kid": "ABCDEFGHIJKLMNOPabc/1A2B3CZ5x6y7MA56Cy+6ubf=", "kty": "RSA", "n": "...", "use": "sig" }, { "alg": "RS256", "e": "AQAB", "kid": "XYZAAAAAAAAAAAAAAA/1A2B3CZ5x6y7MA56Cy+6abc=", "kty": "RSA", "n": "...", "use": "sig" } ] function validateToken(token) { const header = decodeTokenHeader(token); // {"kid":"XYZAAAAAAAAAAAAAAA/1A2B3CZ5x6y7MA56Cy+6abc=", "alg": "RS256"} const jsonWebKey = getJsonWebKeyWithKID(header.kid); verifyJsonWebTokenSignature(token, jsonWebKey, (err, decodedToken) => { if (err) { console.error(err); } else { console.log(decodedToken); } }) } function decodeTokenHeader(token) { const [headerEncoded] = token.split('.'); const buff = new Buffer(headerEncoded, 'base64'); const text = buff.toString('ascii'); return JSON.parse(text); } function getJsonWebKeyWithKID(kid) { for (let jwk of jsonWebKeys) { if (jwk.kid === kid) { return jwk; } } return null } function verifyJsonWebTokenSignature(token, jsonWebKey, clbk) { const pem = jwkToPem(jsonWebKey); jsonwebtoken.verify(token, pem, {algorithms: ['RS256']}, (err, decodedToken) => clbk(err, decodedToken)) } validateToken('xxxxxxxxx.XXXXXXXX.xxxxxxxx')
quelle
<app client id>
das gleiche wie<your-client-id>
?new Buffer(headerEncoded, 'base64')
sollte jetzt seinBuffer.from(headerEncoded, 'base64')
Ich hatte ein ähnliches Problem, aber ohne das API-Gateway zu verwenden. In meinem Fall wollte ich die Signatur eines JWT-Tokens überprüfen, das über die authentifizierte Identitätsroute von AWS Cognito Developer erhalten wurde.
Wie bei vielen Postern auf verschiedenen Websites hatte ich Probleme, genau die Bits zusammenzusetzen, die ich zum Überprüfen der Signatur eines AWS JWT-Tokens extern, dh serverseitig oder per Skript, benötige
Ich glaube, ich habe es herausgefunden und einen Kern erstellt, um eine AWS JWT-Token-Signatur zu überprüfen . Es wird ein AWS JWT / JWS-Token mit pyjwt oder PKCS1_v1_5c von Crypto.Signature in PyCrypto überprüft
Also, ja, das war in meinem Fall Python, aber es ist auch einfach im Knoten machbar (npm install jsonwebtoken jwk-to-pem request).
Ich habe versucht, einige Fallstricke in den Kommentaren hervorzuheben, weil ich, als ich versuchte, dies herauszufinden, meistens das Richtige tat, aber es gab einige Nuancen wie die Reihenfolge der Python-Diktate oder das Fehlen einer solchen und die json-Darstellung.
Hoffentlich kann es jemandem irgendwo helfen.
quelle
Kurze Antwort:
Sie können den öffentlichen Schlüssel für Ihren Benutzerpool vom folgenden Endpunkt abrufen:
https://cognito-idp.{region}.amazonaws.com/{userPoolId}/.well-known/jwks.json
Wenn Sie das Token mit diesem öffentlichen Schlüssel erfolgreich dekodieren, ist das Token gültig, andernfalls wird es gefälscht.
Lange Antwort:
Nachdem Sie sich erfolgreich über Cognito authentifiziert haben, erhalten Sie Ihre Zugriffs- und ID-Token. Jetzt möchten Sie überprüfen, ob dieses Token manipuliert wurde oder nicht. Normalerweise senden wir diese Token an den Authentifizierungsdienst zurück (der dieses Token an erster Stelle ausgestellt hat), um zu überprüfen, ob das Token gültig ist. Diese Systeme verwenden
symmetric key encryption
AlgorithmenHMAC
, um die Nutzdaten mit einem geheimen Schlüssel zu verschlüsseln. Nur dieses System kann daher feststellen, ob dieses Token gültig ist oder nicht.Traditioneller Auth JWT-Token-Header:
Beachten Sie hier, dass der hier verwendete Verschlüsselungsalgorithmus symmetrisch ist - HMAC + SHA256.
Moderne Authentifizierungssysteme wie Cognito verwenden jedoch
asymmetric key encryption
AlgorithmenRSA
, um die Nutzdaten mit einem Paar aus öffentlichem und privatem Schlüssel zu verschlüsseln. Payload wird mit einem privaten Schlüssel verschlüsselt, kann jedoch mit einem öffentlichen Schlüssel dekodiert werden. Der Hauptvorteil der Verwendung eines solchen Algorithmus besteht darin, dass wir keinen einzigen Authentifizierungsdienst anfordern müssen, um festzustellen, ob ein Token gültig ist oder nicht. Da jeder Zugriff auf den öffentlichen Schlüssel hat, kann jeder die Gültigkeit des Tokens überprüfen. Die Last für die Validierung ist fair verteilt und es gibt keinen einzelnen Fehlerpunkt.Cognito JWT-Token-Header:
In diesem Fall verwendeter asymmetrischer Verschlüsselungsalgorithmus - RSA + SHA256
quelle
cognito-jwt-verifier ist ein winziges npm-Paket zum Überprüfen der ID und zum Zugriff auf JWT-Token, die von AWS Cognito in Ihrem Knoten- / Lambda-Backend mit minimalen Abhängigkeiten erhalten wurden.
Haftungsausschluss: Ich bin der Autor davon. Ich habe es mir ausgedacht, weil ich nichts gefunden habe, das alle Kästchen für mich überprüft hat:
Verwendung (siehe Github Repo für ein detaillierteres Beispiel):
const { verifierFactory } = require('@southlane/cognito-jwt-verifier') const verifier = verifierFactory({ region: 'us-east-1', userPoolId: 'us-east-1_PDsy6i0Bf', appClientId: '5ra91i9p4trq42m2vnjs0pv06q', tokenType: 'id', // either "access" or "id" }) const token = 'eyJraWQiOiI0UFFoK0JaVE...' // clipped try { const tokenPayload = await verifier.verify(token) } catch (e) { // catch error and act accordingly, e.g. throw HTTP 401 error }
quelle
Hier erhalten Sie Einblicke in den Lambda-Code
https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-verifying-a-jwt.html
https://github.com/awslabs/aws-support-tools/tree/master/Cognito/decode-verify-jwt
In Golang https://gist.github.com/tmaiaroto/e2ee5e88fc6ae035307d7c5ee71a99cf
quelle
python-jose
zum Dekodieren und Überprüfen von JWT.das funktioniert bei mir in dot net 4.5
quelle
Jemand hat auch ein Python-Paket namens cognitojwt geschrieben , das sowohl im Async- als auch im Sync-Modus funktioniert , um Amazon Cognito JWT zu dekodieren und zu verifizieren.
quelle
Dies basiert auf der ausführlichen Erklärung von Derek ( Antwort ). Ich konnte ein funktionierendes Beispiel für PHP erstellen.
Ich habe https://github.com/firebase/php-jwt für die PEM-Erstellung und Codeüberprüfung verwendet.
Dieser Code wird verwendet, nachdem Sie einen Satz von Base64-codierten Token erhalten haben.
quelle