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:
| Teil | Inhalt (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" } |
| Signature | RSA-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.comsein (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.