add logout method

This commit is contained in:
2026-01-03 15:42:29 +02:00
parent 0510103125
commit cadb42d17a

82
api/auth/logout.go Normal file
View File

@@ -0,0 +1,82 @@
package api_auth
import (
"errors"
"fmt"
"log/slog"
"net/http"
"git.oblat.lv/alex/triggerssmith/internal/auth"
"git.oblat.lv/alex/triggerssmith/internal/server"
"github.com/golang-jwt/jwt/v5"
)
// @Summary Logout
// @Description Requires valid refresh token
// @Tags auth
// @Success 204
// @Failure 401 {object} server.ProblemDetails
// @Failure 500 {object} server.ProblemDetails
// @Router /api/auth/logout [post]
func (h *authHandler) handleLogout(w http.ResponseWriter, r *http.Request) {
// claims, err := h.a.AuthenticateRequest(r)
// if err != nil {
// slog.Error("failed to AuthenticateRequest", "error", err.Error())
// switch err {
// case auth.ErrInvalidToken:
// server.WriteProblem(w, http.StatusUnauthorized, "/errors/auth/invalid-token", "Invalid token", "Invalid token: taking cookies anyways", r)
// case auth.ErrTokenIsMissing:
// server.WriteProblem(w, http.StatusUnauthorized, "/errors/auth/invalid-token", "Invalid token", "Token is missing: taking cookies anyway", r)
// default:
// server.WriteProblem(w, http.StatusInternalServerError, "/errors/internal-server-error", "Internal Server Error", "unexpected error: taking cookies anyway", r)
// }
// http.SetCookie(w, &http.Cookie{
// Name: "refresh_token",
// Value: "",
// MaxAge: -1,
// Path: "/api/auth/",
// HttpOnly: true,
// SameSite: http.SameSiteLaxMode,
// })
// return
// }
// rjti := claims.(jwt.MapClaims)["rjti"].(string)
refreshCookie, err := r.Cookie("refresh_token")
if err != nil && errors.Is(err, http.ErrNoCookie) {
server.WriteProblem(w, http.StatusUnauthorized, "/errors/auth/refresh-token-not-found", "Refresh token is missing", "Refresh token is missing", r)
return
}
refreshStr := refreshCookie.Value
if refreshStr == "" {
server.WriteProblem(w, http.StatusUnauthorized, "/errors/auth/refresh-token-not-found", "Refresh token is missing", "Refresh token is missing", r)
return
}
claims, err := h.a.ValidateRefreshToken(refreshStr)
if err != nil {
slog.Error("failed to ValidateRefreshToken", "error", err.Error())
server.WriteProblem(w, http.StatusInternalServerError, "/errors/internal-server-error", "Internal Server Error", "unexpected error while validating refresh token: maybe invalid", r)
return
}
rjti := claims.(jwt.MapClaims)["jti"].(string)
err = h.a.Logout(rjti)
if err != nil {
slog.Error("failed to Logout", "error", err.Error())
switch err {
case auth.ErrInvalidToken:
server.WriteProblem(w, http.StatusUnauthorized, "/errors/auth/already-revoked", "Token already revoked", fmt.Sprintf("Token with rjti '%s' is already revoked", rjti), r)
default:
server.WriteProblem(w, http.StatusInternalServerError, "/errors/internal-server-error", "Internal Server Error", "unexpected error: taking cookies anyway", r)
}
}
http.SetCookie(w, &http.Cookie{
Name: "refresh_token",
Value: "",
MaxAge: -1,
Path: "/api/auth/",
HttpOnly: true,
SameSite: http.SameSiteLaxMode,
})
if err == nil {
w.WriteHeader(http.StatusNoContent)
}
}