Files
projectreshoot/internal/handler/logout.go

111 lines
2.5 KiB
Go

package handler
import (
"context"
"database/sql"
"net/http"
"strings"
"time"
"projectreshoot/pkg/cookies"
"git.haelnorr.com/h/golib/hlog"
"git.haelnorr.com/h/golib/jwt"
"github.com/pkg/errors"
)
func revokeAccess(
tokenGen *jwt.TokenGenerator,
tx *sql.Tx,
atStr string,
) error {
aT, err := tokenGen.ValidateAccess(tx, atStr)
if err != nil {
if strings.Contains(err.Error(), "Token is expired") ||
strings.Contains(err.Error(), "Token has been revoked") {
return nil // Token is expired, dont need to revoke it
}
return errors.Wrap(err, "jwt.ParseAccessToken")
}
err = aT.Revoke(tx)
if err != nil {
return errors.Wrap(err, "jwt.RevokeToken")
}
return nil
}
func revokeRefresh(
tokenGen *jwt.TokenGenerator,
tx *sql.Tx,
rtStr string,
) error {
rT, err := tokenGen.ValidateRefresh(tx, rtStr)
if err != nil {
if strings.Contains(err.Error(), "Token is expired") ||
strings.Contains(err.Error(), "Token has been revoked") {
return nil // Token is expired, dont need to revoke it
}
return errors.Wrap(err, "jwt.ParseRefreshToken")
}
err = rT.Revoke(tx)
if err != nil {
return errors.Wrap(err, "jwt.RevokeToken")
}
return nil
}
// Retrieve and revoke the user's tokens
func revokeTokens(
tokenGen *jwt.TokenGenerator,
tx *sql.Tx,
r *http.Request,
) error {
// get the tokens from the cookies
atStr, rtStr := cookies.GetTokenStrings(r)
// revoke the refresh token first as the access token expires quicker
// only matters if there is an error revoking the tokens
err := revokeRefresh(tokenGen, tx, rtStr)
if err != nil {
return errors.Wrap(err, "revokeRefresh")
}
err = revokeAccess(tokenGen, tx, atStr)
if err != nil {
return errors.Wrap(err, "revokeAccess")
}
return nil
}
// Handle a logout request
func Logout(
conn *sql.DB,
tokenGen *jwt.TokenGenerator,
logger *hlog.Logger,
) http.Handler {
return http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), 15*time.Second)
defer cancel()
tx, err := conn.BeginTx(ctx, nil)
if err != nil {
logger.Error().Err(err).Msg("Failed to start database transaction")
w.WriteHeader(http.StatusInternalServerError)
return
}
defer tx.Rollback()
err = revokeTokens(tokenGen, tx, r)
if err != nil {
logger.Error().Err(err).Msg("Error occured on user logout")
w.WriteHeader(http.StatusInternalServerError)
return
}
tx.Commit()
cookies.DeleteCookie(w, "access", "/")
cookies.DeleteCookie(w, "refresh", "/")
w.Header().Set("HX-Redirect", "/login")
},
)
}