Skip to Content

Gehostetes Login (Universal Login)

Das Problem: Wo sollte das Login-Formular wohnen?

Jede Anwendung, die Benutzer authentifiziert, muss entscheiden, wo das Login-Formular wohnt. Es gibt drei grundlegende Ansätze, und die Wahl hat tiefgreifende Sicherheitsauswirkungen.

Eingebettetes Login (der riskante Ansatz)

Die Anwendung rendert ihr eigenes Login-Formular und sammelt Anmeldedaten direkt:

Die Anmeldedaten werden an einem anderen Ursprung eingegeben — einem, der vollständig vom Identity Provider kontrolliert wird. Das JavaScript deiner Anwendung kann die Formularfelder nicht lesen, Tastenanschläge nicht abfangen oder auf die Anmeldedaten nicht zugreifen. Die Same-Origin-Richtlinie des Browsers erzwingt diese Grenze automatisch.

RisikoEingebettetes LoginGehostetes Login
XSS stiehlt AnmeldedatenJa — dein JS kann das Passwortfeld lesenNein — anderer Ursprung, dein JS kann nicht darauf zugreifen
Drittanbieter-Skript liest AnmeldedatenJa — jedes Skript in deinem Bundle läuft im selben UrsprungNein — Drittanbieter-Skripte in deinem Ursprung können die Auth-Seite nicht erreichen
Anmeldedaten-Phishing über DOM-ManipulationJa — ein Angreifer kann dein Login-Formular modifizierenNein — die Login-Seite befindet sich in der Domain des IdP
Passwort-Manager-Autofill-BereichDeine DomainDie Domain des IdP (konsistent über alle Apps)
MFA-DurchsetzungDu musst es implementierenDer IdP übernimmt es transparent
Social-Login-IntegrationDu musst jeden Provider integrierenDer IdP zeigt alle konfigurierten Provider an
Compliance-Audit-BereichDeine gesamte AnwendungNur die Login-Seiten des IdP

Gehostetes Login ist der Ansatz, der vom OAuth 2.0 Security Best Current Practice (RFC 6819, draft-ietf-oauth-security-topics) empfohlen wird. Auth0 nennt es “Universal Login”, Okta nennt es “Okta-hosted Sign-In”, und Auris nennt es “Hosted Login”. Das Sicherheitsprinzip ist dasselbe: Lass deine Anwendung niemals rohe Anmeldedaten berühren.

Funktionsweise: Der vollständige Flow

Auris Hosted Login implementiert den OAuth2-Autorisierungscode-Flow mit PKCE (RFC 7636). Hier ist die vollständige Sequenz, Schritt für Schritt.

Sequenzdiagramm

PKCE S256: Warum es wichtig ist

PKCE (Proof Key for Code Exchange) verhindert Autorisierungscode-Abfangangriffe. Der Mechanismus ist einfach, aber effektiv.

Code Verifier und Code Challenge

Bevor der Flow eingeleitet wird, generiert der Client zwei Werte:

  1. Code Verifier: Ein kryptografisch zufälliger String (43-128 Zeichen)
  2. Code Challenge: BASE64URL(SHA256(code_verifier))

Der Client sendet den Code Challenge (den Hash) an den Autorisierungs-Endpunkt. Beim Austausch des Codes gegen Tokens sendet der Client den rohen Code Verifier. Auris berechnet SHA256(code_verifier) neu und überprüft, ob er mit dem gespeicherten Code Challenge übereinstimmt.

code_verifier: "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk" │ SHA-256 + Base64URL │ ▼ code_challenge: "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM"

Warum dies Abfangen stoppt

Wenn ein Angreifer den Autorisierungscode in der Weiterleitungs-URL abfängt (über eine bösartige App, die im gleichen URI-Schema registriert ist, einen Proxy oder den Browser-Verlauf), können sie ihn nicht austauschen. Um den Code auszutauschen, benötigen sie den code_verifier — der nie durch die Browser-URL übertragen wurde. Er wurde im Speicher des Clients gespeichert und nur direkt über HTTPS an den Token-Endpunkt gesendet.

SHA-256 ist eine Einwegfunktion: Ausgehend vom Code Challenge kann der Angreifer ihn nicht umkehren, um den Code Verifier zu erhalten.

Auris erzwingt PKCE S256 bei allen Autorisierungscode-Flows. Die plain-Challenge-Methode wird abgelehnt. Es gibt keine Konfiguration zum Deaktivieren von PKCE — es ist immer erforderlich.

Sitzungsverwaltung

Auris verwendet zwei serverseitige Modelle zur Verwaltung des gehosteten Login-Flows:

