Files
hanko/backend/handler/session.go
2025-09-25 19:15:20 +02:00

125 lines
3.3 KiB
Go

package handler
import (
"fmt"
echojwt "github.com/labstack/echo-jwt/v4"
"github.com/labstack/echo/v4"
"github.com/teamhanko/hanko/backend/v2/config"
"github.com/teamhanko/hanko/backend/v2/dto"
"github.com/teamhanko/hanko/backend/v2/persistence"
"github.com/teamhanko/hanko/backend/v2/session"
"net/http"
"time"
)
type SessionHandler struct {
persister persistence.Persister
sessionManager session.Manager
cfg config.Config
}
func NewSessionHandler(persister persistence.Persister, sessionManager session.Manager, cfg config.Config) *SessionHandler {
return &SessionHandler{
persister: persister,
sessionManager: sessionManager,
cfg: cfg,
}
}
func (h *SessionHandler) ValidateSession(c echo.Context) error {
lookup := fmt.Sprintf("header:Authorization:Bearer,cookie:%s", h.cfg.Session.Cookie.GetName())
extractors, err := echojwt.CreateExtractors(lookup)
if err != nil {
return c.JSON(http.StatusOK, dto.ValidateSessionResponse{IsValid: false})
}
for _, extractor := range extractors {
auths, extractorErr := extractor(c)
if extractorErr != nil {
continue
}
for _, auth := range auths {
token, tokenErr := h.sessionManager.Verify(auth)
if tokenErr != nil {
continue
}
claims, err := dto.GetClaimsFromToken(token)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Errorf("failed to parse token claims: %w", err))
}
sessionModel, err := h.persister.GetSessionPersister().Get(claims.SessionID)
if err != nil {
return fmt.Errorf("failed to get session from database: %w", err)
}
if sessionModel == nil {
continue
}
// Update lastUsed field
sessionModel.LastUsed = time.Now().UTC()
err = h.persister.GetSessionPersister().Update(*sessionModel)
if err != nil {
return dto.ToHttpError(err)
}
return c.JSON(http.StatusOK, dto.ValidateSessionResponse{
IsValid: true,
Claims: claims,
ExpirationTime: &claims.Expiration,
UserID: &claims.Subject,
})
}
}
return c.JSON(http.StatusOK, dto.ValidateSessionResponse{IsValid: false})
}
func (h *SessionHandler) ValidateSessionFromBody(c echo.Context) error {
var request dto.ValidateSessionRequest
err := (&echo.DefaultBinder{}).BindBody(c, &request)
if err != nil {
return dto.ToHttpError(err)
}
err = c.Validate(request)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err)
}
token, err := h.sessionManager.Verify(request.SessionToken)
if err != nil {
return c.JSON(http.StatusOK, dto.ValidateSessionResponse{IsValid: false})
}
claims, err := dto.GetClaimsFromToken(token)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Errorf("failed to parse token claims: %w", err))
}
sessionModel, err := h.persister.GetSessionPersister().Get(claims.SessionID)
if err != nil {
return dto.ToHttpError(err)
}
if sessionModel == nil {
return c.JSON(http.StatusOK, dto.ValidateSessionResponse{IsValid: false})
}
// update lastUsed field
sessionModel.LastUsed = time.Now().UTC()
err = h.persister.GetSessionPersister().Update(*sessionModel)
if err != nil {
return dto.ToHttpError(err)
}
return c.JSON(http.StatusOK, dto.ValidateSessionResponse{
IsValid: true,
Claims: claims,
ExpirationTime: &claims.Expiration,
UserID: &claims.Subject,
})
}