112 lines
2.6 KiB
Go
112 lines
2.6 KiB
Go
package accounts
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/golang-jwt/jwt/v5"
|
|
)
|
|
|
|
type jwtClaims struct {
|
|
UserID uint `json:"user_id"`
|
|
Role string `json:"role"`
|
|
jwt.RegisteredClaims
|
|
}
|
|
|
|
const (
|
|
RoleAdmin = "admin"
|
|
RoleUser = "user"
|
|
)
|
|
|
|
func GenerateTokens(userID uint, role string) (string, string, error) {
|
|
accessSecret := os.Getenv("JWT_SECRET")
|
|
refreshSecret := os.Getenv("JWT_REFRESH_SECRET")
|
|
if accessSecret == "" || refreshSecret == "" {
|
|
return "", "", fmt.Errorf("JWT secrets are not set")
|
|
}
|
|
|
|
normalizedRole := normalizeRole(role)
|
|
|
|
// Access Token
|
|
accessClaims := jwtClaims{
|
|
UserID: userID,
|
|
Role: normalizedRole,
|
|
RegisteredClaims: jwt.RegisteredClaims{
|
|
ExpiresAt: jwt.NewNumericDate(time.Now().Add(15 * time.Minute)),
|
|
IssuedAt: jwt.NewNumericDate(time.Now()),
|
|
},
|
|
}
|
|
accessToken := jwt.NewWithClaims(jwt.SigningMethodHS256, accessClaims)
|
|
accessString, err := accessToken.SignedString([]byte(accessSecret))
|
|
if err != nil {
|
|
return "", "", err
|
|
}
|
|
|
|
// Refresh Token
|
|
refreshClaims := jwtClaims{
|
|
UserID: userID,
|
|
Role: normalizedRole,
|
|
RegisteredClaims: jwt.RegisteredClaims{
|
|
ExpiresAt: jwt.NewNumericDate(time.Now().Add(7 * 24 * time.Hour)),
|
|
IssuedAt: jwt.NewNumericDate(time.Now()),
|
|
},
|
|
}
|
|
refreshToken := jwt.NewWithClaims(jwt.SigningMethodHS256, refreshClaims)
|
|
refreshString, err := refreshToken.SignedString([]byte(refreshSecret))
|
|
if err != nil {
|
|
return "", "", err
|
|
}
|
|
|
|
return accessString, refreshString, nil
|
|
}
|
|
|
|
func ParseAccessToken(tokenString string) (uint, error) {
|
|
secret := os.Getenv("JWT_SECRET")
|
|
claims, err := parseTokenClaims(tokenString, secret)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return claims.UserID, nil
|
|
}
|
|
|
|
func ParseRefreshToken(tokenString string) (uint, error) {
|
|
secret := os.Getenv("JWT_REFRESH_SECRET")
|
|
claims, err := parseTokenClaims(tokenString, secret)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return claims.UserID, nil
|
|
}
|
|
|
|
func parseAccessClaims(tokenString string) (*jwtClaims, error) {
|
|
secret := os.Getenv("JWT_SECRET")
|
|
return parseTokenClaims(tokenString, secret)
|
|
}
|
|
|
|
func parseTokenClaims(tokenString, secret string) (*jwtClaims, error) {
|
|
token, err := jwt.ParseWithClaims(tokenString, &jwtClaims{}, func(token *jwt.Token) (interface{}, error) {
|
|
return []byte(secret), nil
|
|
})
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if claims, ok := token.Claims.(*jwtClaims); ok && token.Valid {
|
|
claims.Role = normalizeRole(claims.Role)
|
|
return claims, nil
|
|
}
|
|
|
|
return nil, fmt.Errorf("invalid token")
|
|
}
|
|
|
|
func normalizeRole(role string) string {
|
|
switch role {
|
|
case RoleAdmin:
|
|
return RoleAdmin
|
|
default:
|
|
return RoleUser
|
|
}
|
|
}
|