mitbringsl/backend/internal/httpapi/config.go
Tronax 3f187f1ede
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.
2026-08-06 10:28:12 +02:00

62 lines
1.7 KiB
Go

package httpapi
import (
"net/http"
"github.com/mitbringsl/backend/internal/config"
)
// ConfigHandler exposes the public server configuration that the Android app
// needs before logging in (e.g. which auth methods are available).
type ConfigHandler struct {
cfg *config.Config
}
// NewConfigHandler creates a ConfigHandler.
func NewConfigHandler(cfg *config.Config) *ConfigHandler {
return &ConfigHandler{cfg: cfg}
}
// serverConfigResponse is the public config payload returned to the app.
type serverConfigResponse struct {
Auth authConfig `json:"auth"`
}
// authConfig describes which login methods the server offers.
type authConfig struct {
PasswordEnabled bool `json:"password_enabled"`
OIDC oidcProvidersDTO `json:"oidc"`
}
type oidcProvidersDTO struct {
Google oidcProviderDTO `json:"google"`
Generic oidcProviderDTO `json:"generic"`
}
type oidcProviderDTO struct {
Enabled bool `json:"enabled"`
Issuer string `json:"issuer,omitempty"`
DisplayName string `json:"display_name,omitempty"`
}
// Config returns the public server configuration.
// GET /api/config (public, no auth required)
func (h *ConfigHandler) Config(w http.ResponseWriter, r *http.Request) {
renderJSON(w, http.StatusOK, serverConfigResponse{
Auth: authConfig{
PasswordEnabled: h.cfg.AuthPasswordEnabled,
OIDC: oidcProvidersDTO{
Google: oidcProviderDTO{
Enabled: h.cfg.GoogleOIDC.Enabled,
Issuer: h.cfg.GoogleOIDC.Issuer,
DisplayName: "Google",
},
Generic: oidcProviderDTO{
Enabled: h.cfg.GenericOIDC.Enabled,
Issuer: h.cfg.GenericOIDC.Issuer,
DisplayName: h.cfg.GenericOIDC.DisplayName,
},
},
},
})
}