OAuthSession

Wird in Schritt 3 erstellt, wenn der Benutzer am Autorisierungs-Endpunkt ankommt. Wird in der Datenbank gespeichert und durch ein httpOnly-Cookie identifiziert.

FeldBeschreibung
sessionTokenEindeutiger Bezeichner (als httpOnly, Secure, SameSite=Lax-Cookie gesetzt)
clientIdDie Anwendung, die Authentifizierung anfordert
redirectUriWohin nach der Authentifizierung weitergeleitet werden soll
codeChallengePKCE-Code-Challenge (S256)
codeChallengeMethodImmer S256
stateCSRF-State-Wert vom Client
scopeAngeforderte OAuth-Scopes
TTL30 Minuten (Sitzung läuft ab, wenn der Benutzer den Login nicht abschließt)

Die OAuthSession verfolgt den Fortschritt des Benutzers durch die gehosteten Login-Seiten. Sie bleibt über die Login-Seite, die 2FA-Seite (falls ausgelöst) und alle Social-Login-Weiterleitungen hinweg bestehen. Wenn der Benutzer den Flow abbricht, läuft die Sitzung ab und wird durch einen Cron-Job bereinigt.

AuthorizationCode

Wird in Schritt 9 nach erfolgreicher Authentifizierung erstellt.

FeldBeschreibung
codeEindeutiger Autorisierungscode
clientIdMuss mit der client_id der Token-Anfrage übereinstimmen
redirectUriMuss genau mit der redirect_uri der Token-Anfrage übereinstimmen
codeChallengeFür PKCE-Verifizierung beim Token-Austausch gespeichert
codeChallengeMethodS256
userIdDer authentifizierte Benutzer
TTL5 Minuten
usedAtWird beim ersten Gebrauch atomar gesetzt (Einmaligkeits-Durchsetzung)

Der Autorisierungscode wird über eine atomare Prisma-Transaktion verbraucht: Der Code wird als verwendet markiert und in derselben Datenbankoperation gelöscht. Wenn zwei Anfragen versuchen, denselben Code gleichzeitig zu verwenden, gelingt nur eine — die andere erhält einen Fehler.

// Atomare Einmaligkeits-Durchsetzung (vereinfacht) const code = await prisma.authorizationCode.update({ where: { code: authCode, usedAt: null, // Gelingt nur, wenn noch nicht verwendet }, data: { usedAt: new Date(), }, }) // Wenn der Code bereits verwendet wurde, wirft Prisma (Datensatz nicht mit usedAt: null gefunden)

Tenant-Branding

Die gehosteten Auris-Login-Seiten passen sich automatisch an die Branding-Konfiguration des Tenants an. Tenants konfigurieren Branding in der Auris-Konsole unter Einstellungen > Branding.

EinstellungAuswirkung auf das gehostete Login
brandingCompanyNameWird als Seitentitel und in der Kopfzeile angezeigt
brandingLogoUrlErsetzt das Standard-Auris-Logo auf der Login-Seite
brandingBackgroundColorLegt die Seitenhintergrundfarbe fest (mit Verlauf)
brandingFaviconUrlSetzt das Favicon des Browser-Tabs

Die gehosteten Login-Seiten lesen Branding aus dem HostedAuthContext, der aus der Kette clientId der OAuthSession → Anwendung → Tenant aufgelöst wird:

Das Branding wird rein mit CSS-Custom-Properties angewendet, sodass die gehosteten Seiten unabhängig vom Farbschema des Tenants korrekt gerendert werden. Die Konsole enthält eine Live-Vorschau, damit Administratoren die Auswirkungen vor der Veröffentlichung sehen können.

Die Sicherheitspipeline

Jeder Authentifizierungsversuch über das gehostete Login durchläuft die vollständige Auris-Sicherheitspipeline. Keine Schicht kann umgangen werden — sie werden sequenziell ausgeführt, und jede Schicht kann die Anfrage blockieren.

Jede Schicht ist unabhängig pro Tenant konfigurierbar. Ein kleines Startup hat möglicherweise nur Keycloak-Auth aktiviert, während ein Enterprise-Tenant alle neun Schichten aktiv haben könnte.

Alle Sicherheitsschichten umschließen ihre Logik in try/catch-Blöcken, um zu verhindern, dass der Ausfall einer einzelnen Schicht den gesamten Login-Flow zum Absturz bringt. Der Standard-Fehlermodus jeder Schicht ist jedoch, die Anfrage zu blockieren (fail-secure). Ein Absturz in der CAPTCHA-Verifizierung beispielsweise blockiert den Login, anstatt stillschweigend durchzulassen.

