jwtdecoder.de

Case-Study · Web-App mit Google-Login (OAuth 2.0 + OIDC)

Case-Study: Google-Login via OpenID Connect

Authorization-Code-Flow mit PKCE. Google liefert ID-Token (JWT, RS256). Backend verifiziert via JWKS, prüft iss, aud, exp.

Eckdaten

Algorithmus

RS256

ID-Token-Lifetime

1 Stunde

Access-Token-Lifetime

1 Stunde

Refresh-Token

Bis zu 6 Monate

Schritte / Maßnahmen

  • Authorization-Code mit code_challenge (PKCE) anfordern
  • Code gegen Token-Tripel tauschen (Access + ID + Refresh)
  • ID-Token via JWKS-Endpoint von accounts.google.com verifizieren
  • Claims prüfen: iss, aud (Client-ID), exp, nonce
  • User-Info aus sub-Claim als Primary-Key

Praktisches Beispiel anhand eines Web-App-Logins über Google. Wir bauen den Flow mit OAuth-2.0-Authorization-Code-Grant + PKCE auf, weil das der von Google empfohlene Modus für Server-side-Web-Apps ist.

Schritt 1: Authorization-Request

Der Client redirected den Nutzer zu Google mit einer URL nach RFC 6749. Beispiel (gekürzt):

https://accounts.google.com/o/oauth2/v2/auth
  ?client_id=YOUR_CLIENT_ID
  &redirect_uri=https://example.com/callback
  &response_type=code
  &scope=openid+email+profile
  &code_challenge=BASE64URL(SHA256(verifier))
  &code_challenge_method=S256
  &state=RANDOM_CSRF_TOKEN
  &nonce=RANDOM_REPLAY_TOKEN

scope=openid markiert den Request als OpenID-Connect-Request - Google liefert dann zusätzlich zum Access-Token ein ID-Token (JWT).

Schritt 2: Code gegen Token tauschen

Nach Auth-Approval redirected Google zum callback mit ?code=... - das tauscht der Server backend-side gegen Tokens:

POST https://oauth2.googleapis.com/token
  client_id=...
  client_secret=...
  code=...
  code_verifier=ORIGINAL_VERIFIER
  grant_type=authorization_code
  redirect_uri=...

Response enthält access_token, id_token (das JWT), refresh_token, expires_in.

Schritt 3: ID-Token verifizieren

Das id_token ist ein RS256-signiertes JWT. So sieht es im jwtdecoder.de zerlegt aus:

TeilInhalt (gekürzt)
Header{ "alg": "RS256", "kid": "abc123...", "typ": "JWT" }
Payload (Claims){ "iss": "https://accounts.google.com", "aud": "YOUR_CLIENT_ID", "sub": "1234567890", "email": "user@example.com", "exp": 1234567890, "iat": 1234564290, "nonce": "RANDOM_REPLAY_TOKEN" }
SignatureRSA-SHA256-Signatur über header.payload

Schritt 4: JWKS-Lookup

Backend holt Googles JWKS:

GET https://www.googleapis.com/oauth2/v3/certs

Das JWKS enthält mehrere Keys mit verschiedenen kid-Werten. Backend cached die Response (Cache-Control-Header beachten, typisch 1-24 h). Bei jedem Token-Verify: kid aus Header lesen, passenden JWK finden, Public Key konstruieren, Signatur prüfen.

Schritt 5: Claims validieren

  • iss muss exakt https://accounts.google.com sein (nicht trauen!)
  • aud muss die eigene Client-ID enthalten
  • exp muss in der Zukunft liegen (Clock-Skew ±60s)
  • nonce muss dem zuvor gesendeten Wert entsprechen - schützt vor Replay
  • sub ist die eindeutige Google-User-ID (NIE email als Primary-Key)

Häufige Fehler

  • Validation der ID-Token-Claims wird vergessen - Backend vertraut blind
  • aud wird nicht geprüft - Token eines anderen Google-Clients wäre akzeptiert
  • Email als Primary-Key verwendet - User kann Email ändern, sub bleibt stabil
  • JWKS bei jedem Request neu geladen - Rate-Limit-Risiko

Im jwtdecoder.de lässt sich jedes Google-ID-Token live zerlegen - Header, Payload, exp-Check. Signature-Verifikation funktioniert mit dem passenden Public Key aus Googles JWKS.