Authentifizierung oder Autorisierung: Die richtige Wahl für Ihr Backend treffen
James Reed
Infrastructure Engineer · Leapcell

Einleitung
In der dynamischen Welt der Backend-Entwicklung ist die sichere Verwaltung des Benutzerzugriffs von größter Bedeutung. Egal, ob Sie eine elegante Microservice-Architektur oder eine monolithische Unternehmensanwendung erstellen, die Frage "Wer ist dieser Benutzer?" und "Was kann dieser Benutzer tun?" taucht unweigerlich auf. Viele Entwickler und sogar erfahrene Architekten stoßen häufig auf eine konzeptionelle Unschärfe zwischen den Mechanismen, die darauf abzielen, diese beiden unterschiedlichen Fragen zu beantworten. Diese Verwirrung führt häufig zu Fehltritten, von der Überkonstruktion einfacher Lösungen bis hin zur – kritischeren – Einführung von Sicherheitslücken. Das Verständnis der genauen Rollen von Authentifizierung und Autorisierung, und insbesondere wie OpenID Connect (OIDC) und OAuth 2.0 in diese Landschaft passen, ist nicht nur akademisch; es wirkt sich direkt auf die Sicherheit, Skalierbarkeit und Wartbarkeit Ihrer Backend-Systeme aus. Dieser Artikel zielt darauf ab, diese Konzepte zu klären und Sie bei der Auswahl der am besten geeigneten Lösung für Ihre spezifischen Backend-Anforderungen zu unterstützen.
Kernkonzepte erklärt
Bevor wir uns mit den Besonderheiten von OIDC und OAuth 2.0 befassen, wollen wir ein klares Verständnis der grundlegenden Begriffe schaffen, die dieser Diskussion zugrunde liegen.
- Authentifizierung: Der Prozess der Überprüfung der Identität eines Benutzers. Sie beantwortet die Frage: "Sind Sie der, der Sie vorgeben zu sein?" Wenn Sie sich mit einem Benutzernamen und Passwort bei einer Anwendung anmelden, authentifizieren Sie sich.
 - Autorisierung: Der Prozess der Bestimmung, was ein authentifizierter Benutzer oder eine Anwendung tun darf. Sie beantwortet die Frage: "Was dürfen Sie zugreifen oder ausführen?" Zum Beispiel kann ein authentifizierter Benutzer berechtigt sein, sein eigenes Profil anzuzeigen, aber nicht das Profil eines anderen Benutzers zu bearbeiten.
 - Identitätsanbieter (IdP): Ein Dienst, der Identitätsinformationen für Benutzer erstellt, pflegt und verwaltet und dann Authentifizierungsdienste für andere Anwendungen (Dienstanbieter) bereitstellt. Beispiele hierfür sind Google, Facebook oder ein Unternehmens-LDAP-Server.
 - Ressourcenserver: Der Server, der die geschützten Ressourcen hostet (z. B. APIs, Benutzerdaten).
 - Clientanwendung: Die Anwendung, die im Namen eines Benutzers auf geschützte Ressourcen zugreifen möchte. Dies kann eine Webanwendung, eine mobile App oder ein anderer Backend-Dienst sein.
 
OAuth 2.0: Das Autorisierungs-Framework
OAuth 2.0 ist ein Autorisierungs-Framework, das es einer Clientanwendung ermöglicht, "delegierten Zugriff" auf geschützte Ressourcen im Namen eines Ressourceneigners (typischerweise eines Benutzers) zu erhalten, ohne die Anmeldeinformationen des Ressourceneigners jemals an den Client preiszugeben. Es befasst sich nicht direkt mit der Benutzerauthentifizierung. Stattdessen bietet es eine sichere Methode für eine Clientanwendung, ein Zugriffstoken zu erhalten, das dann für den Zugriff auf geschützte Ressourcen verwendet wird.
Wie OAuth 2.0 funktioniert
Der Kernablauf von OAuth 2.0, typischerweise der Authorization Code Grant-Typ, sieht wie folgt aus:
- Client fordert Autorisierung an: Die Clientanwendung (z. B. Ihr Backend) leitet den Browser des Benutzers zum Autorisierungsserver weiter und fordert Zugriff auf bestimmte Ressourcen (Scopes) an.
 - Benutzer erteilt Autorisierung: Der Benutzer authentifiziert sich über die Benutzeroberfläche des Autorisierungsservers mit dem Autorisierungsserver (mithilfe seiner Anmeldeinformationen, z. B. Benutzername/Passwort) und erteilt der Clientanwendung die Erlaubnis, auf die angeforderten Ressourcen zuzugreifen.
 - Autorisierungsserver leitet mit Autorisierungscode weiter: Der Autorisierungsserver leitet den Browser des Benutzers mit einem einmalig verwendbaren 
