JSON Web Tokens (JWTs, ausgesprochen „Jots“) sind ein kompaktes und äußerst portables Mittel zum Austausch von Identitätsinformationen. Die JWT-Spezifikation bildet eine wichtige Grundlage für OpenID Connect und stellt ein Single-Sign-on-Token für das OAuth-2.0-Ökosystem bereit. JWTs können auch eigenständig als Anmeldeinformationen zur Authentifizierung verwendet werden und eignen sich besser zur Steuerung des Zugriffs auf webbasierte APIs als herkömmliche API-Schlüssel.
NGINX Plus R10 und höher können JWTs direkt validieren. In diesem Blogbeitrag beschreiben wir, wie NGINX Plus als API-Gateway eingesetzt werden kann, das als Frontend für einen API-Endpunkt dient und JWTs zur Authentifizierung von Clientanwendungen verwendet.
Native JWT-Unterstützung ist nur in NGINX Plus verfügbar, nicht in NGINX Open Source.
Redaktion – Dieser Blogbeitrag wurde im Dezember 2021 aktualisiert, um die mit NGINX Plus R25 eingeführte Direktive auth_jwt_require zu verwenden. Eine ausführliche Erläuterung der Direktive finden Sie unter Benutzerdefinierte JWT-Validierungsregeln im Blogbeitrag zur Ankündigung von NGINX Plus R25.
NGINX Plus R15 und höher können auch den „Authorization Code Flow“ in OpenID Connect 1.0 steuern, was die Integration mit den meisten großen Identitätsanbietern ermöglicht. Weitere Informationen finden Sie unter „Ankündigung von NGINX Plus R15<.htmlspan>“.
Anatomie eines JWT
JWTs bestehen aus drei Teilen: einem Header, einer Payload und einer Signatur. Bei der Übertragung sehen sie wie folgt aus. Zur besseren Lesbarkeit haben wir Zeilenumbrüche eingefügt (das eigentliche JWT ist eine einzige Zeichenfolge) und die drei Teile farblich gekennzeichnet:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.ewogICAgInN1YiI6ICJsYzEiLAogICAgImVtYWlsIjogImxpYW0uY3JpbGx5QG5naW54LmNvbSIsCn0=.VGYHWPterIaLjRi0LywgN3jnDUQbSsFptUw99g2slfcWie dargestellt, trennt ein Punkt ( . ) den Header, die Nutzdaten und die Signatur voneinander. Der Header und die Nutzdaten sind Base64-kodierte JSON-Objekte. Die Signatur wird mit dem Algorithmus verschlüsselt, der im alg-Header angegeben ist. Dies können wir sehen, wenn wir unser Beispiel-JWT dekodieren:
Kodiert DekodiertHeader eyJhbGciOiJIUzI1NiIsInR5cCI6Ik pXVCJ9 {Nutzdaten
"alg": "HS256",
"typ": "JWT"
}ewogICAgInN1YiI6ICJsYzEiLAogICAgImVtYWlsIjogImxpYW0uY3JpbGx5QG5naW54LmNvbSIsCn0= {
"sub": "lc1",
"email": "liam.crilly@nginx.com",
}
The JWT standard defines several signature algorithms. The value HS256 in our example refers to HMAC SHA‑256, which we’re using for all sample JWTs in this blog post. NGINX Plus supports the HSxxx, RSxxx, and ESxxx signature algorithms that are defined in the standard. The ability to cryptographically sign JWTs makes them ideal for use as authentication credentials.
JWT als API-Schlüssel
Eine gängige Methode zur Authentifizierung eines API-Clients (also des entfernten Software-Clients, der API-Ressourcen anfordert) ist die Verwendung eines gemeinsamen Geheimnisses, das üblicherweise als API-Schlüssel bezeichnet wird. Ein herkömmlicher API-Schlüssel ist im Wesentlichen ein langes und komplexes Passwort, das der Client bei jeder einzelnen Anfrage als zusätzlichen HTTP-Header sendet. Der API-Endpunkt gewährt Zugriff auf die angeforderte Ressource, wenn der übermittelte API-Schlüssel in der Liste der gültigen Schlüssel enthalten ist. In der Regel validiert der API-Endpunkt die API-Schlüssel nicht selbst. Stattdessen übernimmt ein API-Gateway den Authentifizierungsprozess und leitet jede Anfrage an den entsprechenden Endpunkt weiter. Neben der Auslagerung von Rechenaufwand bietet dies die Vorteile eines Reverse-Proxys, etwa hohe Verfügbarkeit und Lastverteilung auf mehrere API-Endpunkte.

