api/internal/provider/token/service.go
2025-09-09 23:16:58 +03:00

109 lines
2.3 KiB
Go

package token
import (
"fmt"
"github.com/golang-jwt/jwt/v5"
log "github.com/sirupsen/logrus"
"net/http"
"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),
}
}
func (j *JWT) CreateAccessToken(userUuid, sessionUuid string) (string, error) {
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,
"sid": sessionUuid,
})
signedToken, err := token.SignedString([]byte(j.SecretKey))
if err != nil {
return "", err
}
return signedToken, nil
}
func (j *JWT) CreateRefreshToken(refreshUuid string, expires time.Time) *http.Cookie {
return &http.Cookie{
Name: "refresh_uuid",
Value: refreshUuid,
Expires: expires,
Secure: false,
HttpOnly: true,
SameSite: 3,
Partitioned: false,
}
}
func (j *JWT) Parse(token string) (string, string, error) {
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)
return "", "", err
}
if claims, ok := parse.Claims.(jwt.MapClaims); ok && parse.Valid {
userUuid := claims["sub"].(string)
var sessionUuid string
if sid, exists := claims["sid"]; exists {
if tknStr, okay := sid.(string); okay {
sessionUuid = tknStr
} else {
return "", "", fmt.Errorf("invalid type for 'sid' claim")
}
}
return userUuid, sessionUuid, nil
}
return "", "", fmt.Errorf("invalid token")
}
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
}