add jwt creating and parsing
This commit is contained in:
28
internal/jwt/parse.go
Normal file
28
internal/jwt/parse.go
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package jwt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/golang-jwt/jwt/v5"
|
||||||
|
)
|
||||||
|
|
||||||
|
func parse(
|
||||||
|
tokenStr string,
|
||||||
|
method jwt.SigningMethod,
|
||||||
|
key any,
|
||||||
|
) (jwt.Claims, error) {
|
||||||
|
t, err := jwt.Parse(tokenStr, func(tok *jwt.Token) (any, error) {
|
||||||
|
if tok.Method.Alg() != method.Alg() {
|
||||||
|
return nil, fmt.Errorf("unexpected signing method")
|
||||||
|
}
|
||||||
|
return key, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// check validity twice: invalid token may return nil error
|
||||||
|
if !t.Valid {
|
||||||
|
return nil, fmt.Errorf("invalid token")
|
||||||
|
}
|
||||||
|
return t.Claims, nil
|
||||||
|
}
|
||||||
49
internal/jwt/service.go
Normal file
49
internal/jwt/service.go
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
package jwt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang-jwt/jwt/v5"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
signer Signer
|
||||||
|
expiry time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewService(signer Signer, exp time.Duration) *Service {
|
||||||
|
return &Service{
|
||||||
|
signer: signer,
|
||||||
|
expiry: exp,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate creates a new JWT token for a given user ID and
|
||||||
|
// returns the token string along with its JTI(JWT IDentifier).
|
||||||
|
func (s *Service) Generate(userID int) (string, string, error) {
|
||||||
|
jti := uuid.NewString()
|
||||||
|
|
||||||
|
claims := jwt.MapClaims{
|
||||||
|
"sub": userID,
|
||||||
|
"jti": jti,
|
||||||
|
"exp": time.Now().Add(s.expiry).Unix(),
|
||||||
|
"iat": time.Now().Unix(),
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err := s.signer.Sign(claims)
|
||||||
|
return token, jti, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate verifies the JWT token and extracts the user ID and JTI(JWT IDentifier).
|
||||||
|
func (s *Service) Validate(token string) (int, string, error) {
|
||||||
|
claims, err := s.signer.Verify(token)
|
||||||
|
if err != nil {
|
||||||
|
return 0, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
sub := int(claims.(jwt.MapClaims)["sub"].(float64))
|
||||||
|
jti := claims.(jwt.MapClaims)["jti"].(string)
|
||||||
|
|
||||||
|
return sub, jti, nil
|
||||||
|
}
|
||||||
8
internal/jwt/signer.go
Normal file
8
internal/jwt/signer.go
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package jwt
|
||||||
|
|
||||||
|
import "github.com/golang-jwt/jwt/v5"
|
||||||
|
|
||||||
|
type Signer interface {
|
||||||
|
Sign(claims jwt.Claims) (string, error)
|
||||||
|
Verify(token string) (jwt.Claims, error)
|
||||||
|
}
|
||||||
20
internal/jwt/signer_HS256.go
Normal file
20
internal/jwt/signer_HS256.go
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package jwt
|
||||||
|
|
||||||
|
import "github.com/golang-jwt/jwt/v5"
|
||||||
|
|
||||||
|
type HMACSigner struct {
|
||||||
|
secret []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHMACSigner(secret []byte) *HMACSigner {
|
||||||
|
return &HMACSigner{secret: secret}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *HMACSigner) Sign(claims jwt.Claims) (string, error) {
|
||||||
|
t := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||||
|
return t.SignedString(s.secret)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *HMACSigner) Verify(tokenStr string) (jwt.Claims, error) {
|
||||||
|
return parse(tokenStr, jwt.SigningMethodHS256, s.secret)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user