package auth
import (
"time"
"github.com/golang-jwt/jwt/v5"
)
const tokenLeeway = time.Minute
var (
allowedSigningMethods = []string{jwt.SigningMethodHS256.Alg()}
unverifiedParser = jwt.NewParser(jwt.WithValidMethods(allowedSigningMethods))
)
type APIKeyTokenVerifier struct {
raw string
identity string
apiKey string
}
func ParseAPIToken(raw string) (*APIKeyTokenVerifier, error) {
claims := &jwt.RegisteredClaims{}
if _, _, err := unverifiedParser.ParseUnverified(raw, claims); err != nil {
return nil, err
}
v := &APIKeyTokenVerifier{
raw: raw,
apiKey: claims.Issuer,
identity: claims.Subject,
}
if v.identity == "" {
v.identity = claims.ID
}
return v, nil
}
func (v *APIKeyTokenVerifier) APIKey() string {
return v.apiKey
}
func (v *APIKeyTokenVerifier) Identity() string {
return v.identity
}
func (v *APIKeyTokenVerifier) Verify(key interface{}) (*jwt.RegisteredClaims, *ClaimGrants, error) {
if key == nil || key == "" {
return nil, nil, ErrKeysMissing
}
if s, ok := key.(string); ok {
key = []byte(s)
}
claims := &tokenClaims{}
_, err := jwt.ParseWithClaims(v.raw, claims, func(*jwt.Token) (interface{}, error) {
return key, nil
},
jwt.WithValidMethods(allowedSigningMethods),
jwt.WithIssuer(v.apiKey),
jwt.WithLeeway(tokenLeeway),
)
if err != nil {
return nil, nil, err
}
claims.ClaimGrants.Identity = v.identity
return &claims.RegisteredClaims, &claims.ClaimGrants, nil
}