Social Login auf gehosteten Seiten

Auris unterstützt 9 Social-Login-Provider auf den gehosteten Login-Seiten:

ProviderProtokollSymbol
GoogleOIDCGoogle „G”
GitHubOAuth 2.0Octocat
MicrosoftOIDCMicrosoft-Logo
AppleOIDCApple-Logo
FacebookOAuth 2.0Facebook „f”
DiscordOAuth 2.0Discord-Logo
LinkedInOAuth 2.0LinkedIn „in”
Twitter/XOAuth 2.0X-Logo
SlackOAuth 2.0Slack-Raute

Wenn ein Tenant Social-Provider in der Konsole aktiviert, zeigt die gehostete Login-Seite automatisch die entsprechenden Schaltflächen an. In der Client-Anwendung sind keine Änderungen erforderlich — Social Login wird vollständig innerhalb der gehosteten Seite behandelt.

SSO-Erkennung über E-Mail-Domain

Für Tenants mit konfiguriertem Enterprise SSO (SAML 2.0 / OIDC-Federation) kann die gehostete Login-Seite SSO-Domains automatisch erkennen. Wenn der Benutzer seine E-Mail-Adresse eingibt:

  1. Die Seite ruft GET /api/auth/sso/[email protected] auf
  2. Wenn die Domain company.com verifiziert und mit einer SSO-Verbindung verknüpft ist, zeigt die Seite eine Schaltfläche „Mit SSO fortfahren” an
  3. Ein Klick darauf leitet durch den SSO-Flow (Keycloak IdP-Brokering) anstelle der Passwort-Authentifizierung weiter

Dies bietet eine nahtlose Erfahrung: Benutzer von SSO-fähigen Organisationen werden automatisch zu ihrem Unternehmens-Identity-Provider weitergeleitet.

Vergleich: Login-Ansätze

DimensionGehostetes Login (Auris)Eingebettetes LoginBenutzerdefinierte Login-Seite
SicherheitsgrenzeSame-Origin-Richtlinie des Browsers trennt Anmeldedaten vom App-CodeAnmeldedaten sind für alle Skripte im App-Ursprung zugänglichAbhängig von der Implementierung
XSS-AuswirkungXSS in deiner App kann keine Anmeldedaten stehlenXSS in deiner App kann das Passwortfeld direkt lesenXSS in deiner App kann Anmeldedaten möglicherweise erreichen
AnpassungLogo, Farben, Favicon, Hintergrund (Tenant-Branding)Vollständige Kontrolle über jeden PixelVollständige Kontrolle, aber du pflegst den Code
MFA-HandlingTransparent — Auris übernimmt TOTP, SMS, WebAuthn, adaptives MFADu musst MFA-UI und Verifizierungslogik implementierenDu musst implementieren oder delegieren
Social LoginAutomatisch — in Konsole aktivieren, Schaltflächen erscheinenDu musst jeden OAuth-Provider integrierenDu musst jeden Provider integrieren
SSO / SAMLAutomatisch — IdP-Brokering über KeycloakNicht ohne serverseitige Integration verfügbarKomplexe serverseitige Implementierung
WartungNull — Auris aktualisiert die Login-SeiteDu musst deine Auth-UI aktuell haltenDu musst die Seite pflegen
ComplianceAnmeldedaten berühren deinen Ursprung nie (sauberer Audit-Trail)Deine Anwendung ist im Umfang der Anmeldedaten-VerarbeitungAbhängig von der Architektur
ImplementierungsaufwandEin SDK-Aufruf (loginWithRedirect())Formular erstellen, API aufrufen, Fehler behandeln, Tokens speichern, MFA implementierenAlles von Grund auf erstellen
Passwort-Manager-UXKonsistent über alle Apps mit demselben Auris-TenantAnderes Autofill-Ziel pro AnwendungAnderes Autofill-Ziel pro App

Code-Beispiel: Verwendung des Auris SDK

Der empfohlene Weg zur Integration des gehosteten Logins ist über das Auris SDK. Das SDK übernimmt PKCE-Generierung, State-Verwaltung, Weiterleitungsbehandlung und Token-Speicherung automatisch.

JavaScript SDK (@auris/js)

