created: jwt provider

This commit is contained in:
nquidox 2025-07-06 22:25:10 +03:00
parent 7e5010ac78
commit bc2038ef34
3 changed files with 139 additions and 0 deletions

View file

@ -3,6 +3,7 @@ package config
type Config struct { type Config struct {
AppConf AppConfig AppConf AppConfig
DBConf DatabaseConfig DBConf DatabaseConfig
JWTConf JWTConfig
} }
type AppConfig struct { type AppConfig struct {
@ -23,6 +24,13 @@ type DatabaseConfig struct {
LogLevel string LogLevel string
} }
type JWTConfig struct {
Secret string
Issuer string
AccessExpire string
RefreshExpire string
}
func NewConfig() *Config { func NewConfig() *Config {
return &Config{ return &Config{
AppConf: AppConfig{ AppConf: AppConfig{
@ -42,5 +50,12 @@ func NewConfig() *Config {
DBName: getEnv("DB_NAME", ""), DBName: getEnv("DB_NAME", ""),
LogLevel: getEnv("DB_LOGLEVEL", ""), LogLevel: getEnv("DB_LOGLEVEL", ""),
}, },
JWTConf: JWTConfig{
Secret: getEnv("JWT_SECRET", ""),
Issuer: getEnv("JWT_ISSUER", ""),
AccessExpire: getEnv("JWT_ACCESS_EXPIRE", ""),
RefreshExpire: getEnv("JWT_REFRESH_EXPIRE", ""),
},
} }
} }

View file

@ -0,0 +1,7 @@
package interfaces
type JWTProvider interface {
CreateAccessToken(userUuid string) (string, error)
CreateRefreshToken(userUuid, tokenUuid string) (string, int64, error)
Parse(token string) (string, string, error)
}

View file

@ -0,0 +1,117 @@
package token
import (
"fmt"
"github.com/golang-jwt/jwt/v5"
log "github.com/sirupsen/logrus"
"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 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,
})
signedToken, err := token.SignedString([]byte(j.SecretKey))
if err != nil {
return "", err
}
return signedToken, nil
}
func (j *JWT) CreateRefreshToken(userUuid, tokenUuid string) (string, int64, error) {
now := time.Now()
exp := now.Add(j.RefreshExpire).Unix()
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"exp": exp,
"iat": now.Unix(),
"iss": j.Issuer,
"nbf": now.Unix(),
"sub": userUuid,
"tkn": tokenUuid,
})
signedToken, err := token.SignedString([]byte(j.SecretKey))
if err != nil {
return "", 0, err
}
return signedToken, exp, nil
}
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 refreshUuid string
if tkn, exists := claims["tkn"]; exists {
if tknStr, okay := tkn.(string); okay {
refreshUuid = tknStr
} else {
return "", "", fmt.Errorf("invalid type for 'tkn' claim")
}
}
return userUuid, refreshUuid, 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
}