initial commit
This commit is contained in:
121
pkg/jwt/token_generator.go
Normal file
121
pkg/jwt/token_generator.go
Normal file
@@ -0,0 +1,121 @@
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/lestrrat-go/jwx/v3/jwa"
|
||||
"github.com/lestrrat-go/jwx/v3/jwt"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrTokenVerificationFailed = errors.New("token verification failed")
|
||||
)
|
||||
|
||||
type tokenService struct {
|
||||
secretKey []byte
|
||||
accessTokenExpiration time.Duration
|
||||
refreshTokenExpiration time.Duration
|
||||
}
|
||||
|
||||
func New(secret string, ate, rfe time.Duration) TokenService {
|
||||
secretKey := []byte(secret)
|
||||
return &tokenService{
|
||||
secretKey: secretKey,
|
||||
accessTokenExpiration: ate,
|
||||
refreshTokenExpiration: rfe,
|
||||
}
|
||||
}
|
||||
|
||||
func (ts tokenService) GenerateAccessRefreshTokenPair(
|
||||
ctx context.Context,
|
||||
tokenData *TokenData,
|
||||
) (*AccessRefreshTokenPair, error) {
|
||||
accessTokenExp := time.Now().Add(ts.accessTokenExpiration)
|
||||
generateAccessJwt, err := ts.generateJwt(accessTokenExp, tokenData.Sub, "alinme-web")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
refreshTokenExp := time.Now().Add(ts.refreshTokenExpiration)
|
||||
generateRefreshJwt, err := ts.generateJwt(refreshTokenExp, tokenData.Sub, "alinme-web")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &AccessRefreshTokenPair{
|
||||
AccessToken: generateAccessJwt,
|
||||
AccessTokenExpiresAt: accessTokenExp,
|
||||
RefreshToken: generateRefreshJwt,
|
||||
RefreshTokenExpiresAt: refreshTokenExp,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (ts tokenService) generateJwt(exp time.Time, sub string, aud string) (string, error) {
|
||||
t, err := jwt.NewBuilder().
|
||||
Subject(sub).
|
||||
IssuedAt(time.Now()).
|
||||
Issuer("alinme-server").
|
||||
Audience([]string{aud}).
|
||||
Expiration(exp).
|
||||
Build()
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
signed, err := jwt.Sign(t, jwt.WithKey(jwa.HS256(), ts.secretKey))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(signed), nil
|
||||
}
|
||||
|
||||
func (ts tokenService) VerifyToken(ctx context.Context, accessToken string) (*TokenPayload, error) {
|
||||
parsed, err := jwt.Parse([]byte(accessToken), jwt.WithKey(jwa.HS256(), ts.secretKey))
|
||||
if err != nil {
|
||||
return nil, ErrTokenVerificationFailed
|
||||
}
|
||||
|
||||
sub, ok := parsed.Subject()
|
||||
if !ok {
|
||||
return nil, ErrTokenVerificationFailed
|
||||
}
|
||||
|
||||
aud, ok := parsed.Audience()
|
||||
if !ok {
|
||||
return nil, ErrTokenVerificationFailed
|
||||
}
|
||||
|
||||
iat, ok := parsed.IssuedAt()
|
||||
if !ok {
|
||||
return nil, ErrTokenVerificationFailed
|
||||
}
|
||||
|
||||
exp, ok := parsed.Expiration()
|
||||
if !ok {
|
||||
return nil, ErrTokenVerificationFailed
|
||||
}
|
||||
|
||||
iss, ok := parsed.Issuer()
|
||||
if !ok {
|
||||
return nil, ErrTokenVerificationFailed
|
||||
}
|
||||
|
||||
return &TokenPayload{
|
||||
Sub: sub,
|
||||
Aud: aud,
|
||||
Iat: iat,
|
||||
Exp: exp,
|
||||
Iss: iss,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (ts tokenService) GenerateToken(ctx context.Context, input *GenerateTokenInput) (string, error) {
|
||||
generateJwt, err := ts.generateJwt(time.Now().Add(time.Minute*5), input.Sub, input.Aud)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return generateJwt, nil
|
||||
}
|
||||
Reference in New Issue
Block a user