import { AurisClient } from '@auris/js' const auris = new AurisClient({ domain: 'your-tenant.auris.example.com', clientId: 'app_abc123', redirectUri: 'https://app.ihredomain.com/callback', autoRefresh: true, }) // Login einleiten — leitet zur gehosteten Login-Seite weiter // Intern: generiert code_verifier, berechnet S256-Challenge, // generiert State, speichert beides in sessionStorage, leitet weiter await auris.loginWithRedirect() // Auf der Callback-Seite (/callback) — Code gegen Tokens austauschen // Intern: validiert State, extrahiert Code aus URL, // sendet Code + code_verifier an Token-Endpunkt, speichert Tokens const result = await auris.handleRedirectCallback() console.log(result.user) // { // id: 'usr_abc123', // email: '[email protected]', // firstName: 'Jane', // lastName: 'Doe', // roles: ['user'], // }

React SDK (@auris/react)

import { AurisProvider, useAuris, AuthGuard } from '@auris/react' // Deine App mit AurisProvider umhüllen function App() { return ( <AurisProvider domain="your-tenant.auris.example.com" clientId="app_abc123" redirectUri="https://app.ihredomain.com/callback" > <Router /> </AurisProvider> ) } // Den Hook in einer beliebigen Komponente verwenden function LoginButton() { const { loginWithRedirect, isAuthenticated, user, logout } = useAuris() if (isAuthenticated) { return ( <div> <span>Willkommen, {user.firstName}</span> <button onClick={() => logout()}>Abmelden</button> </div> ) } return <button onClick={() => loginWithRedirect()}>Anmelden</button> } // Routen mit AuthGuard schützen function ProtectedPage() { return ( <AuthGuard> <Dashboard /> </AuthGuard> ) }

Next.js SDK (@auris/nextjs)

// middleware.ts — Routen am Edge schützen import { aurisMiddleware } from '@auris/nextjs' export default aurisMiddleware({ protectedPaths: ['/dashboard', '/settings', '/admin'], publicPaths: ['/', '/about', '/pricing'], loginPath: '/auth/login', }) export const config = { matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'], }
// Server Component — Auth auf dem Server prüfen import { getSession } from '@auris/nextjs/server' export default async function DashboardPage() { const session = await getSession() if (!session) { redirect('/auth/login') } return <h1>Willkommen, {session.user.firstName}</h1> }

Weiterleitungs-URI-Validierung

Auris erzwingt eine strikte Weiterleitungs-URI-Validierung, um den Diebstahl von Autorisierungscodes über Open-Redirect-Angriffe zu verhindern.

Regeln

RegelBeschreibung
Exakte ÜbereinstimmungDie redirect_uri in der Token-Anfrage muss genau mit der an den Autorisierungs-Endpunkt gesendeten übereinstimmen
VorregistriertDie redirect_uri muss im redirectUris-Array der Anwendung in der Auris-Konsole registriert sein
Keine WildcardsWildcard-Weiterleitungs-URIs (z. B. https://*.example.com/callback) werden nicht unterstützt
Keine FragmenteURIs mit #fragment-Komponenten werden abgelehnt
HTTPS erforderlichHTTP-Weiterleitungs-URIs werden in der Produktion abgelehnt (localhost ist für die Entwicklung erlaubt)

Wenn die redirect_uri nicht mit einem registrierten Wert übereinstimmt, gibt Auris eine Fehlerseite direkt zurück (es leitet nicht zur nicht übereinstimmenden URI weiter, da dies den Zweck zunichte machen würde).

Warum exakte Übereinstimmung?

Partielle Übereinstimmung (z. B. Präfix-Übereinstimmung wie https://app.example.com/) schafft eine Schwachstelle: Ein Angreifer könnte https://app.example.com/evil-page registrieren und Autorisierungscodes dorthin leiten lassen. Exakte Übereinstimmung eliminiert diese Angriffskategorie vollständig.

Füge bei der Registrierung von Weiterleitungs-URIs in der Auris-Konsole den vollständigen Pfad einschließlich aller nachfolgenden Komponenten ein. https://app.example.com/callback und https://app.example.com/callback/ werden als verschiedene URIs behandelt. Registriere genau die URI, die deine Anwendung verwenden wird.

Bereinigung und Ablauf

Auris führt einen Cron-Job (/api/oauth/cron/cleanup/) zur Bereinigung abgelaufener Sitzungen und Codes aus:

RessourceTTLBereinigungsverhalten
OAuthSession30 MinutenGelöscht, wenn nicht innerhalb der TTL abgeschlossen
AuthorizationCode5 MinutenGelöscht, wenn nicht innerhalb der TTL ausgetauscht
Verwendete AuthorizationCodesSofortBeim Verbrauch atomar gelöscht

Der Cron läuft periodisch (konfiguriert in vercel.json) und stellt sicher, dass die Datenbank keine veralteten Sitzungen aus abgebrochenen Login-Flows ansammelt.

Verwandte Konzepte