v2.0.0 — Jellyfin Security
Plugin rename from Two-Factor Authentication to Jellyfin Security. GUID unchanged — upgrades in place.
🆕 New features
- OIDC / SSO sign-in — Google, Microsoft/Entra, Apple, Authelia, Authentik, Keycloak, PocketID, Cloudflare Access, or any OIDC-compliant IdP. PKCE S256, id_token signature + issuer + audience + nonce validation, optional AMR-based IdP-MFA enforcement, optional group allowlist.
- Brute-force IP banning (Fail2Ban-style) — configurable threshold/window/duration, persisted across restarts, LAN/trusted-proxy/exempt CIDRs always bypass. Admin IP Bans tab lists/unbans + manual ban.
- Impossible-travel detection — notifies when consecutive sign-ins exceed commercial-jet speed. Uses MaxMind GeoLite2-City for lat/lon.
- Per-user IP allowlist — pin high-value accounts to specific CIDRs. Self-service in Setup.
- Login-page provider buttons — each configured SSO provider appears below the normal form.
- Linked Sign-In Methods card in user Setup for self-service unlink.
- Pill-style admin tab bar with new Sign-in Methods and IP Bans tabs.
🔒 Security hardening
X-Forwarded-Host/Protoonly honoured when peer matches TrustedProxyCidrs (prevents redirect_uri poisoning).- Rate limit on
/Oidc/Login(20 per 5 min per IP). - Bridge HTML uses
JsonSerializer.Serializefor JS-context injection + strict CSP +Cache-Control: no-store. returnUrlvalidated to same-origin relative paths.- New
/TwoFactorAuth/MyStatus(auth-only) so the Setup page shows correct TOTP state without admin permission.
🐛 Bug fixes
- TOTP replay cache cleared on new-secret generation — fixed "Invalid code" false-positive when Begin Setup ran twice.
- Setup page no longer silently shows "NOT SET UP" for non-admin users.
- Default-auth provider delegation now uses
IRequiresResolvedUsercorrectly (Jellyfin 10.11'sDefaultAuthenticationProviderthrowsNotImplementedExceptionon the plainAuthenticateoverload). - Provider no longer throws the 2FA challenge as an AuthenticationException — Jellyfin swallowed the payload.
TwoFactorEnforcementMiddlewarerewrites the 200 auth response with the challenge body, as intended.
📦 Installation
Adds JSON: https://raw.githubusercontent.com/ZL154/JellyfinSecurity/main/manifest.json in Dashboard → Plugins → Repositories, then install Jellyfin Security from the catalog.
SHA / MD5: `ACD2EC0221D308D773D3755951E1DDA3`
See README for full walkthrough (Google, Microsoft, Authelia, etc.), per-provider options, IP ban admin, and impossible-travel setup.