github.com/golang-jwt/jwt/v5 parses, validates and signs JWTs with the keys from the standard library: []byte for HMAC, *rsa.PublicKey, *ecdsa.PublicKey and ed25519.PublicKey. 5.3.1 signed and verified the HS, RS, PS and ES families and EdDSA; ES256K and the fully specified Ed25519 and Ed448 names have no registered signing method.
Verification hinges on the keyfunc you pass to jwt.Parse. Each signing method checks the Go type of the key it receives, so with a keyfunc that returns *ecdsa.PublicKey, an RS256 token failed with RSA verify expects *rsa.PublicKey and an HS256 token keyed with the PEM text failed with HMAC verify expects []byte. The protection disappears if the keyfunc hands back raw bytes for every token — a keyfunc that loads the PEM file as []byte let that forged HS256 token verify in the check. Pass jwt.WithValidMethods with the exact algorithm, and keep the keyfunc typed, as the sample does.
alg: none verifies only when the keyfunc returns the sentinel jwt.UnsafeAllowNoneSignatureType; any real key yields 'none' signature type is not allowed. ES256 refuses a P-384 key at signing time with a bare key is invalid. ES256 signatures are the 64-byte raw r‖s that JWS requires; a DER signature fails with crypto/ecdsa: verification error, which the JWT debugger and the DER ⇄ raw converter help track down.
Claims validation is on by default in v5, but exp is optional — a token without it is valid forever — and there is no leeway. jwt.WithExpirationRequired(), jwt.WithIssuer, jwt.WithAudience and jwt.WithLeeway close those gaps; errors can be matched with errors.Is(err, jwt.ErrTokenExpired) instead of comparing strings.
To verify tokens from an identity provider, pair it with a JWKS client and check what the provider publishes with the JWKS checker; go-jose is the alternative when JWE or JWK handling is needed.