authorization_codezurück zur Clientanwendung. - Client tauscht Code gegen Tokens: Die Clientanwendung sendet unter Verwendung ihrer vertraulichen Client-Anmeldeinformationen und des 
authorization_codeeine direkte Anfrage an den Token-Endpunkt des Autorisierungsservers. - Autorisierungsserver stellt Tokens aus: Der Autorisierungsserver validiert die Anfrage und stellt ein 
access_token(und optional einrefresh_token) aus. - Client greift auf geschützte Ressourcen zu: Die Clientanwendung verwendet das 
access_token, um Anfragen an den Ressourcenserver zu stellen. 
Wann OAuth 2.0 verwendet werden sollte
Sie benötigen OAuth 2.0, wenn Ihre Backend-Anwendung Folgendes tun muss:
- Auf APIs von Drittanbietern im Namen eines Benutzers zugreifen: Zum Beispiel, wenn Ihre Anwendung Beiträge im Facebook-Feed eines Benutzers posten, dessen Google Kalender einsehen oder Daten von dessen GitHub-Konto abrufen möchte. In diesem Szenario ist Ihr Backend die "Clientanwendung" und Facebook/Google/GitHub sind die "Resserv server".
 - Granulare Zugriffskontrolle zwischen Diensten ermöglichen: In einer Microservice-Architektur muss ein Dienst möglicherweise auf die Daten eines anderen Dienstes zugreifen, aber nur auf bestimmte Endpunkte oder mit bestimmten Berechtigungen. OAuth 2.0 kann diese serviceübergreifende Autorisierung erleichtern.
 
