// Copyright 2024 Patial Tech (Ankit Patial). // // This file is part of code.patial.tech/go/appcore, which is MIT licensed. // See http://opensource.org/licenses/MIT package jwt import ( "crypto/ed25519" "errors" "fmt" "log" "maps" "time" "github.com/golang-jwt/jwt/v5" ) // Sign using EdDSA func Sign(key ed25519.PrivateKey, claims map[string]any, issuer string, d time.Duration) (string, error) { return SignEdDSA(key, claims, issuer, d) } func Parse(key ed25519.PrivateKey, tokenString string, issuer string) (jwt.MapClaims, error) { return ParseEdDSA(key, tokenString, issuer) } // SignEdDSA (Edwards-curve Digital Signature Algorithm, typically Ed25519) is an excellent, // modern choice for JWT signing—arguably safer and more efficient than both HS256 and traditional RSA/ECDSA. func SignEdDSA(key ed25519.PrivateKey, claims map[string]any, issuer string, d time.Duration) (string, error) { cl := jwt.MapClaims{ "iss": issuer, "iat": jwt.NewNumericDate(time.Now().UTC()), "exp": jwt.NewNumericDate(time.Now().Add(d)), } maps.Copy(cl, claims) t := jwt.NewWithClaims(jwt.SigningMethodEdDSA, cl) return t.SignedString(key) } func ParseEdDSA(key ed25519.PrivateKey, tokenString string, issuer string) (jwt.MapClaims, error) { token, err := jwt.Parse( tokenString, func(token *jwt.Token) (any, error) { return key.Public(), nil }, jwt.WithValidMethods([]string{jwt.SigningMethodEdDSA.Alg()}), jwt.WithIssuer(issuer), jwt.WithIssuedAt(), jwt.WithExpirationRequired(), ) if err != nil { log.Fatal(err) } if claims, ok := token.Claims.(jwt.MapClaims); ok { return claims, nil } else { return nil, errors.New("no claims found") } } func SignHS256(secret []byte, claims map[string]any, issuer string, d time.Duration) (string, error) { cl := jwt.MapClaims{ "iss": issuer, "iat": jwt.NewNumericDate(time.Now().UTC()), "exp": jwt.NewNumericDate(time.Now().Add(d)), } maps.Copy(cl, claims) t := jwt.NewWithClaims(jwt.SigningMethodHS256, cl) return t.SignedString(secret) } func ParseHS256(secret []byte, tokenString string, issuer string) (jwt.MapClaims, error) { token, err := jwt.Parse( tokenString, func(token *jwt.Token) (any, error) { if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) } return secret, nil }, jwt.WithValidMethods([]string{jwt.SigningMethodHS256.Alg()}), jwt.WithIssuer(issuer), jwt.WithIssuedAt(), jwt.WithExpirationRequired(), ) if err != nil { log.Fatal(err) } if claims, ok := token.Claims.(jwt.MapClaims); ok { return claims, nil } else { return nil, errors.New("no claims found") } }