2025-07-06 22:25:10 +03:00
|
|
|
package token
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"github.com/golang-jwt/jwt/v5"
|
|
|
|
|
log "github.com/sirupsen/logrus"
|
2025-09-08 22:38:30 +03:00
|
|
|
"net/http"
|
2025-07-06 22:25:10 +03:00
|
|
|
"strconv"
|
|
|
|
|
"strings"
|
|
|
|
|
"time"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type JWT struct {
|
|
|
|
|
SecretKey string
|
|
|
|
|
Issuer string
|
|
|
|
|
AccessExpire time.Duration
|
|
|
|
|
RefreshExpire time.Duration
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type Deps struct {
|
|
|
|
|
SecretKey string
|
|
|
|
|
Issuer string
|
|
|
|
|
AccessExpire string
|
|
|
|
|
RefreshExpire string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewJWT(deps Deps) *JWT {
|
|
|
|
|
return &JWT{
|
|
|
|
|
SecretKey: deps.SecretKey,
|
|
|
|
|
Issuer: deps.Issuer,
|
|
|
|
|
AccessExpire: duration(deps.AccessExpire),
|
|
|
|
|
RefreshExpire: duration(deps.RefreshExpire),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-08 23:58:44 +03:00
|
|
|
func (j *JWT) CreateAccessToken(userUuid, sessionUuid string) (string, error) {
|
2025-07-06 22:25:10 +03:00
|
|
|
now := time.Now()
|
|
|
|
|
|
|
|
|
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
|
|
|
|
|
"exp": now.Add(j.AccessExpire).Unix(),
|
|
|
|
|
"iat": now.Unix(),
|
|
|
|
|
"iss": j.Issuer,
|
|
|
|
|
"nbf": now.Unix(),
|
|
|
|
|
"sub": userUuid,
|
2025-09-08 23:58:44 +03:00
|
|
|
"sid": sessionUuid,
|
2025-07-06 22:25:10 +03:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
signedToken, err := token.SignedString([]byte(j.SecretKey))
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return signedToken, nil
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-08 22:38:30 +03:00
|
|
|
func (j *JWT) CreateRefreshToken(refreshUuid string, expires time.Time) *http.Cookie {
|
|
|
|
|
return &http.Cookie{
|
|
|
|
|
Name: "refresh_uuid",
|
|
|
|
|
Value: refreshUuid,
|
|
|
|
|
Expires: expires,
|
2025-09-09 23:16:58 +03:00
|
|
|
Secure: false,
|
2025-09-08 22:38:30 +03:00
|
|
|
HttpOnly: true,
|
|
|
|
|
SameSite: 3,
|
|
|
|
|
Partitioned: false,
|
2025-07-06 22:25:10 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-10 19:26:54 +03:00
|
|
|
func (j *JWT) Parse(token string) (string, error) {
|
2025-07-06 22:25:10 +03:00
|
|
|
if strings.HasPrefix(token, "Bearer ") {
|
|
|
|
|
token = strings.TrimPrefix(token, "Bearer ")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
parse, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) {
|
|
|
|
|
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
|
|
|
|
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
|
|
|
|
|
}
|
|
|
|
|
return []byte(j.SecretKey), nil
|
|
|
|
|
})
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Error(err)
|
2025-09-10 19:26:54 +03:00
|
|
|
return "", err
|
2025-07-06 22:25:10 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if claims, ok := parse.Claims.(jwt.MapClaims); ok && parse.Valid {
|
|
|
|
|
userUuid := claims["sub"].(string)
|
|
|
|
|
|
2025-09-10 19:26:54 +03:00
|
|
|
return userUuid, nil
|
2025-07-06 22:25:10 +03:00
|
|
|
}
|
|
|
|
|
|
2025-09-10 19:26:54 +03:00
|
|
|
return "", fmt.Errorf("invalid token")
|
2025-07-06 22:25:10 +03:00
|
|
|
}
|
|
|
|
|
|
2025-09-14 14:13:35 +03:00
|
|
|
func (j *JWT) RefreshExpires() time.Duration {
|
|
|
|
|
return j.RefreshExpire
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-06 22:25:10 +03:00
|
|
|
func duration(minutes string) time.Duration {
|
|
|
|
|
dur, err := strconv.Atoi(minutes)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return time.Duration(10) * time.Minute
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return time.Duration(dur) * time.Minute
|
|
|
|
|
}
|