Beispiel: Verwendung von OAuth 2.0 für den Zugriff auf APIs von Drittanbietern (Konzeptionell)
Stellen Sie sich vor, Ihr Backend ist in Python mit Flask geschrieben und benötigt Zugriff auf die Google Drive-Dateien eines Benutzers.
# Dies ist stark vereinfacht und konzeptionell. Eine reale Implementierung würde # eine Bibliothek wie Authlib oder google-auth-oauthlib verwenden und Zustand, PKCE usw. behandeln. from flask import Flask, redirect, url_for, session, request import requests import os app = Flask(__name__) app.secret_key = os.urandom(24) # Ersetzen Sie dies durch einen starken, permanenten Schlüssel GOOGLE_CLIENT_ID = os.environ.get("GOOGLE_CLIENT_ID") GOOGLE_CLIENT_SECRET = os.environ.get("GOOGLE_CLIENT_SECRET") GOOGLE_AUTH_URL = "https://accounts.google.com/o/oauth2/v2/auth" GOOGLE_TOKEN_URL = "https://oauth2.googleapis.com/token" GOOGLE_DRIVE_API_URL = "https://www.googleapis.com/drive/v3/files" REDIRECT_URI = "http://localhost:5000/callback" @app.route('/') def index(): if 'google_access_token' in session: return f"Hallo, Sie sind mit Google authentifiziert. <a href='{url_for('list_drive_files')}'>Drive-Dateien anzeigen</a>" return '<a href="/login_google">Mit Google anmelden</a>' @app.route('/login_google') def login_google(): params = { "client_id": GOOGLE_CLIENT_ID, "redirect_uri": REDIRECT_URI, "response_type": "code", "scope": "https://www.googleapis.com/auth/drive.readonly", # Lesezugriff auf Drive anfordern "access_type": "offline", # Um ein Aktualisierungstoken zu erhalten "prompt": "consent" } auth_url = f"{GOOGLE_AUTH_URL}?{'&'.join([f'{k}={v}' for k,v in params.items()])}" return redirect(auth_url) @app.route('/callback') def callback(): code = request.args.get('code') if not code: return "Autorisierungscode fehlt!", 400 token_payload = { "client_id": GOOGLE_CLIENT_ID, "client_secret": GOOGLE_CLIENT_SECRET, "code": code, "grant_type": "authorization_code", "redirect_uri": REDIRECT_URI } response = requests.post(GOOGLE_TOKEN_URL, data=token_payload) token_data = response.json() if 'access_token' in token_data: session['google_access_token'] = token_data['access_token'] # Optional Aktualisierungstoken speichern für langlebigen Zugriff # session['google_refresh_token'] = token_data['refresh_token'] return redirect(url_for('index')) return "Fehler beim Abrufen des Zugriffstokens.", 500 @app.route('/drive_files') def list_drive_files(): access_token = session.get('google_access_token') if not access_token: return "Nicht mit Google Drive authentifiziert.", 401 headers = { "Authorization": f"Bearer {access_token}" } response = requests.get(GOOGLE_DRIVE_API_URL + "?q='me' in owners", headers=headers) if response.status_code == 200: files = response.json().get('files', []) file_names = [f['name'] for f in files] return f"Ihre Google Drive-Dateien: {', '.join(file_names)}" else: return f"Fehler beim Zugriff auf Google Drive: {response.text}", response.status_code if __name__ == '__main__': app.run(debug=True)
In diesem Beispiel fungiert Ihr Flask-Backend als OAuth 2.0-Client. Es delegiert die Authentifizierung des Benutzers an Google und erhält dann mit Zustimmung des Benutzers ein access_token, um im Namen des Benutzers mit Google Drive zu interagieren. Der Benutzer gibt niemals sein Google-Passwort in Ihre Anwendung ein.
OpenID Connect (OIDC): Authentifizierung auf Basis von OAuth 2.0
OIDC ist eine Authentifizierungsschicht, die auf dem OAuth 2.0-Framework aufbaut. Während OAuth 2.0 die Autorisierung (delegierter Zugriff) handhabt, kümmert sich OIDC um die Authentifizierung und stellt überprüfbare Informationen über die Identität des Endbenutzers bereit. Es verwendet OAuth 2.0-Flows, um seine Ziele zu erreichen. Das bedeutet, wenn Sie OAuth 2.0 verstehen, sind Sie auf halbem Weg, OIDC zu verstehen.
Wie OIDC funktioniert
OIDC führt ein neues Artefakt ein: den ID Token. Dies ist ein JSON Web Token (JWT), das Claims (Assertions) über den authentifizierten Benutzer enthält, wie seine Benutzer-ID, Name, E-Mail und ob seine E-Mail verifiziert wurde. Der typische OIDC-Flow sieht wie folgt aus (unter Verwendung des Authorization Code Flow für OIDC):
- Client fordert Authentifizierung an: Die Clientanwendung leitet den Benutzer zum OIDC-Anbieter (der auch ein OAuth 2.0-Autorisierungsserver ist) weiter. Die Anfrage enthält den 
openid-Scope, der eine OIDC-Anfrage kennzeichnet, zusammen mit allen anderen gewünschten Scopes (z. B.profile,email). - Benutzer authentifiziert sich und stimmt zu: Der Benutzer authentifiziert sich beim OIDC-Anbieter und stimmt zu, seine Identitätsinformationen mit der Clientanwendung zu teilen.
 - Autorisierungsserver leitet mit Autorisierungscode weiter: Der OIDC-Anbieter leitet den Benutzer mit einem 
