dgrijalva / jwt-go

ARCHIVE - Golang implementation of JSON Web Tokens (JWT). This project is now maintained at:
https://github.com/golang-jwt/jwt
MIT License
10.79k stars 994 forks source link

Claim conversion: interface{} gets converted to map #403

Closed Techassi closed 4 years ago

Techassi commented 4 years ago

Hi,

first off: great library!

I am setting a claim like this:

var user interface{}
claims jwt.MapClaims = make(jwt.MapClaims)

claims["user"] = user
token = jwt.NewWithClaims(j.SigningMethod, claims)

I now parse the token and retrieve the claims

token, err := jwt.Parse(key, func(token *jwt.Token) (interface{}, error) {
    return secret, nil
})
fmt.Println(token.Claims.(jwt.MapClaims)["user"])

Output:

setting claim: map[user:{{false totp secret test@test.de} Test Test}]
retrieving claim: map[user:map[Password:Test Username:Test twofa_method:totp uses_twofa:false]]

The saved interface (user) did get converted to a map. Is there any possiblity to keep the value of the the claim an interface{}?

dcormier commented 4 years ago

A JWT simply stores JSON-formatted values. That var user interface{} ends up getting marshaled to JSON. When marshaling back from JSON to a jwt.Claims type (jwt.MapClaims, in this case), the unmarshaler doesn't know anything about the original golang type, only the type it's unmarshaling into. In this case, a map.

If you want different behavior, use a different jwt.Claims type instead of jwt.MapClaims. That may be as simple as something like:

type UserClaims sturct {
    jwt.StandardClaims
   User User `json:"u,omitempty"`
}

Then you would do (or example from docs):

claims  := UserClaims{
    User: user,
}

token = jwt.NewWithClaims(j.SigningMethod, claims)

And (or example from docs):

token, err := jwt.ParseWithClaims(key, UserClaims{}, func(token *jwt.Token) (interface{}, error) {
    return secret, nil
})
fmt.Println(token.Claims.(UserClaims).User)

Keep in mind that data you put into a JWT token is basically plain text (you can create one and put it here to see its decoded format). So, take care with what you put into one.

Related to that, the more you put in the claims, the larger the resulting token it will be. That may be important depending on how you expect the token to be used.

Techassi commented 4 years ago

Okay thank you.

A JWT simply stores JSON-formatted values. That var user interface{} ends up getting marshaled to JSON.

I did eventually get behind that fact, after writing this issue (duh). I will look into your suggestion and give you feedback.

Techassi commented 4 years ago

So I eventually settled with coverting my interface{} to an map aswell. Just made things easier.

For context: I am writing a simple and plugable authenticator and my interface{} was the user struct users are able to pass to my authenticator. So I wanted the most freedom and chose an interface.

Im closing this. Thank you for your help @dcormier