External authentication (ADR 0021) built on jose (#188's vetted library) plus fetch — no new dependency enters the supply chain for a security base function. Discovery-configured; ID tokens validate against the IdP's JWKS under an explicit RS256/ES256 allowlist with issuer, audience, expiry and nonce binding. State, nonce and the PKCE verifier travel in a signed HttpOnly Lax cookie keyed by a dedicated HKDF purpose (oidc-state, ADR 0020). Deploy-level configuration (OIDC_ISSUER/CLIENT_ID/CLIENT_SECRET/SCOPES/ PROVIDER_LABEL): who authenticates users is a platform decision. The login page discovers the provider via GET /auth/methods and renders the SSO button (i18n de+en). Identities use the existing slot (provider oidc:<issuer>, subject from the token). First login creates the account just-in-time — ACTIVE and mail-verified only when the IdP asserts a verified address. An existing local account is NEVER adopted silently by e-mail (account-takeover path): login refuses with oidc_link_required and the owner links explicitly via GET /auth/oidc/link (audited auth.identity_linked, catalogue v1.3). Sessions come from the one existing session service. Tests run the full flow against a protocol-faithful fake IdP: PKCE verifier at the token endpoint, JIT creation incl. personal pond, invalid state/nonce/signature/issuer/audience/expiry each rejected, the linking refusal and the explicit link flow. Verified end-to-end against a real Keycloak 26.0 (repeatable procedure documented in security.md §External authentication). Refs #214. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AUtYMxwTCMHG9mVHnwbFg8
88 lines
3.6 KiB
JSON
88 lines
3.6 KiB
JSON
{
|
|
"login": {
|
|
"title": "Anmelden",
|
|
"usernameOrEmail": "Benutzername oder E-Mail",
|
|
"password": "Passwort",
|
|
"submit": "Anmelden",
|
|
"forgot": "Passwort vergessen?",
|
|
"noAccount": "Noch kein Konto?",
|
|
"signupLink": "Jetzt registrieren",
|
|
"resendHint": "Keine Bestätigungs-Mail bekommen?",
|
|
"resendLink": "Erneut senden"
|
|
},
|
|
"signup": {
|
|
"title": "Konto anlegen",
|
|
"username": "Benutzername",
|
|
"usernameHint": "Buchstaben, Ziffern, Bindestriche — deine Adresse im Dorfteich.",
|
|
"email": "E-Mail-Adresse",
|
|
"displayName": "Anzeigename",
|
|
"password": "Passwort",
|
|
"passwordHint": "Mindestens 10 Zeichen. Ein kurzer Satz funktioniert gut.",
|
|
"submit": "Registrieren",
|
|
"haveAccount": "Schon registriert?",
|
|
"loginLink": "Anmelden",
|
|
"closed": "Die Registrierung ist auf dieser Instanz derzeit geschlossen.",
|
|
"success": {
|
|
"title": "Schau in dein Postfach",
|
|
"body": "Wir haben einen Bestätigungslink an {{email}} geschickt. Er ist 24 Stunden gültig.",
|
|
"resend": "Mail erneut senden"
|
|
}
|
|
},
|
|
"verify": {
|
|
"title": "E-Mail-Adresse wird bestätigt …",
|
|
"success": {
|
|
"title": "E-Mail-Adresse bestätigt",
|
|
"body": "Dein Konto ist aktiv — du kannst dich jetzt anmelden.",
|
|
"login": "Zur Anmeldung"
|
|
},
|
|
"error": {
|
|
"title": "Dieser Link hat nicht funktioniert",
|
|
"resendPrompt": "Gib deine E-Mail-Adresse ein, wir schicken dir einen frischen Link:",
|
|
"resend": "Neuen Link senden"
|
|
},
|
|
"resent": "Falls die Adresse zu einem unbestätigten Konto gehört, ist eine neue Mail unterwegs."
|
|
},
|
|
"forgot": {
|
|
"title": "Passwort zurücksetzen",
|
|
"body": "Gib deine E-Mail-Adresse ein. Falls ein Konto existiert, bekommst du einen Link zum Zurücksetzen (eine Stunde gültig).",
|
|
"email": "E-Mail-Adresse",
|
|
"submit": "Link senden",
|
|
"sent": "Erledigt — schau in dein Postfach.",
|
|
"backToLogin": "Zurück zur Anmeldung"
|
|
},
|
|
"reset": {
|
|
"title": "Neues Passwort setzen",
|
|
"password": "Neues Passwort",
|
|
"submit": "Passwort speichern",
|
|
"success": {
|
|
"title": "Passwort gespeichert",
|
|
"body": "Alle bisherigen Sitzungen wurden abgemeldet. Melde dich mit dem neuen Passwort an.",
|
|
"login": "Zur Anmeldung"
|
|
}
|
|
},
|
|
"menu": {
|
|
"settings": "Einstellungen",
|
|
"admin": "Administration",
|
|
"logout": "Abmelden",
|
|
"login": "Anmelden",
|
|
"signup": "Registrieren"
|
|
},
|
|
"oidc": {
|
|
"signIn": "Anmelden mit {{provider}}",
|
|
"or": "oder",
|
|
"errors": {
|
|
"oidc_failed": "Die Anmeldung über Single Sign-on ist fehlgeschlagen. Bitte erneut versuchen.",
|
|
"oidc_cancelled": "Die Single-Sign-on-Anmeldung wurde abgebrochen.",
|
|
"oidc_state_invalid": "Der Anmeldeversuch ist abgelaufen. Bitte erneut versuchen.",
|
|
"oidc_exchange_failed": "Der Identitätsanbieter hat die Anmeldung abgelehnt. Bitte erneut versuchen.",
|
|
"oidc_token_invalid": "Die Antwort des Identitätsanbieters konnte nicht geprüft werden.",
|
|
"oidc_discovery_failed": "Der Identitätsanbieter ist derzeit nicht erreichbar.",
|
|
"oidc_email_missing": "Der Identitätsanbieter hat keine E-Mail-Adresse übermittelt.",
|
|
"oidc_email_unverified": "Deine E-Mail-Adresse ist beim Identitätsanbieter nicht bestätigt.",
|
|
"oidc_link_required": "Ein Konto mit dieser E-Mail-Adresse existiert bereits. Melde dich mit Passwort an und verknüpfe Single Sign-on in den Einstellungen.",
|
|
"oidc_identity_taken": "Diese Single-Sign-on-Identität ist bereits mit einem anderen Konto verknüpft.",
|
|
"account_disabled": "Dieses Konto ist deaktiviert."
|
|
}
|
|
}
|
|
}
|