Giter Club home page Giter Club logo

jwt-go's People

Contributors

abdollar avatar aboodman avatar abourget avatar albrow avatar alias-dev avatar appleboy avatar aspic avatar aussiegeek avatar bbigras avatar bruston avatar cenkalti avatar cryptix avatar dakom avatar dgrijalva avatar emanoelxavier avatar evanphx avatar fredbi avatar hnakamur avatar itsjamie avatar jamesrwhite avatar johnlockwood-wf avatar jsaguiar avatar kevinburke avatar martinlindhe avatar polarina avatar simonjefford avatar vongohren avatar waterdrips avatar zimbatm avatar zoofood avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jwt-go's Issues

Unclear when HMAC signature verification is successful

I was reading through the code, trying to get a feel for it as I'm fairly new with JWT and got slightly confused when I came to check out the Verify func on the SigningMethodHMAC (Haven't checked others yet)

https://github.com/dgrijalva/jwt-go/blob/master/hmac.go#L47-L67

As the err variable is declared on line 50 and we return that nil error on line 63 instead of just returning nil, it took a little longer than it should have to see that it was a successful verification at that point.

Can we remove line 50, use good old := on line 51 and then change line 60 to simply return ErrSignatureInvalid and 63 to return nil?

API Change around Key Parsing

There have been several questions around keys and key formats. Currently, jwt.KeyFunc expects the key as []byte. This has a few negative consequences:

  • The keys must be in a particular format
    • the format is different for each signing method
    • several signing methods don't have an obvious best serialization format
  • The keys must be parsed every time they are used, wasting CPU and producing GC garbage
  • If the key is provided in a different format, it must be re-encoded so it can be returned from KeyFunc

I'm wondering if we shouldn't change the return type of KeyFunc to (interface{}, error). If we make public the RSA parsePublicKey and parsePrivateKey, it won't be terribly difficult to keep existing behavior by calling these and returning the result. This will allow users of this library to decide how their keys will be serialized/stored and it will allow in-memory caching of already parsed keys.

The negative consequence I see are:

  • it will make integration of this library a bit more complicated
  • it's an API change that will require work to integrate (though a pretty small amount)
  • the type interface{} is not very descriptive about what object type each signing method expects. Unfortunately, I don't think there's a lot we can do about this. It's not any worse than the current case.

For ease of integration, we could have the RSA library attempt to parse a []byte value if it's passed in.

Thoughts?

Vulnerability: expiration assertion is quietly skipped if type assertion fails

The JWT MUST contain an "exp" (expiration time) claim that limits the time window during which the JWT can be used. The authorization server MUST reject any JWT with an expiration time that has passed, subject to allowable clock skew between systems. - Source

if exp, ok := token.Claims["exp"].(float64); ok {
    if now > int64(exp) {
        vErr.err = "token is expired"
        vErr.Errors |= ValidationErrorExpired
    }
}
// No error if exp could not be asserted to float64

Only nbf is optional.

I'm having issues understanding your signing example

Hi folks,

Looking at your example:

token, err := jwt.Parse(myToken, func(token *jwt.Token) (interface{}, error) {
    return myLookupKey(token.Header["kid"])
})

if err == nil && token.Valid {
    fmt.Println("Your token is valid.  I like your style.")
} else {
    fmt.Println("This token is terrible!  I cannot accept this.")
}

What exactly is myLookupKey?

I have:

package services

import (
    "bitbucket.org/bandzest/applications/core/api/drivers"
    "bitbucket.org/bandzest/applications/core/api/models"
    jwt "github.com/dgrijalva/jwt-go"
    "time"
)

var (
    jwtKey = "testing123"
)

func CreateToken(user *models.User) (string, error) {
    token := jwt.New(jwt.SigningMethodHS256)

    // Set some claims
    token.Claims["id"] = user.Id
    token.Claims["username"] = user.Name
    token.Claims["email"] = user.Email
    token.Claims["iat"] = time.Now().Unix()
    token.Claims["exp"] = time.Now().Add(time.Second * 3600 * 24).Unix()

    // Sign and get the complete encoded token as a string
    tokenString, err := token.SignedString([]byte(jwtKey))

    return tokenString, err
}

func ValidateToken(tokenString string) (bool, error) {

    token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
        return []byte("jwtKey"), nil
    })

    if err != nil {
        panic(err)
    }

    if !token.Valid {
        return false, nil
    }

    return true, nil
}

