feat(proxy): add /auth/token and /auth/refresh endpoints (#18)
CI / CI (push) Successful in 4m2s

Closes homelab#6 (P3.1) and homelab#8 (P3.3)

## Endpoints

| Path | Method | Body | What it does |
|------|--------|------|-------------|
| `/auth/token` | POST | `{username, password, scope?}` | Password grant → JWT |
| `/auth/refresh` | POST | `{refresh_token, scope?}` | Refresh grant → new JWT |

Both proxy to Authentik `tokenUrl` (from P3.7 config). Upstream response forwarded verbatim — client sees Authentik errors directly.
This commit was merged in pull request #18.
This commit is contained in:
2026-09-09 00:00:07 +00:00
parent ddee0f2dc9
commit a51c14426f
3 changed files with 491 additions and 0 deletions
+16
View File
@@ -29,6 +29,8 @@ type Handler struct {
config *config.Config
// jwtValidator validates JWT tokens for authenticated endpoints
jwtValidator *auth.Validator
// authHTTP is the HTTP client for token exchange with the identity provider.
authHTTP authClient
// Default timeouts for synthesized routes (model-based dispatch)
defaultConnectTimeout time.Duration
defaultReadTimeout time.Duration
@@ -86,6 +88,10 @@ func New(cfg *config.Config) *Handler {
)
}
if cfg.Auth.TokenURL != "" {
h.authHTTP = newAuthClient()
}
for name, route := range cfg.Routes {
// Create a transport per unique upstream address for connection reuse
transport := h.getOrCreateTransport(route.Upstream.Address, &route.Upstream)
@@ -228,6 +234,16 @@ func writeProblemDetail(w http.ResponseWriter, status int, problemType, title, d
// ServeHTTP implements http.Handler.
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Auth endpoints — no JWT required (they issue tokens)
if r.URL.Path == "/auth/token" {
h.handleAuthToken(w, r)
return
}
if r.URL.Path == "/auth/refresh" {
h.handleAuthRefresh(w, r)
return
}
// Handle /v1/models endpoint (no routing needed, derived from config)
if r.URL.Path == "/v1/models" && r.Method == "GET" {
h.handleModelsEndpoint(w, r)