golang-jwt / jwt

Go implementation of JSON Web Tokens (JWT).
https://golang-jwt.github.io/jwt/
MIT License
6.98k stars 335 forks source link

ECDSA signature is invalid #375

Closed bentcoder closed 7 months ago

bentcoder commented 7 months ago

Hi,

I am creating a ECDSA 256 to use with SigningMethodES256 to generate signed token. However the signature is said to be invalid when checking with https://jwt.io/. Could someone tell me if there is a bug or am I missing something please?

Thank you

Playground

package main

import (
    "context"
    "crypto/ecdsa"
    "crypto/elliptic"
    "crypto/rand"
    "fmt"
    "time"

    "github.com/golang-jwt/jwt/v5"
)

func main() {
    ecdsa, err := NewECDSA(elliptic.P256())
    if err != nil {
        panic(err)
    }

    jwt := JWT{
        Issuer:        "my-api",
        SigningMethod: jwt.SigningMethodES256,
        PublicKey:     ecdsa.Public,
        PrivateKey:    ecdsa.Private,
    }

    token, err := jwt.CreateToken(context.Background(), CreateTokenArgs{
        ID:       "token-id-1",
        ClientID: "client-id-1",
        Now:      time.Now().UTC(),
        TTL:      time.Hour,
    })
    if err != nil {
        panic(err)
    }

    fmt.Println(token)
}

// ECDSA ------------------------------------------------------

type ECDSA struct {
    Private *ecdsa.PrivateKey
    Public  *ecdsa.PublicKey
}

func NewECDSA(curve elliptic.Curve) (ECDSA, error) {
    prv, err := ecdsa.GenerateKey(curve, rand.Reader)
    if err != nil {
        return ECDSA{}, err
    }

    return ECDSA{
        Private: prv,
        Public:  &prv.PublicKey,
    }, nil
}

// JWT --------------------------------------------------------

type CreateTokenArgs struct {
    ID       string
    ClientID string
    Now      time.Time
    TTL      time.Duration
}

type JWT struct {
    Issuer        string
    SigningMethod jwt.SigningMethod
    PublicKey     any
    PrivateKey    any
}

func (j *JWT) CreateToken(ctx context.Context, args CreateTokenArgs) (string, error) {
    token := jwt.NewWithClaims(j.SigningMethod, jwt.RegisteredClaims{
        ID:        args.ID,
        Subject:   args.ClientID,
        Issuer:    j.Issuer,
        ExpiresAt: jwt.NewNumericDate(args.Now.Add(args.TTL)),
        NotBefore: jwt.NewNumericDate(args.Now),
        IssuedAt:  jwt.NewNumericDate(args.Now),
    })

    sig, err := token.SignedString(j.PrivateKey)
    if err != nil {
        return "", err
    }

    return sig, nil
}