fully working refresh tokens. No more expiring :)
This commit is contained in:
@@ -36,6 +36,14 @@ type codeReturn struct {
|
||||
Refresh string `json:"refresh"`
|
||||
}
|
||||
|
||||
type refreshBody struct {
|
||||
Refresh string `json:"refresh"`
|
||||
}
|
||||
|
||||
type refreshReturn struct {
|
||||
Access string `json:"access"`
|
||||
}
|
||||
|
||||
func (h *AuthHandler) login(body loginBody, w http.ResponseWriter, r *http.Request) {
|
||||
err := h.auth.CreateCode(body.Email)
|
||||
if err != nil {
|
||||
@@ -78,6 +86,22 @@ func (h *AuthHandler) code(body codeBody, w http.ResponseWriter, r *http.Request
|
||||
middleware.WriteJsonOrError(h.logger, codeReturn, w)
|
||||
}
|
||||
|
||||
func (h *AuthHandler) refresh(body refreshBody, w http.ResponseWriter, r *http.Request) {
|
||||
userId, err := h.jwtManager.GetUserIdFromRefresh(body.Refresh)
|
||||
if err != nil {
|
||||
middleware.WriteErrorBadRequest(h.logger, "invalid refresh token: "+err.Error(), w)
|
||||
return
|
||||
}
|
||||
|
||||
access := h.jwtManager.CreateAccessToken(userId)
|
||||
|
||||
refreshReturn := refreshReturn{
|
||||
Access: access,
|
||||
}
|
||||
|
||||
middleware.WriteJsonOrError(h.logger, refreshReturn, w)
|
||||
}
|
||||
|
||||
func (h *AuthHandler) CreateRoutes(r chi.Router) {
|
||||
h.logger.Info("Mounting auth router")
|
||||
|
||||
@@ -86,6 +110,7 @@ func (h *AuthHandler) CreateRoutes(r chi.Router) {
|
||||
|
||||
r.Post("/login", middleware.WithValidatedPost(h.login))
|
||||
r.Post("/code", middleware.WithValidatedPost(h.code))
|
||||
r.Post("/refresh", middleware.WithValidatedPost(h.refresh))
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
@@ -19,7 +18,7 @@ const (
|
||||
type JwtClaims struct {
|
||||
UserID string
|
||||
Type JwtType
|
||||
Expire time.Time
|
||||
Expiry time.Time
|
||||
}
|
||||
|
||||
type JwtManager struct {
|
||||
@@ -34,7 +33,7 @@ func (jm *JwtManager) createToken(claims JwtClaims) *jwt.Token {
|
||||
return jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
|
||||
"UserID": claims.UserID,
|
||||
"Type": claims.Type,
|
||||
"Expire": claims.Expire,
|
||||
"exp": claims.Expiry.Unix(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -42,7 +41,7 @@ func (jm *JwtManager) CreateRefreshToken(userId uuid.UUID) string {
|
||||
token := jm.createToken(JwtClaims{
|
||||
UserID: userId.String(),
|
||||
Type: Refresh,
|
||||
Expire: time.Now().Add(time.Hour * 24 * 30),
|
||||
Expiry: time.Now().Add(time.Hour * 24 * 30),
|
||||
})
|
||||
|
||||
tokenString, err := token.SignedString(jm.secret)
|
||||
@@ -57,7 +56,7 @@ func (jm *JwtManager) CreateAccessToken(userId uuid.UUID) string {
|
||||
token := jm.createToken(JwtClaims{
|
||||
UserID: userId.String(),
|
||||
Type: Access,
|
||||
Expire: time.Now().Add(time.Minute),
|
||||
Expiry: time.Now().Add(time.Minute),
|
||||
})
|
||||
|
||||
tokenString, err := token.SignedString(jm.secret)
|
||||
@@ -79,7 +78,7 @@ func (jm *JwtManager) GetUserIdFromAccess(accessToken string) (uuid.UUID, error)
|
||||
return uuid.Nil, err
|
||||
}
|
||||
|
||||
// Check if token is valid (including expiry check)
|
||||
// Check if token is valid (JWT library validates exp claim automatically)
|
||||
if !token.Valid {
|
||||
return uuid.Nil, NotValidToken
|
||||
}
|
||||
@@ -90,27 +89,34 @@ func (jm *JwtManager) GetUserIdFromAccess(accessToken string) (uuid.UUID, error)
|
||||
return uuid.Nil, NotValidToken
|
||||
}
|
||||
|
||||
// Additional explicit expiry check
|
||||
expireClaim, ok := claims["Expire"]
|
||||
if !ok {
|
||||
userId, err := uuid.Parse(claims["UserID"].(string))
|
||||
if err != nil {
|
||||
return uuid.Nil, NotValidToken
|
||||
}
|
||||
|
||||
var expireTime time.Time
|
||||
switch exp := expireClaim.(type) {
|
||||
case float64:
|
||||
expireTime = time.Unix(int64(exp), 0)
|
||||
case json.Number:
|
||||
expInt, err := exp.Int64()
|
||||
if err != nil {
|
||||
return uuid.Nil, NotValidToken
|
||||
}
|
||||
expireTime = time.Unix(expInt, 0)
|
||||
default:
|
||||
return uuid.Nil, NotValidToken
|
||||
}
|
||||
return userId, nil
|
||||
} else {
|
||||
return uuid.Nil, NotValidToken
|
||||
}
|
||||
}
|
||||
|
||||
if time.Now().After(expireTime) {
|
||||
func (jm *JwtManager) GetUserIdFromRefresh(refreshToken string) (uuid.UUID, error) {
|
||||
token, err := jwt.Parse(refreshToken, func(token *jwt.Token) (any, error) {
|
||||
return jm.secret, nil
|
||||
}, jwt.WithValidMethods([]string{jwt.SigningMethodHS256.Alg()}))
|
||||
|
||||
if err != nil {
|
||||
return uuid.Nil, err
|
||||
}
|
||||
|
||||
// Check if token is valid (JWT library validates exp claim automatically)
|
||||
if !token.Valid {
|
||||
return uuid.Nil, NotValidToken
|
||||
}
|
||||
|
||||
if claims, ok := token.Claims.(jwt.MapClaims); ok {
|
||||
tokenType, ok := claims["Type"]
|
||||
if !ok || tokenType.(string) != "refresh" {
|
||||
return uuid.Nil, NotValidToken
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user