But I'm getting the error Panic recovery -> signature is invalid.

Thanks in advance!

Support for other signing methods

Hi there. Thanks for the library.

Per https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40#section-3.1 the spec supports PSS and ECDSA. It looks like the go crypto library supports this as well. Do you have any plans to implement this as a signing mechanism?

If not I can take a crack at the implementation

   +--------------+-----------------------------------+----------------+
   | alg Param    | Digital Signature or MAC          | Implementation |
   | Value        | Algorithm                         | Requirements   |
   +--------------+-----------------------------------+----------------+
   | HS256        | HMAC using SHA-256                | Required       |
   | HS384        | HMAC using SHA-384                | Optional       |
   | HS512        | HMAC using SHA-512                | Optional       |
   | RS256        | RSASSA-PKCS-v1_5 using SHA-256    | Recommended    |
   | RS384        | RSASSA-PKCS-v1_5 using SHA-384    | Optional       |
   | RS512        | RSASSA-PKCS-v1_5 using SHA-512    | Optional       |
   | ES256        | ECDSA using P-256 and SHA-256     | Recommended+   |
   | ES384        | ECDSA using P-384 and SHA-384     | Optional       |
   | ES512        | ECDSA using P-521 and SHA-512     | Optional       |
   | PS256        | RSASSA-PSS using SHA-256 and MGF1 | Optional       |
   |              | with SHA-256                      |                |
   | PS384        | RSASSA-PSS using SHA-384 and MGF1 | Optional       |
   |              | with SHA-384                      |                |
   | PS512        | RSASSA-PSS using SHA-512 and MGF1 | Optional       |
   |              | with SHA-512                      |                |
   | none         | No digital signature or MAC       | Optional       |
   |              | performed                         |                |
   +--------------+-----------------------------------+----------------+

(m *SigningMethodHMAC) Sign Expecting []byte Is Not Clear

https://github.com/dgrijalva/jwt-go/blob/master/hmac.go#L70 tries to do a type assertion on interface{} to []byte but this will not work on strings. See http://play.golang.org/p/mYMjdz8vQi for a simple example.

What I do not understand is why all the examples and tests pass a string into token.SignedString() when you should really pass in []byte.

For example https://github.com/dgrijalva/jwt-go/blob/master/example_test.go#L28 (You can see that .Sign() is directly invoked https://github.com/dgrijalva/jwt-go/blob/master/jwt.go#L60)