authorization_codezurück zur Clientanwendung. - Client tauscht gegen Tokens: Die Clientanwendung sendet den 
authorization_codezusammen mit ihren Client-Anmeldeinformationen an den Token-Endpunkt des OIDC-Anbieters. - OIDC-Anbieter stellt Tokens aus: Der OIDC-Anbieter antwortet mit einem 
access_token, einemrefresh_token(optional) und entscheidend einemid_token. - Client überprüft und verwendet 
id_token: Die Clientanwendung überprüft denid_token(überprüft Signatur, Aussteller, Zielgruppe, Ablaufdatum), um die Identität des Benutzers zu bestätigen. Nach der Überprüfung kann der Client Benutzerinformationen aus denid_token-Claims extrahieren. - Client verwendet 
access_tokenzur Autorisierung: Wenn zusätzlicher Ressourcenaufruf angefordert wurde (über non-openid-Scopes), kann der Client dann dasaccess_tokenverwenden, um geschützte APIs aufzurufen. 
Wann OIDC verwendet werden sollte
Sie benötigen OIDC, wenn Ihre Backend-Anwendung Folgendes tun muss:
- Benutzer authentifizieren: Dies ist der primäre Anwendungsfall. Wenn Sie möchten, dass sich Benutzer mit ihrer Google-, GitHub- oder einer anderen OIDC-kompatiblen Identität bei Ihrer Anwendung anmelden können, ist OIDC die Lösung.
 - Single Sign-On (SSO) implementieren: OIDC ist grundlegend für SSO. Sobald sich ein Benutzer bei einem OIDC-Anbieter angemeldet hat, kann er nahtlos auf mehrere Anwendungen zugreifen, die mit demselben Anbieter verbunden sind, ohne sich erneut authentifizieren zu müssen.
 - Benutzerprofilinformationen abrufen: Der 