an den API-Endpunkt weiterleitet
Es ist üblich, für verschiedene API-Clients unterschiedliche Zugriffskontrollen und Richtlinien anzuwenden. Bei herkömmlichen API-Schlüsseln ist dazu eine Abfrage erforderlich, um den API-Schlüssel einem Satz von Attributen zuzuordnen. Diese Abfrage bei jeder einzelnen Anfrage wirkt sich verständlicherweise auf die Gesamtlatenz des Systems aus. Bei JWT sind diese Attribute eingebettet, sodass keine separate Abfrage erforderlich ist.
Die Verwendung von JWT als API-Schlüssel bietet eine leistungsstarke Alternative zu herkömmlichen API-Schlüsseln und kombiniert bewährte Authentifizierungstechnologie mit einem standardbasierten Schema für den Austausch von Identitätsattributen.

NGINX Plus als authentifizierendes API-Gateway konfigurieren
Die NGINX Plus-Konfiguration zur Validierung von JWTs ist sehr einfach.
upstream api_server {
server 10.0.0.1;
server 10.0.0.2;
}
server {
listen 80;
location /products/ {
auth_jwt "Products API";
auth_jwt_key_file conf/api_secret.jwk;
proxy_pass http://api_server;
}
}Als Erstes geben wir im upstream-Block die Adressen der Server an, auf denen der API-Endpunkt gehostet wird. Der location-Block legt fest, dass alle Anfragen an URLs, die mit /products/ beginnen, authentifiziert werden müssen. Die auth_jwt-Direktive definiert den Authentifizierungsbereich, der zusammen mit dem Statuscode 401 zurückgegeben wird, wenn die Authentifizierung fehlschlägt.
Die Direktive „auth_jwt_key_file“ teilt NGINX Plus mit, wie das Signaturelement des JWT validiert werden soll. In diesem Beispiel verwenden wir den HMAC-SHA-256-Algorithmus zum Signieren von JWTs. Daher müssen wir in conf/api_secret.jwk einen JSON Web Key erstellen, der den für die Signierung verwendeten symmetrischen Schlüssel enthält. Die Datei muss dem in der JSON-Web-Key-Spezifikation beschriebenen Format entsprechen. Unser Beispiel sieht wie folgt aus:
{"keys":
[{
"k":"ZmFudGFzdGljand0",
"kty":"oct",
"kid":"0001"
}]
}Der symmetrische Schlüssel wird im Feld „k“ definiert. Hier sehen Sie den Base64URL-kodierten Wert der Klartext-Zeichenfolge „fantasticjwt“. Den kodierten Wert haben wir mit folgendem Befehl erzeugt:
$ echo -n fantasticjwt | base64 | tr '+/' '-_' | tr -d '='Das Feld „kty“ definiert den Schlüsseltyp als symmetrischen Schlüssel (Oktettfolge). Das Feld „kid“ (Schlüssel-ID) legt schließlich eine Seriennummer für diesen JSON Web Key fest, hier „0001“. Dadurch können mehrere Schlüssel in derselben Datei (angegeben durch die Direktive „auth_jwt_key_file“) unterstützt sowie der Lebenszyklus dieser Schlüssel und der damit signierten JWTs verwaltet werden.
Jetzt können wir JWTs für unsere API-Clients ausstellen.
Ausstellen eines JWT für API-Clients
Als Beispiel-API-Client verwenden wir eine Anwendung für ein „Angebotssystem“ und erstellen ein JWT für den API-Client. Zunächst definieren wir den JWT-Header:
{
"typ":"JWT",
"alg":"HS256",
"kid":"0001"
}Das Feld „typ“ definiert den Typ als JSON Web Token, das Feld „alg“ gibt an, dass das JWT mit dem HMAC-SHA256-Algorithmus signiert ist, und das Feld „kid“ gibt an, dass das JWT mit dem JSON Web Key mit dieser Seriennummer signiert ist.
Als Nächstes definieren wir die JWT-Nutzdaten:
{
"name":"Quotation System",
"sub":"quotes",
"iss":"My API Gateway"
}Das Feld „sub“ (Subjekt) ist unsere eindeutige Kennung für den vollständigen Wert im Feld „name“. Das Feld „iss“ gibt den Aussteller des JWT an. Dies ist nützlich, wenn Ihr API-Gateway auch JWTs von Drittanbietern oder einem zentralen Identitätsverwaltungssystem akzeptiert.
Da wir nun alles haben, was wir zum Erstellen des JWT benötigen, führen wir die folgenden Schritte aus, um es korrekt zu codieren und zu signieren. Befehle und codierte Werte werden lediglich zur besseren Lesbarkeit über mehrere Zeilen dargestellt; tatsächlich werden sie jeweils in einer einzigen Zeile eingegeben bzw. angezeigt.
- Header und Nutzdaten jeweils separat in eine kompakte Form bringen und Base64URL-kodieren.
$ echo -n '{"typ":"JWT","alg":"HS256","kid":"0001"}' | base64 | tr '+/' '-_' | tr -d '='eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEifQ
$ echo -n '{"name":"Quotation System","sub":"quotes","iss":"My API Gateway"}' | base64 | tr '+/' '-_' | tr -d '='
eyJuYW1lIjoiUXVvdGF0aW9uIFN5c3RlbSIsInN1YiI6InF1b3RlcyIsImlzcyI6Ik
15IEFQSSBHYXRld2F5In0- Verketten Sie den codierten Header und die Nutzdaten mit einem Punkt (.) und weisen Sie das Ergebnis der Variablen
HEADER_PAYLOADzu.
$ HEADER_PAYLOAD=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEifQ.eyJuYW1lIjoiUXVvdGF0aW9uIFN5c3RlbSIsInN1YiI6InF1b3RlcyIsIm lzcyI6Ik15IEFQSSBHYXRld2F5In0- Signieren Sie den Header und die Nutzdaten mit unserem symmetrischen Schlüssel und kodieren Sie die Signatur mit Base64URL.
$ echo -n $HEADER_PAYLOAD | openssl dgst -binary -sha256 -hmac fantasticjwt | base64 | tr '+/' '-_' | tr -d '='ggVOHYnVFB8GVPE-VOIo3jD71gTkLffAY0hQOGXPL2I- Hängen Sie die codierte Signatur an den Header und die Nutzdaten an.
$ echo $HEADER_PAYLOAD.ggVOHYnVFB8GVPE-VOIo3jD71gTkLffAY0hQOGXPL2I > quotes.jwt- Testen Sie die Konfiguration, indem Sie eine authentifizierte Anfrage an das API-Gateway senden (in diesem Beispiel wird das Gateway auf localhost ausgeführt).
$ curl -H "Authorization: Bearer `cat quotes.jwt`" http://localhost/products/widget1Der Befehl curl in Schritt 5 sendet das JWT in Form eines Bearer-Tokens an NGINX Plus. Dies ist das Format, das NGINX Plus standardmäßig erwartet. NGINX Plus kann das JWT auch aus einem Cookie oder einem Abfragezeichenfolgenparameter abrufen. Um dies zu konfigurieren, fügen Sie den Parameter token= zur Direktive auth_jwt hinzu. Mit der folgenden Konfiguration kann NGINX Plus beispielsweise das mit diesem curl-Befehl gesendete JWT validieren:
$ curl http://localhost/products/widget1?apijwt=`cat quotes.jwt`server {
listen 80;
location /products/ {
auth_jwt "Products API" token=$arg_apijwt;
auth_jwt_key_file conf/api_secret.jwk;
proxy_pass http://api_server;
}
}Nachdem Sie NGINX Plus konfiguriert und wie oben gezeigt ein JWT generiert und verifiziert haben, können Sie das JWT an den Entwickler des API-Clients senden und mit ihm vereinbaren, über welchen Mechanismus das JWT bei jeder API-Anfrage übermittelt wird.
JWT-Claims für Protokollierung und Ratenbegrenzung nutzen
Einer der Hauptvorteile von JWTs als Anmeldeinformationen besteht darin, dass sie „Claims“ übermitteln. Diese repräsentieren Entitäten, die mit dem JWT und seiner Nutzlast verknüpft sind (beispielsweise den Aussteller, den Benutzer, für den es ausgestellt wurde, und den vorgesehenen Empfänger). Nach der Validierung des JWT kann NGINX Plus auf alle im Header und in der Nutzlast enthaltenen Felder als Variablen zugreifen. Der Zugriff erfolgt, indem dem gewünschten Feld $jwt_header_ oder $jwt_claim_ vorangestellt wird (beispielsweise $jwt_claim_sub für den Claim sub). Dadurch können wir die im JWT enthaltenen Informationen sehr einfach an den API-Endpunkt weiterleiten, ohne die JWT-Verarbeitung in der API selbst implementieren zu müssen.
Dieses Konfigurationsbeispiel veranschaulicht einige der erweiterten Funktionen.
log_format jwt '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" "$http_user_agent" '
'$jwt_header_alg $jwt_claim_sub';
limit_req_zone $jwt_claim_sub zone=10rps_per_client:1m rate=10r/s;
server {
listen 80;
location /products/ {
auth_jwt "Products API";
auth_jwt_key_file conf/api_secret.jwk;
limit_req zone=10rps_per_client;
proxy_pass http://api_server;
proxy_set_header API-Client $jwt_claim_sub;
access_log /var/log/nginx/access_jwt.log jwt;
}
}Die log_format-Direktive definiert ein neues Format namens jwt, das das allgemeine Protokollformat um zwei zusätzliche Felder erweitert: $jwt_header_alg und $jwt_claim_sub. Innerhalb des location-Blocks verwenden wir die access_log-Direktive, um die aus dem validierten JWT abgerufenen Werte zu protokollieren.
In diesem Beispiel verwenden wir außerdem Claim-basierte Variablen, um die API-Anfragerate pro API-Client statt pro IP-Adresse zu begrenzen. Dies ist besonders nützlich, wenn mehrere API-Clients in ein einziges Portal eingebettet sind und nicht anhand ihrer IP-Adresse unterschieden werden können. Die Direktive „limit_req_zone“ verwendet den JWT-Claim „sub“ als Schlüssel zur Berechnung der Ratenbegrenzungen. Diese werden anschließend auf den Block „location“ angewendet, indem die Direktive „limit_req“ eingebunden wird.
Schließlich stellen wir den JWT-Betreff als neuen HTTP-Header bereit, wenn die Anfrage an den API-Endpunkt weitergeleitet wird. Die proxy_set_header-Direktive fügt einen HTTP-Header namens API‑Client hinzu, den der API-Endpunkt problemlos verarbeiten kann. Daher muss der API-Endpunkt keine Logik zur JWT-Verarbeitung implementieren. Dies wird mit zunehmender Anzahl von API-Endpunkten immer wertvoller.
JWTs widerrufen
Von Zeit zu Zeit kann es erforderlich sein, das JWT eines API-Clients zu widerrufen oder neu auszustellen. Durch die Kombination eines einfachen map-Blocks mit der Direktive auth_jwt_require können wir einem API-Client den Zugriff verweigern, indem wir sein JWT so lange als ungültig kennzeichnen, bis das Ablaufdatum des JWT (dargestellt im exp-Claim) erreicht ist. Anschließend kann der map-Eintrag für dieses JWT gefahrlos entfernt werden.
In diesem Beispiel setzen wir die Variable $jwt_status abhängig vom Wert des Claims 0 oder 1 sub im Token (der in der Variable $jwt_claim_sub erfasst wird). Anschließend verwenden wir die Direktive auth_jwt_require im Block location, um das Token zusätzlich zu validieren (oder abzulehnen). Damit es gültig ist, darf die Variable $jwt_status weder leer noch gleich 0 (null) sein.
map $jwt_claim_sub $jwt_status { "quotes" 0; "test" 0; default 1;
}
server {
listen 80;
location /products/ {
auth_jwt "Products API";
auth_jwt_key_file conf/api_secret.jwk;
auth_jwt_require $jwt_status;
proxy_pass http://api_server;
}
}Zusammenfassung
JSON Web Tokens eignen sich hervorragend, um authentifizierten Zugriff auf APIs bereitzustellen. Für Entwickler von API-Clients sind sie genauso einfach zu handhaben wie herkömmliche API-Schlüssel und stellen dem API-Gateway Identitätsinformationen zur Verfügung, für die andernfalls eine Datenbankabfrage erforderlich wäre. NGINX Plus unterstützt die JWT-Authentifizierung und bietet ausgefeilte Konfigurationslösungen auf Grundlage der im JWT selbst enthaltenen Informationen. In Kombination mit weiteren API-Gateway-Funktionen ermöglicht Ihnen NGINX Plus, API-basierte Dienste schnell, zuverlässig, skalierbar und sicher bereitzustellen.
Wenn Sie JWT mit NGINX Plus selbst ausprobieren möchten, starten Sie noch heute Ihre kostenlose 30-tägige Testversion oder kontaktieren Sie uns, um Ihre Anwendungsfälle zu besprechen.
Über den Autor