In general, I do not understand why you are relying on interface{} in methods instead of explicitly expecting []byte. (t *Token) SignedString(key interface{} and (m *SigningMethodHMAC) Sign(signingString string, key interface{}) for two examples.

gist example won't compile -

I think you need to modify the type from []byte to interface{} ... on line 151
token, err := jwt.Parse(tokenCookie.Value, func(token *jwt.Token) (interface{}, error) {...

ValidationError struct needs a exported field of type error

Currently there is no way for callers of the func Parse to handle error types returned by the extension point KeyFunc. In other words, in my implementation of KeyFunc I return my own error type with my error code in it. Parse does not surface this information to its caller and therefore I cannot easily handle my own error type and code. My suggestion to tackle this is to include an exported field on the type ValidationError, something like "InnerError error", here you can place the whole error returned by KeyFunc. Currently when KeyFunc fails I see that you place the .Error() of that failure in the ValidationError.err but this is not quite the same as keeping the whole KeyFunc error type since that can contain more information. Another option is to provide another extension point so that KeyFunc errors can be handled on a custom fashion.

Adding compression for the claims

Hi, in our project the claims part of the JWT token is getting really long. I was wondering if it would be possible to compress the data in the claims part.
It would look pretty straightforward,
I would add an 'compression' : 'gzip' key and value to the header map. This can be done by adding a new argument to the jwt.New() function.
The rest would be transparent. Just add compression between JSON encoding and Base64 encoding,
and decompression symmetrically.

I would rather contribute to the main repo instead of forking it or doing the same thing in our code.

Token.Signature is never populated when parsing?

I can't find where the field Token.Signature is populated while parsing.
A comment in line 29 in jwt.go says: "Populated when you Parse a token"

It doesn't seem to be necessary to populate it while Parsing, because the token verification works either way, but I thought I'd point it out anyway since the comment clearly says it is. It might confuse some people... like me :(

While testing I accidentally used a token without the last character in the signature and I kept getting an "invalid signature error" because of it. So I tried printing the token's fields before and after calling token.Parse and the Signature field was always empty. It made me think there was something wrong with my code or the library and it took me quiet a long time to figure out my token was missing a character :/

Usage with Google Sign-In for Websites

I implemented Googles Oauth2 for websites.
https://developers.google.com/identity/sign-in/web/backend-auth

ParseRSAPublicKeyFromPEM() seems to expect a full PEM encoded public key,
such as one of these: https://www.googleapis.com/oauth2/v1/certs

But the JavaScript creates a PWT with only the key to the PEM above, i.e.
9015759ea37707cb6d325cca00e6299231b7f72f

The PWT is created by https://apis.google.com/js/platform.js.

How is that supposed to work?
Is there a "PEM Key Lookup" stage, that I overlooked?
Is my use case off base?

I changed the code.
I replaced the key with the full PEM.
Then it works perfectly.

Regards
Peter

Incorrect comments for SignningMethodRSAPSS.Verify() / Sign()

Hi Dave,

I found 2 incorrect comments in rsa_pss.go(line 72 and 101):

// Implements the Verify method from SigningMethod
// For this verify method, key must be an *rsa.PrivateKey(should be rsa.PublicKey?) struct
func (m *SigningMethodRSAPSS) Verify(signingString, signature string, key interface{}) error {

// Implements the Sign method from SigningMethod
// For this signing method, key must be an *rsa.PublicKey(should be rsa.PrivateKey?) struct
func (m *SigningMethodRSAPSS) Sign(signingString string, key interface{}) (string, error) {

PS:

Your jwt-go is cool and I love it:)

Couldn't parse token: signature is invalid

The example on jwt.io has the following example:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ encoded with secret

In jwt-go/cmd/jwt, I created a file named key with content secret and ran the following command but encountered an error:

ยป echo eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ | go run app.go -key="./key" -verify -
Error: Couldn't parse token: signature is invalid
exit status 1

Any ideas on what I'm doing wrong?

Keep getting errors when parsing

I use this method in creating token:

token := jwt.New(jwt.SigningMethodHS256)
token.Claims["id"] = user.UserID
token.Claims["iat"] = time.Now().Unix()
token.Claims["exp"] = time.Now().Add(time.Second * 3600 * 24).Unix()
jwtString, err := token.SignedString([]byte("mysupersecretkey"))
fmt.Println(jwtString);

Then I take that string i get echoed out an try to do a simple call to the my root route which has this inside it:

func IndexHandler(env *db.Env, w http.ResponseWriter, r *http.Request) error {
  jwtString := r.Header.Get("Authorization")
  token, err := jwt.ParseFromRequest(jwtString, keyFn)
  fmt.Println(token)
  fmt.Println(err)
  if err == nil && token.Valid {
      // token parsed, exp/nbf checks out, signature verified, Valid is true
      fmt.Fprint(w, "Welcome!\n")
      return nil;
  }

  fmt.Println("index");
  fmt.Fprint(w, "NOT AUTHORIZED")
  return nil
}

func keyFn(token *jwt.Token) (interface{}, error) {
    return []byte("mysupersecretkey"), nil
}

But I keep getting error illegal base64 data at input byte 6 or illegal base64 data at input byte 4.

What am i missing? I have read that i need to return an interface from the keyFn, ref this http://stackoverflow.com/questions/25848215/go-and-parsing-token-with-jwt-go.

But I dont understand what that should be? Any help here? Cant seem to find any examples that work for me. Also tried this example, https://sendgrid.com/blog/tokens-tokens-intro-json-web-tokens-jwt-go/, but its pretty the same thing.

Explicit behavior for key

Would be great if the key has an interface with a Byte() func instead of interface{} type

What do you think? Implicit is better than explicit :), btw this would introduce a huge BC...

cfr: gin-gonic/contrib#19

key is invalid or of invalid type

I got the following error:

key is invalid or of invalid type

by the following code. I'm not sure if I'm missing anything.

package main

import (
    "fmt"
    "github.com/dgrijalva/jwt-go"
    "time"
)

func main() {
    tokenString, err := CreateJwtToken()
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println(tokenString)
}

func CreateJwtToken() (string, error) {
    token := jwt.New(jwt.SigningMethodHS256)
    token.Claims["foo"] = "bar"
    token.Claims["exp"] = time.Now().Add(time.Hour * 72).Unix()
    tokenString, err := token.SignedString("netdata.io")
    return tokenString, err
}

Cannot Valid parse

I have code like this

token := jwt.New(jwt.GetSigningMethod("HS256"))
    token.Claims["ID"] = "Christopher"
    token.Claims["exp"] = time.Now().Add(time.Hour * 1).Unix()
    s, e := token.SignedString([]byte("unicornsAreAwesome"))

    if e != nil {
        panic(e.Error())
    }
    fmt.Println(s)

when I'm running I get
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJJRCI6IkNocmlzdG9waGVyIiwiZXhwIjoxNDM5ODE2Njg2fQ.OU2K92mLwEy9hrL-gwiNEm1Rd_vVVCZ0o3mYxdT2e-I
but when I want to parse it with this code

myToken := "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9leGFtcGxlLm9yZyIsImF1ZCI6Imh0dHA6XC9cL2V4YW1wbGUuY29tIiwiaWF0IjoxMzU2OTk5NTI0LCJuYmYiOjEzNTcwMDAwMDB9.KcNaeDRMPwkRHDHsuIh1L2B01VApiu3aTOkWplFjoYI"
    token, err := jwt.Parse(myToken, nil)

    if err == nil && token.Valid {
        fmt.Println("Your token is valid.  I like your style.")
    } else {
        fmt.Println("This token is terrible!  I cannot accept this.")
    }

I have This token is terrible! I cannot accept this.

Running several SignedString(privateKey) in goroutines is almost the same as running in serial.

Hi there, just a note, not sure if this would be a bug, or just a normal behaviour that's to be expected with signing tokens via RSxxx.

On my system, where I need to sign one or many token at once. When I sign a token, it may take roughly 200-250ms for jwt.SignedString(). Of course, depending on what machine I use, it may be faster or slower due to CPU.

But when I tried signing 3 different tokens at the same time, using the same privateKey, the results are almost 3x longer.

The source for my implementation in psuedocode-ish looks like this:

for item := range stuff {
  i := doSomethingWith(item)
  go func() {
    doBasicClaims()
    AddPayloadClaim(i)
    s := jwt.SignedString(privateKey)
    sendOffToken(s)
    getBackData()
  }
}

So for this, all the other stuff took only a few ms, but the goroutines will take a total of 600 to 900 ms on a request that produces 3 iterations.

Here's what the verbose log looks like

Started POST /settings for localhost:10000
Processing all stuff 915.559ยตs
Iterating through 3 settings request 933.57ยตs
Finished processing all stuff, and waiting for return 954.803ยตs (for range:)
Processing AAAA 989.179ยตs
Before token signing with RSA256 1.175348ms
Processing BBBB 11.132295ms
Before token signing with RSA256 11.341492ms
Processing CCCC 22.01571ms
Before token signing with RSA256 22.350366ms
Token signing for BBBB took 613.113249ms current time @ 624.455326ms
Sent Request for BBBB 624.532368ms
Token signing for AAAA took 658.879584ms current time @ 660.055904ms
Sent Request for AAAA 660.175747ms
Token signing for CCCC took 656.992226ms current time @ 679.343004ms
Sent Request for CCCC 679.402761ms
Got back reply from AAAA 684.077767ms travel time took 23.902779ms
Finished Processing AAAA 684.188976ms
Got back reply from CCCC 686.740498ms travel time took 7.338188ms
Finished Processing CCCC 686.815321ms
Got back reply from BBBB 767.306613ms travel time took 142.774982ms
Finished Processing BBBB 767.355212ms
Completed 200 OK in 767.547319ms: served 1511 bytes

So, the question is, is this expected behaviour that I'm observing? I would be afraid to do this on hundreds of simultaneous token creations with RSA.

Just a note, the getBackData() parts are actually tokens signed with HS256 over a network, and the slowest one that took 142ms (BBBB), is actually from a Raspberry Pi. Which means, it took less time to verify an RSA signature, and generate a SignedString() with HS256 than to actually sign with RSA on a faster machine.

Is checking token.Valid needed?

In the README this example is given:

    token, err := jwt.Parse(myToken, func(token *jwt.Token) ([]byte, error) {
        return myLookupKey(token.Header["kid"])
    })

    if err == nil && token.Valid {
        deliverGoodness("!")
    } else {
        deliverUtterRejection(":(")
    }

Is there any case where err == nil but token.Valid == false or can we just check err?

"Signature is invalid" error

When verifying the token in the gist example "func (m *SigningMethodHS256) Verify" in sha256 throws "Signature is invalid" error. But in the example you ignore it and just check for type of error. I don't understand it. Can you explain ?

3.0

Opening a ticket for discussion. There are several proposed changes that will not be backwards compatible. It makes sense to land them together so we don't have to break integration multiple times. These are the changes I'm thinking of for 3.x:

  • Dropping support for passing []byte to the RSA signing methods. Instead, use the helper methods to deserialize your keys first. See #59
  • Support for custom types for Claims. See #66 and #73
  • Potentially adding support for json.Number, though I haven't fully grokked that yet. I need to re-read the json library documentation. #68
  • Potentially moving ParseFromRequest to a sub package and adding some options. This is a very popular request.

Things that look like they can land in 2.x:

  • Support for ECDSA signing methods (#74)
  • Support for RSASSA-PSS signing methods (#72)

I'm still on the fence about supporting none out of the box, though, if we did it would look something like #34 (comment)

Thoughts? Ideas? Did I miss something?

Should exp and nbf really be float64 or int64?

The example given in the readme shows something like:

token.Claims["exp"] = time.Now().Add(time.Hour * 72).Unix()

And this makes sense, feels like idiomatic Go. However, the actual implementation that checks for expired tokens expects a float64. What is the proper methodology here? I'm guessing float64 as the tests were written this way, so then maybe the README.md needs to be updated accordingly?

I'd be interested in thoughts on this!

3.0 - Claims panic

Hey!

I'm trying out the 3.0.0 release, works perfectly fine except one thing, I can't read the claims.
Panic: jwt.Claims is *jwt.StandardClaims, not jwt.StandardClaims

Code is pretty much the same as it is in the readme.

token, err := jwt.ParseWithClaims(t, keyFunc, &jwt.StandardClaims{})
claims := token.Claims.(jwt.StandardClaims)
fmt.Println(claims.Subject)

Any idea how to fix it? Or should I just go back to 2.0 for the time being?

Bad token in header causes error

I was trying to use the ParseFromRequest method and seem to have hit a problem when I send in a bad token in my Authorization header. If I delete a character or two from the token I send in I'll get something like:

Error while verifying token: *jwt.ValidationError:invalid character ''' looking for beginning of value

I've added a test case at mojotalantikite/jwt-go@7de7ec4ef43cbe0b3ec5f76a7a01b2285f4a7de7 where I'm just removing the 'ey' from the front of the token as an example.

JWT Audience

I am trying to parse a auth0.com JWT token that contains the CLIENT_ID in the payload. Are audiences supported? The token gets parsed successfully but Token.Valid is set to false. Where can I pass the CLIENT_ID? Thanks for your help

token, err := jwt.Parse("MY_JWT_TOKEN", func(token *jwt.Token) (interface{}, error) {
    return []byte("CLIENT_SECRET"), nil
})
"Claims": {
    "aud": "CLIENT_ID",
}

Any example of Parsing when using keys?

All of the examples I've found are for validating a token using HS256 using a []byte() for the secret. I'm wondering if there are any examples for validation when using keys?

Panic when parsing from request

Hi,

I noticed that the library will panic due to invalid memory address or nil pointer dereference if there is is a space in a token.

I just noticed this while playing around with PostMan Rest Client. If I send something like:

Authorization: asdasd asd asd asd 

There is no problem, but if I send:

Authorization: bearer asd asd asd asd 

Then the server panics. I guess this isn't a big issue really, I just thought you should be aware of it.

Tests fail in go1.3 rc1

Hey,

i just tested the new version go1.3rc1 and sadly it makes the test fail (for me at least, please verify)

--- FAIL: TestJWT (0.29 seconds)
    jwt_test.go:93: [basic expired] Claims mismatch. Expecting: map[foo:bar exp:1.401757378e+09]  Got: map[]
    jwt_test.go:108: [basic expired] Errors don't match expectation
    jwt_test.go:93: [basic nbf] Claims mismatch. Expecting: map[foo:bar nbf:1.401757578e+09]  Got: map[]
    jwt_test.go:108: [basic nbf] Errors don't match expectation
--- FAIL: TestParseRequest (0.29 seconds)
    jwt_test.go:134: [basic expired] Claims mismatch. Expecting: map[foo:bar exp:1.401757378e+09]  Got: map[]
    jwt_test.go:134: [basic nbf] Claims mismatch. Expecting: map[foo:bar nbf:1.401757578e+09]  Got: map[]
--- FAIL: TestHS256Verify (0.00 seconds)
    sha256_test.go:43: [web sample] Error while verifying key: illegal base64 data at input byte 44
FAIL
exit status 1
FAIL    github.com/dgrijalva/jwt-go 0.678s

A t.Log(err) before the DeepEqual in TestJWT reviled this:

illegal base64 data at input byte 48

The error is returned by the 2nd DecodeSegment in jwt.go L103

Googles OAuth2 JWT seems to have a similar issue. I adapted their workaround, which is really similar to the switch len(seg) %4 {} that was in DecodeSegment before.

key is invalid or of invalid type

Hi all,

I was working on something off of the advanced-ish gist from Cryptixfor this lib: https://gist.github.com/cryptix/45c33ecf0ae54828e63b

I ran the

openssl genrsa -out app.rsa 2048
openssl rsa -in app.rsa -pubout > app.rsa.pub

commands and saved the files into a keys/ dir. I got back two PEM format type files (PUBLIC KEY and PRIVATE KEY).

my go code is throwing the error, "key is invalid or of invalid type" when I try to use the token.SignedString() method as shown in the gist. I checked the source but this error is thrown in many places and I don't know how to resolve it.

package xyz

const privKeyPath string = "keys/app.rsa"
const pubKeyPath string = "keys/app.rsa.pub"

var signKey *rsa.PrivateKey
var verifyKey *rsa.PublicKey

func init() {

    var signBytes []byte
    var verifyBytes []byte
    var err error

    signBytes, err = ioutil.ReadFile(privKeyPath)
    if err != nil {
        log.Print(err)
    }
    signKey, err = jwt.ParseRSAPrivateKeyFromPEM(signBytes)
    if err != nil {
        log.Print(err)
    }
    verifyBytes, err = ioutil.ReadFile(pubKeyPath)
    if err != nil {
        log.Print(err)
    }
    verifyKey, err = jwt.ParseRSAPublicKeyFromPEM(verifyBytes)
    if err != nil {
        log.Print(err)
    }
}

func LoginAccount(username string, password string) (string, error) {
    var token_str string

    // get the account info from db

    combination := string(salt) + string(password)
    passwordHash := sha1.New()
    io.WriteString(passwordHash, combination)
    match := bytes.Equal(passwordHash.Sum(nil), hashedPassword)
    if !match {
        return token_str, errors.New("invalid password")
    }

    // create the jwt token
    token := jwt.New(jwt.SigningMethodHS256)
    token.Claims["username"] = username
    token.Claims["iat"] = time.Now()

    token_str, err = token.SignedString(signKey)
    if err != nil {
        return token_str, err
    }

    return token_str, nil
}

Missing checks on jwt.io

According to jwt.io, jwt-go is missing the following checks:

*iss check
*sub check
*aud check
*iat check
*jti check

I am not sure what exactly they entail, but does their lack create any security concerns?

Pass in User Type / Function for Claims Unmarshal

I'd like to pass in a custom type that I can have the JWT claims unmarshaled into rather than going into the default [map]{interface}. I don't know if it's easier to pass in a UDF that runs on the claim or if we can just pass in a type and implement the unmarshal interface for custom processing in an external package. Is there a technical reason that wouldn't work?

Draft version?

Hi,

Just curious about which draft version is implemented by this library.

For instance the ruby one listed on http://jwt.io clearly states it's implementing draft 6.
Putting it in the README as they do might help.

Thanks!

Migrate the `FromRequest` things into a sub-package with some more flexible features

The original ParseFromRequest method was just a helper I inserted based on how I was using this library. It is useful as an example, but far more specific than I'm comfortable with for this library. It's also hard to change it's behavior without introducing risk to users of the library.

I'd like to migrate, for version 3.0, all the request parsing behavior into a sub-package. In doing so, we should also modify it to be flexible, but have well defined behavior. Adding functionality should not introduce unexpected behavior for existing users.

basic example

I'm struggling to get the example from README to work, and keep getting error Signature is invalid

My code is as follows:

package main

import (
    "fmt"
    jwt "github.com/dgrijalva/jwt-go"
    "io/ioutil"
    "time"
)

func main() {

    privateKey, err := ioutil.ReadFile("keys/app.rsa")
    if err != nil {
        fmt.Println("Error reading private key")
        return
    }

    t := jwt.New(jwt.GetSigningMethod("HS256"))
    t.Claims["AccessToken"] = "bar"
    t.Claims["exp"] = time.Now().Add(time.Hour * 72).Unix()
    tokenString, err := t.SignedString(privateKey)

    fmt.Println("tokenString: " + tokenString)

    token, err := jwt.Parse(tokenString, func(token *jwt.Token) ([]byte, error) {

        fmt.Printf("parsed token obj: %v\n", token)
        publicKey, err := ioutil.ReadFile("keys/app.rsa.pub")
        if err != nil {
            return nil, fmt.Errorf("Error reading public key")
        }

        return publicKey, nil
    })

    if err == nil && token.Valid {
        //Carry on
    } else {
        fmt.Printf("Token parse error: %v\n", err)
    }
}

Running this generates the following output:

tokenString: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJBY2Nlc3NUb2tlbiI6ImJhciIsImV4cCI6MTM5MzEzODM5NH0.Bc15fCosx8K4PD2gavPIGoYTrxEvslhcw8sIa8GgYJc
parsed token obj: &{eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJBY2Nlc3NUb2tlbiI6ImJhciIsImV4cCI6MTM5MzEzODM5NH0.Bc15fCosx8K4PD2gavPIGoYTrxEvslhcw8sIa8GgYJc map[alg:HS256 typ:JWT] map[AccessToken:bar exp:1.393138394e+09] 0x771300  false}
Token parse error: Signature is invalid

What am I missing?

Slice bounds out of range exception

Hi,
I installed the jwt tool with go get github.com/dgrijalva/jwt-go/cmd/jwt and ran it using your example:

echo '{"foo":"bar"}' | jwt -key mykey -alg RS256 -sign - | jwt -key mykey.pub -verify -

It crashed with a "slice bounds out of range" Error in
main.verifyToken.func1 -> app.go:123
github.com/dgrijalva/jwt-go.Parse -> jwt-go/jwt.go:127
main.verifyToken -> jwt/app.go:127
main.start -> jwt/app.go:57 +0x67
main.main -> jwt/app.go:46

Hope that helps.

Add example for checking ValidationErrors

Can you add an example for checking if a token is valid? For some reason if there is a validation error it uses a bit instead of a specific err variable. Do you do this because you can set multiple errors this way(can you even do this with bits?)? I see that you use |= which I couldn't find much info about. However I made a playground to test it and it seems to work the same as =.

This is what I'm currently using to check for a validation error but I don't fully understand if there can be multiple validation errors because of how you set them with bits. Also I don't know if this will work if there are multiple errors.

if vErr,ok := err.(jwt.ValidationError); ok {
                if vErr.Errors == jwt.ValidationErrorExpired {
                    //handle the error
                }
            }

Would you mind explaining how this works a bit more or perhaps switching the validation errors to regular error variables in a future version. Thanks

Retrieving Objects from Claims fields

Is it possible to marshal an object from a t.Claims value (which is a map[string]interface{}) back to its original type?

Typically this would just be a type assertion away - e.g.

type User struct {
    ID string
    Data string
    Admin bool
}

// Generation
user = &User{ID: "1313193933391913", Data: "[email protected]", Admin: false}
t.Claims["user"] = user

// Parsing after calling jwt.Parse(...)
val, ok := t.Claims["user"].(*User)
if !ok {
    return nil, ErrInvalidUser
}

// val is of type *User.
return val, nil

My assumption here is that the boolean field in the struct is being marshalled to a string and cannot be un-marshalled back to the struct based on the below:

fmt.Printf("Type: %t\nValue: %v\n", t.Claims["user"], t.Claims["user"])

// Outputs:
Type: map[%!t(string=ID):%!t(string=1313193933391913) %!t(string=Data):%!t([email protected]) %!t(string=Admin):false]
Value: map[ID:1313193933391913 Data:[email protected] Admin:false]

Is there a way to resolve this without writing a ton of un-marshalling logic?

JWT produced 5 segments

I'm unable to recreate this occurrence but I was able to produce a JWT that contained 5 segments. I've built a test for it but have hit padding issues similar to what was resolved in: commit: 679bf0f .

JWT:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOiIyMDE1LTAxLTIyVDEzOjM5OjM2Ljc1MjcyNDA0Ny0wNTowMCIsImlkIjoxLCJpc3MiOiJsb2NhbGhvc3QiLCJpdCI6ImlaY0hjZG9JdlluSnBiRXBEaElQWWc9PSJ9.DRFip65fLbqOomUT82q1cin9s2_znpbiBcnHMU2-Vcg.eyJpYXQiOiIyMDE1LTAxLTIyVDEzOjIxOjI1LjQyMTAxMzczOC0wNTowMCIsImlkIjoxLCJpc3MiOiJsb2NhbGhvc3QiLCJpdCI6IkFETG9Bc3h1VklUdlc2MmpYd2lUYnc9PSJ9.frBtab8-eul5kle2iLwF0krmG0Cor0SeGs-3EKx6TL0

This results in 5 segments with header and claims correctly formatted but the third segment seems to be corrupted:

// Header
{
  "alg": "HS256",
  "typ": "JWT"
}

// Claims
{
  "iat": "2015-01-22T13:39:36.752724047-05:00",
  "id": 1,
  "iss": "localhost",
  "it": "iZcHcdoIvYnJpbEpDhIPYg=="
}

The crypto segment is very odd, but the second "sub-segment" in the crypto is the claims:

DRFip65fLbqOomUT82q1cin9s2_znpbiBcnHMU2-Vcg.eyJpYXQiOiIyMDE1LTAxLTIyVDEzOjIxOjI1LjQyMTAxMzczOC0wNTowMCIsImlkIjoxLCJpc3MiOiJsb2NhbGhvc3QiLCJpdCI6IkFETG9Bc3h1VklUdlc2MmpYd2lUYnc9PSJ9.frBtab8-eul5kle2iLwF0krmG0Cor0SeGs-3EKx6TL0

I made a hack to accept the multiple parts and just string it back together in Parse(): https://github.com/DisruptiveMind/jwt-go/blob/parse-multiple-segments/jwt_test.go#L180

The JWT seems to validate using jwt.io if that helps anything....

RSA signature shouldn't be used

  • AFAIK it isn't present in the JWT standard (only HS256 is)
  • there are no two distinct parties communicating here (which would require public key crypto)
  • my spidey sense tells me that the signing algorithm isn't correctly implemented and can be circumvented

RS256 panic

The example from the README fails with a panic when attempting to use RS256 (the example is working if I switch to HS256):

// Create the token
token := jwt.New(jwt.GetSigningMethod("RS256"))
// Set some claims
token.Claims["foo"] = "bar"
token.Claims["exp"] = time.Now().Add(time.Hour * 72).Unix()
// Sign and get the complete encoded token as a string
tokenString, err := token.SignedString(mySigningKey)

Panic:

panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x20 pc=0x438ef7]

goroutine 1 [running]:
runtime.panic(0x60a960, 0x8a4b28)
    /usr/local/go/src/pkg/runtime/panic.c:266 +0xb6
github.com/dgrijalva/jwt-go.New(0x0, 0x0, 0x0)
    /home/kmp/go/src/github.com/dgrijalva/jwt-go/jwt.go:39 +0x27
main.main()
    /home/kmp/projects/playground/googleapi.go:25 +0x54
exit status 2

Won't Decode Ruby Encoded String

I tested this with the jwt debugger at http://jwt.io. This key encoded with ruby-jwt and will not decode with go.

secret: supersecretkey

token:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1cmwiOiJodHRwOi8vbG9jYWxob3N0OjMwMDAvbWFuaWZlc3QuanNvbiJ9.a8DtiNS6v-n-OqLeVw2HTPDICGRVey3b-PUYBXlQkNk

code:

func parseToken(tokenString string) *jwt.Token {
    token, err := jwt.Parse(tokenString, keyFn)
    if err != nil {
        panic(err)
    }
    return token
}

func keyFn(token *jwt.Token) (interface{}, error) {
    println(token.Method.Alg())
    return vars.ManifestKey, nil
}

error:

key is invalid or of invalid type

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.