id_tokenbietet eine standardisierte Möglichkeit, grundlegende Benutzerattribute wie Name, E-Mail und Profilbild direkt vom Identitätsanbieter abzurufen. 
Beispiel: Verwendung von OIDC zur Benutzerauthentifizierung (Konzeptionell)
Angenommen, Ihr Backend muss Benutzer über die OIDC-Funktionen von Google authentifizieren und dann deren Sitzung verwalten.
# Wiederum stark vereinfacht. Bibliotheken wie Authlib vereinfachen dies erheblich. from flask import Flask, redirect, url_for, session, request, jsonify import requests import os import jwt # PyJWT für die Überprüfung des ID Tokens app = Flask(__name__) app.secret_key = os.urandom(24) # Ersetzen Sie dies durch einen starken, permanenten Schlüssel GOOGLE_OIDC_CLIENT_ID = os.environ.get("GOOGLE_OIDC_CLIENT_ID") GOOGLE_OIDC_CLIENT_SECRET = os.environ.get("GOOGLE_OIDC_CLIENT_SECRET") GOOGLE_DISCOVERY_URL = "https://accounts.google.com/.well-known/openid-configuration" REDIRECT_URI = "http://localhost:5000/oidc_callback" # OIDC-Metadaten abrufen (z. B. authorization_endpoint, token_endpoint, jwks_uri) # In einer realen App würden diese zwischengespeichert und aktualisiert. response = requests.get(GOOGLE_DISCOVERY_URL) OIDC_METADATA = response.json() @app.route('/') def index(): if 'user_info' in session: user = session['user_info'] return f"Hallo, {user.get('name', user.get('sub'))}! <a href='/logout'>Abmelden</a>" return '<a href="/login_oidc">Mit Google anmelden (OIDC)</a>' @app.route('/login_oidc') def login_oidc(): params = { "client_id": GOOGLE_OIDC_CLIENT_ID, "redirect_uri": REDIRECT_URI, "response_type": "code", "scope": "openid profile email", # Wichtiger 'openid'-Scope für OIDC "access_type": "offline", "prompt": "consent" } auth_url = f"{OIDC_METADATA['authorization_endpoint']}?{'&'.join([f'{k}={v}' for k,v in params.items()])}" return redirect(auth_url) @app.route('/oidc_callback') def oidc_callback(): code = request.args.get('code') if not code: return "Autorisierungscode fehlt!", 400 token_payload = { "client_id": GOOGLE_OIDC_CLIENT_ID, "client_secret": GOOGLE_OIDC_CLIENT_SECRET, "code": code, "grant_type": "authorization_code", "redirect_uri": REDIRECT_URI } response = requests.post(OIDC_METADATA['token_endpoint'], data=token_payload) token_data = response.json() if 'id_token' in token_data: id_token = token_data['id_token'] # --- ID Token Überprüfung (Wichtiger Sicherheitsschritt) --- # 1. JWKS vom Anbieter abrufen, um die Signatur zu überprüfen jwks_response = requests.get(OIDC_METADATA['jwks_uri']) jwks = jwks_response.json() # In einer realen App würde man eine robuste JWT-Bibliothek wie PyJWT # mit geeigneter Schlüsselbeschaffung und Validierung verwenden. # Dies ist ein vereinfachtes Beispiel. try: # Muss den richtigen Schlüssel aus jwks abrufen header = jwt.get_unverified_header(id_token) key = None for jwk in jwks['keys']: if jwk['kid'] == header['kid']: key = jwk break if not key: raise ValueError("Passender JWK für KID nicht gefunden") public_key = jwt.decode(id_token, key, algorithms=[header['alg']], audience=GOOGLE_OIDC_CLIENT_ID, issuer=OIDC_METADATA['issuer'], options={"verify_signature": True}) # Zusätzliche Validierungen (z. B. nonce, Ablaufdatum, 'azp'-Claim) würden hier folgen session['user_info'] = public_key return redirect(url_for('index')) except jwt.exceptions.PyJWTError as e: app.logger.error(f"ID Token Überprüfung fehlgeschlagen: {e}") return "ID Token Überprüfung fehlgeschlagen.", 401 return "Fehler beim Abrufen des ID Tokens.", 500 @app.route('/logout') def logout(): session.pop('user_info', None) # Optional Zugriff-/Aktualisierungstokens widerrufen, wenn sie gespeichert wurden return redirect(url_for('index')) if __name__ == '__main__': app.run(debug=True)
Hier verwendet Ihr Flask-Backend OIDC, um den Benutzer über Google zu authentifizieren. Der erhaltene id_token wird überprüft und die darin enthaltenen Claims werden verwendet, um eine Benutzersitzung in Ihrer Anwendung einzurichten. Jetzt weiß Ihr Backend, wer der Benutzer ist. Das access_token (ebenfalls erhalten) könnte verwendet werden, um Google APIs aufzurufen, wenn zusätzliche Berechtigungen angefordert wurden, aber der id_token allein bestätigt die Identität.
Authentifizierung vs. Autorisierung: Eine klare Unterscheidung
Der wichtigste Punkt ist, dass OIDC für die Authentifizierung (Wer ist dieser Benutzer?) und OAuth 2.0 für die Autorisierung (Was darf er tun?) ist.
- Wenn Ihr Hauptziel darin besteht, Benutzern zu ermöglichen, sich mit einer externen Identitätsanbieter (wie Google, Facebook, Okta, Auth0) bei Ihrer Anwendung anzumelden, benötigen Sie OIDC. Sie verwenden den 
id_token, um ihre Identität zu bestätigen. - Wenn Ihr Hauptziel darin besteht, dass Ihre Anwendung im Namen eines Benutzers (oder sogar eines anderen Dienstes) sicher auf die geschützten Ressourcen einer anderen Anwendung zugreift, benötigen Sie OAuth 2.0. Sie verwenden das 
access_token, um autorisierte Anfragen zu stellen. 
Es ist üblich, beide zusammen zu verwenden. Zum Beispiel könnte sich ein Benutzer bei Ihrer Anwendung anmelden (Authentifizierung über OIDC), und dann muss Ihre Anwendung auf dessen Google Kalender zugreifen (Autorisierung über OAuth 2.0) – beides ausgelöst durch eine einzige Interaktion mit Google. Der anfängliche OIDC-Flow würde sowohl ein id_token als auch ein access_token zurückgeben (vorausgesetzt, entsprechende Scopes wurden angefordert).
Fazit
Die Wahl zwischen OpenID Connect und OAuth 2.0 für Ihr Backend läuft auf eine grundlegende Frage hinaus: Versuchen Sie zu überprüfen, wer ein Benutzer ist, oder versuchen Sie zu verwalten, was er tun kann? OIDC baut auf OAuth 2.0 auf, um robuste Authentifizierungsfunktionen zu liefern und eine standardisierte Möglichkeit zur Bestätigung der Benutzeridentität zu bieten. OAuth 2.0 hingegen bleibt der Industriestandard für die delegierte Autorisierung, der einen sicheren Zugriff auf geschützte Ressourcen ermöglicht, ohne Anmeldeinformationen preiszugeben. Für Benutzeranmeldungen und Identitätsinformationen verwenden Sie OIDC; für den delegierten Zugriff auf externe APIs verwenden Sie OAuth 2.0.

