Feature: Server-driven auth method discovery + OIDC-only enforcement

Backend:
- New AUTH_PASSWORD_ENABLED flag (default true). When false, email/password
  registration and login return 403; the server enforces OIDC-only login.
- New OIDC_GENERIC_DISPLAY_NAME so the app can show 'Authentik'/'Keycloak'
  instead of a generic 'OIDC' label.
- New public endpoint GET /api/config returns which auth methods the
  server offers (password_enabled + per-provider OIDC capabilities).
  No auth required, so the login screen can query it before logging in.
- .env.example and docker-compose.yml expose the new env vars.

App:
- DTOs + MitbringslApi.getServerConfig() for /api/config.
- AuthViewModel: new 'connect' flow. The user enters the server URL,
  taps 'Verbinden', and the app fetches /api/config. The returned
  ServerAuthConfig drives which login options are shown:
    * password-only -> email/password form
    * OIDC-only     -> OIDC token form
    * both          -> toggle between the two
  If the server offers no method, a clear error is shown.
- AuthScreen: split into ConnectView (server URL) and LoginView (the
  login form matching the server's capabilities). The mode toggle only
  appears when the server offers more than one method.
This commit is contained in:
Tronax 2026-08-06 10:28:12 +02:00
parent b44bc8c3af
commit 3f187f1ede
Signed by: Tronax
SSH key fingerprint: SHA256:2pKKXDZucWvaF/GzXNz0FY53EAO1YDLN80bqS+TTz/o
10 changed files with 577 additions and 244 deletions

View file

@ -65,6 +65,11 @@ type userDTO struct {
// Register creates a new email/password account and immediately issues a session.
func (h *AuthHandler) Register(w http.ResponseWriter, r *http.Request) {
if !h.cfg.AuthPasswordEnabled {
renderError(w, http.StatusForbidden, "Password auth disabled",
"Email/password registration is disabled on this server. Use OIDC.")
return
}
var req registerRequest
if !decodeJSON(w, r, &req) {
return
@ -104,6 +109,11 @@ func (h *AuthHandler) Register(w http.ResponseWriter, r *http.Request) {
// Login verifies credentials and issues a session. Uses a constant-shape error
// path so a wrong password and an unknown email yield the same response.
func (h *AuthHandler) Login(w http.ResponseWriter, r *http.Request) {
if !h.cfg.AuthPasswordEnabled {
renderError(w, http.StatusForbidden, "Password auth disabled",
"Email/password login is disabled on this server. Use OIDC.")
return
}
var req loginRequest
if !decodeJSON(w, r, &req) {
return