Node.js mit TSOA und Authentifizierung - (Teil 3) Ein JWT erzeugen

In diesem Artikel besorgen wir uns ein Token, mit dem wir unsere Endpunkte künftig aufrufen. Dazu erstellen wir einen Endpunkt, der ein gültiges, signiertes Token erzeugt. Packen wir es an!

4 Minuten

Bevor wir die Authentifizierung implementieren, benötigen wir ein gültiges JWT, das wir an unsere Schnittstelle übermitteln. Das Thema Nutzerverwaltung allein ist umfangreich, weswegen ich mich auf das absolute Minimum beschränke: Wir fragen ein neues JWT an und erhalten es als Antwort.

Um das in einen sinnvollen Kontext zu bringen: Je nachdem, wie die Anforderung ist, ist es notwendig, neue Nutzer:innen zu registrieren, dies zu bestätigen und beim erfolgreichen Login das JWT zu übermitteln. Alternativ zu Nutzernamen und Passwort kann man einen Magic-Link an die registrierte E-Mail-Adresse senden. Diese E-Mail enthält einen JWT, mit dem wir die Applikation nutzen können.

Wir erstellen ein JWT und geben es als Antwort zurück. Stattdessen könntest du das JWT an die registrierte E-Mail-Adresse schicken und hättest einen Loginmechanismus, bei dem deine Nutzenden kein Passwort benötigen. Wenn ich die Details in einer separaten Artikelserie aufarbeiten soll, schreib mir einen Kommentar.

Bevor wir anfangen, empfiehlt es sich, die Vorgänger der Artikelserie zu lesen:

npm install jsonwebtoken
npm install -D @types/jsonwebtoken

Des Weiteren wird zur Signierung des JWTs ein asymmetrisches Verfahren verwendet. In unserer Node.js-Applikation verwenden wir den privaten Schlüssel bei der Erstellung. Den öffentlichen Schlüssel können wir zur Prüfung unserer Token an Dritte (z. B. unser Frontend) weitergeben.

Für unseren Fall kannst du das Schlüsselpaar wie folgt erstellen:

openssl genrsa -out jwt 4096
openssl rsa -in jwt -pubout -outform PEM -out jwt.pub

Der erste Befehl erzeugt den privaten Schlüssel namens jwt. Der zweite Befehl generiert daraus den passenden öffentlichen Teil namens jwt.pub. Diese beiden Dateien legst du im Projekt-Root-Verzeichnis „certs“ ab.

Endpunkt für JWT-Abfrage

Für die Abfrage erstellen wir uns einen GET-Endpunkt, der im Controller die notwendigen Schritte durchführt:

  • Definition der JWT-Daten
  • Einlesen des privaten Schlüssels
  • Definition der Signaturoptionen
import { Controller } from '@tsoa/runtime'  
import { Get, Route } from 'tsoa'  
import fs from 'node:fs'  
import path from 'node:path'  
import jwt from 'jsonwebtoken'  

@Route('users')  
export class UserController extends Controller {  
  @Get('jwt')  
  public async getJwt (): Promise<string> {  
    const jwtData = {  
      userId: 'user-uuid',  
      email: 'user.mail@example.com',  
      scopes: ['ADMIN'],  
      name: `Test User`,  
    }  

    const privateKey = fs.readFileSync(path.join(path.resolve('certs'), 'jwt'), 'utf8')  

    const durationInSeconds = 60 * 60 * 24 // 24 hours  
    const signOptions = {  
      issuer: 'demo-company',  
      subject: 'user-uuid',  
      audience: 'https://demo-company.de',  
      expiresIn: durationInSeconds,  
      algorithm: 'RS256' as jwt.Algorithm,  
    }  

    return jwt.sign(jwtData, privateKey, signOptions)  
  }  
}

Wenn du mehr über JWT erfahren möchtest, arbeite ich das gerne in einem separaten Artikel auf. Lass mir hier einen Kommentar oder

Schnapp dir einen Termin

Mit einem Neustart der Applikation über npm run start:dev ist die neue Route direkt verfügbar. Achtung: Wenn du an den Routendefinitionen arbeitest, während das Watch von start:dev lauscht, aktualisiert sich die Datei route.ts nicht. Dazu habe ich leider noch keinen schlauen Ansatz gefunden. Selbst der GitHub-Eintrag dazu ist nicht hilfreich

Das Token kannst du jetzt abfragen:

curl http://localhost:4000/users/jwt

Die Antwort ist das JWT, das du auf der Webseite https://jwt.io eingeben kannst, um dir das Ergebnis anzusehen. Du wirst sehen, dass mit der Eingabe eines öffentlichen Schlüssels die Echtheit des Tokens geprüft werden kann → hierfür kopiere den Inhalt der Datei certs/jwt.pub in den entsprechenden Bereich. Wenn es passt, wird die Anzeige grün.

Fazit

Mit diesem Schritt haben wir ein JWT, das wir beim Aufruf des EntityControllers verwenden können. Dafür verwenden wir den Authorization-Header. Mittels curl sähen die Aufrufe wie folgt aus:

DEMO_TOKEN=$(curl -s http://localhost:4000/users/jwt)

Das Token wird zwischengespeichert und anschließend direkt wiederverwendet.

curl -H "Authorization: Bearer ${DEMO_TOKEN}" http://localhost:4000/entities

In unserer AuthMiddleware haben wir über request.headers['authorization'] Zugriff darauf. An genau dieser Stelle machen wir im nächsten Artikel weiter.

call to action background image

Abonniere meinen Newsletter

Erhalte einmal im Monat Nachrichten aus den Bereichen Softwareentwicklung und Kommunikation gespikt mit Buch- und Linkempfehlungen.