package authjwt import ( "crypto/rsa" "crypto/x509" "encoding/pem" "fmt" "github.com/golang-jwt/jwt/v5" ) var _ Verifier = (*rsaPublicVerifier)(nil) type rsaPublicVerifier struct{ public *rsa.PublicKey } // NewRSAPublicKeyVerifier returns a Verifier backed by an RSA public key. // Use this in services that verify tokens but never issue them. func NewRSAPublicKeyVerifier(publicKey *rsa.PublicKey) Verifier { return &rsaPublicVerifier{public: publicKey} } // NewRSAPublicKeyVerifierFromPEM parses a PKIX or PKCS#1 PEM-encoded RSA public key. func NewRSAPublicKeyVerifierFromPEM(pemKey []byte) (Verifier, error) { block, _ := pem.Decode(pemKey) if block == nil { return nil, fmt.Errorf("no PEM block found") } pub, err := x509.ParsePKIXPublicKey(block.Bytes) if err != nil { rsaPub, err2 := x509.ParsePKCS1PublicKey(block.Bytes) if err2 != nil { return nil, fmt.Errorf("parse RSA public key: %w", err) } return NewRSAPublicKeyVerifier(rsaPub), nil } rsaPub, ok := pub.(*rsa.PublicKey) if !ok { return nil, fmt.Errorf("PEM key is not an RSA public key") } return NewRSAPublicKeyVerifier(rsaPub), nil } func (v *rsaPublicVerifier) Verify(tokenString string) (*jwt.Token, error) { return jwt.Parse(tokenString, func(t *jwt.Token) (any, error) { if _, ok := t.Method.(*jwt.SigningMethodRSA); !ok { return nil, fmt.Errorf("unexpected signing method %q", t.Header["alg"]) } return v.public, nil }, jwt.WithJSONNumber()) }