fix: handle 401 gracefully on web; add Bearer token auth for Tauri

- fetchMe() no longer surfaces 401 as a user-facing error (it just
  means 'no session', not a failure)
- API client auto-clears auth state on 401 mid-session so the user
  gets redirected to login instead of seeing 'ERR: Request failed: 401'
- Session middleware now accepts Authorization: Bearer <token> header
  as fallback when no cookie is present (for Tauri/native clients)
- Login, register, and WebAuthn endpoints expose X-Session-Token header
  so non-browser clients can capture the token
This commit is contained in:
2026-07-16 14:46:17 -04:00
parent d4fff01e35
commit bda4c9d73d
9 changed files with 407 additions and 5 deletions
+2
View File
@@ -331,6 +331,7 @@ func (h *Handler) Register(w http.ResponseWriter, r *http.Request) {
}
h.setSessionCookie(w, token)
w.Header().Set("X-Session-Token", token)
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{"id": userID})
}
@@ -383,6 +384,7 @@ func (h *Handler) Login(w http.ResponseWriter, r *http.Request) {
}
h.setSessionCookie(w, token)
w.Header().Set("X-Session-Token", token)
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{"id": userID})
}
+1
View File
@@ -346,6 +346,7 @@ func (h *WebAuthnHandler) LoginFinish(w http.ResponseWriter, r *http.Request) {
Secure: true,
})
w.Header().Set("X-Session-Token", token)
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{"status": "authenticated"})
}
+12 -2
View File
@@ -18,13 +18,23 @@ type SessionStore interface {
func Session(store SessionStore, cfg *config.Config) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var token string
cookie, err := r.Cookie(cfg.Session.CookieName)
if err != nil {
if err == nil {
token = cookie.Value
} else {
authHeader := r.Header.Get("Authorization")
if len(authHeader) > 7 && authHeader[:7] == "Bearer " {
token = authHeader[7:]
}
}
if token == "" {
next.ServeHTTP(w, r)
return
}
userID, err := store.GetUserIDByToken(r.Context(), cookie.Value)
userID, err := store.GetUserIDByToken(r.Context(), token)
if err != nil {
next.ServeHTTP(w, r)
return