Ähnliche Blogbeiträge
Die Zukunft von NGINX: Zurück zu unseren Open-Source-Wurzeln
Beim NGINX Sprint 2022 besinnen wir uns auf unsere Open-Source-Wurzeln. Erfahren Sie mehr über die Initiativen, die wir im kommenden Jahr verfolgen, und teilen Sie uns mit, was Sie sich wünschen.

Ein Leitfaden zur Auswahl eines Ingress-Controllers, Teil 1: Ermitteln Sie Ihre Anforderungen
Ein Ingress-Controller kann eines der leistungsstärksten Tools in Ihrem Kubernetes-Stack sein. Erfahren Sie, wie Sie Ihre Ingress-Anforderungen ermitteln, um die beste Option auszuwählen.
Bereitstellung des NGINX Ingress Controllers auf Amazon EKS: So haben wir getestet
Wir haben kürzlich den Lösungsleitfaden zum NGINX Ingress Controller um Empfehlungen zur Dimensionierung für Amazon Elastic Kubernetes Service (EKS) ergänzt. In diesem Blogbeitrag erläutern wir, wie wir diese Empfehlungen erarbeitet haben, und stellen Ihnen alle Informationen zur Verfügung, die Sie benötigen, um selbst ähnliche Tests durchzuführen.

Protokollierung des Datenverkehrs zwischen NGINX und Upstream-Servern bei CDN77
Bei der Fehlersuche bei Datenverkehrsproblemen zwischen NGINX und Upstream-Servern konnte CDN77 die benötigten Daten nur aus dem Fehlerprotokoll mit aktivierter Debug-Ausgabe beziehen, was die Leistung beeinträchtigt und riesige Dateien erzeugt. Daher entwickelte das Team ein neues benutzerdefiniertes Modul, das ausschließlich die benötigten Daten protokolliert.
Ankündigung von NGINX Plus R16
NGINX Plus R16 ist eine einheitliche, elastische Ingress- und Egress-Schicht für Anwendungen, die die Funktionen eines Load Balancers, API-Gateways und einer WAF vereint und neue Features wie clusterfähige Ratenbegrenzung, Schlüssel-Wert-Speicher, „Random with Two Choices“, verbessertes UDP-Load-Balancing und vieles mehr bietet.
5 Gründe für den Umstieg auf softwarebasiertes Load Balancing
Entdecken Sie fünf Gründe für den Wechsel zu einem softwarebasierten Load Balancer wie NGINX Plus, darunter Kosteneinsparungen, die Einführung von DevOps und eine einheitliche Lösung für alle Umgebungen.