I'm reading the example folder for JWT i'm a bit unsure how things work for validating the token.
func ExampleNewWithClaims_customClaimsType() {
mySigningKey := []byte("AllYourBase")
type MyCustomClaims struct {
Foo string `json:"foo"`
jwt.StandardClaims
}
// Create the Claims
claims := MyCustomClaims{
"bar",
jwt.StandardClaims{
ExpiresAt: 15000,
Issuer: "test",
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
ss, err := token.SignedString(mySigningKey)
fmt.Printf("%v %v", ss, err)
//Output: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJleHAiOjE1MDAwLCJpc3MiOiJ0ZXN0In0.HE7fK0xOQwFEr4WDgRWj4teRPZ6i3GLwD5YCm6Pwu_c <nil>
}
Here it's straight forward and the token is being signed here token.SignedString(mySigningKey) using "mySigningKey"
Now there unparsing is much less clear for me :
func ExampleParseWithClaims_customClaimsType() {
tokenString := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJleHAiOjE1MDAwLCJpc3MiOiJ0ZXN0In0.HE7fK0xOQwFEr4WDgRWj4teRPZ6i3GLwD5YCm6Pwu_c"
type MyCustomClaims struct {
Foo string `json:"foo"`
jwt.StandardClaims
}
// sample token is expired. override time so it parses as valid
at(time.Unix(0, 0), func() {
token, err := jwt.ParseWithClaims(tokenString, &MyCustomClaims{}, func(token *jwt.Token) (interface{}, error) {
return []byte("AllYourBase"), nil
})
if claims, ok := token.Claims.(*MyCustomClaims); ok && token.Valid {
fmt.Printf("%v %v", claims.Foo, claims.StandardClaims.ExpiresAt)
} else {
fmt.Println(err)
}
})
// Output: bar 15000
}
Is order to validate that the signature of the token string given back by the client is valid would you need to
decode the claim ( done in &MyCustomClaims{} )
validate that the signature part of the decoded claim is valid against the " pub key included in the token" using token.Valid.
But the example is just decoding the key and by "magic" the return is the secret/signing key?
It doesn't make sense to me at all. Also returning a valid claim for a public key is useless as it could have been done by any private key.
What am i missing ?
Validation is not done by the public key included in the token.
HS256 is symmetric, so whatever key you used to sign the token, you have to use the same key to validate the signature, and that's what's happening. The function passed to ParseWithClaims is returning the same key used to sign the token.
If an asymmetric signing algorithm was used, you'd use the private key to sign the token, and then the public key to validate it, and that nested function would have to return the public key so that ParseWithClaims can validate it.
It sounds like the part that confused you is:
jwt.ParseWithClaims(tokenString, &MyCustomClaims{}, func(token *jwt.Token) (interface{}, error) {
return []byte("AllYourBase"), nil
})
The nested function passed to ParseWithClaims is supposed to inspect the token passed, and return the correct key that can be used to verify the signature. For HS256, it is the same as the key used to sign it. For RSxxx, it'd be the public key, and which public key it should return can be retrieved from the token passed in. It usually contains a public key id so you can select the correct key.
Related
I am trying to implement JWT for REST
I'm just curious on this code below
var mySigningKey = []byte("mysecret")
token, err := jwt.Parse(r.Header["Token"][0], func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("There was an error")
}
return mySigningKey, nil
})
fmt.Println(token)
I expect token will return mySigningKey value but its return Token value
that shoud return value inside mySigningKey right?
Or did I misunderstand some concept?
By calling Parse method on your header Token value you are creating the token struct. If you want to get your SigningString you need to call SigningString() method on your token variable.
// Generate the signing string. This is the
// most expensive part of the whole deal. Unless you
// need this for something special, just go straight for
// the SignedString.
func (t *Token) SigningString() (string, error) {
var err error
parts := make([]string, 2)
for i, _ := range parts {
var source map[string]interface{}
if i == 0 {
source = t.Header
} else {
source = t.Claims
}
var jsonValue []byte
if jsonValue, err = json.Marshal(source); err != nil {
return "", err
}
parts[i] = EncodeSegment(jsonValue)
}
return strings.Join(parts, "."), nil
}
The function which is the second argument to Parse is responsible for providing the signing key which will be used to verify the JWT signature is correct.
In the case illustrated in the question, the signing key is a constant because HMAC is used to sign it.
However, if you had a RSA keypair, the token header would be useful to pick the right public key to check the signature, perhaps pulling it down from a well known JWKS endpoint.
I see private key, but where to provide the public key so I can publish. Works perfectly but I am missing the public key, where is it given while creating the JWT token? I assume the example key (dnfksdmfksd) below is the private key. I am using github.com/dgrijalva/jwt-go Thanks!
func CreateToken(userid uint64) (string, error) {
var err error
//Creating Access Token
os.Setenv("ACCESS_SECRET", "jdnfksdmfksd") //this should be in an env file
atClaims := jwt.MapClaims{}
atClaims["authorized"] = true
atClaims["user_id"] = userid
atClaims["exp"] = time.Now().Add(time.Minute * 15).Unix()
at := jwt.NewWithClaims(jwt.SigningMethodHS256, atClaims)
token, err := at.SignedString([]byte(os.Getenv("ACCESS_SECRET")))
if err != nil {
return "", err
}
return token, nil
}
HS256 is a symmetric algorithm. It uses a shared secret. There is not public/private key. The recipients of the JWT have to use the same secret to validate the signature.
func Login(c echo.Context) error {
user := &users.User{}
if err := c.Bind(&user); err != nil {
return err
}
return token.SigIn(c, user.Email, user.Password)
}
This is my Login function that retrieve the token when the user send the requests.
the Signin func that handle the token
func SigIn(c echo.Context, email, password string) error {
user := users.User{}
db := database.SetUp()
if err := db.Where("email = ?", email).First(&user).Error; gorm.IsRecordNotFoundError(err) {
restErr := errors.NewBadRequestError("Invalid credentials")
return c.JSON(http.StatusBadRequest, restErr)
}
if user.VerifyPassword(password) != nil {
restErr := errors.NewUnauthorizedError("Couldn't log you in with these credentials")
return c.JSON(http.StatusUnauthorized, restErr)
}
//user is successfull
return CreateToken(c)
}
the CreateToken func is as follow
type TokenJWT struct {
Token string `json:"token"`
}
func CreateToken(c echo.Context) error {
token := jwt.New(jwt.SigningMethodHS256)
claims := token.Claims.(jwt.MapClaims)
claims["authorized"] = true
claims["name"] = "Pascal Gaetan"
claims["exp"] = time.Now().Add(time.Hour * 1).Unix()
// Generate encoded token and send it as response.
t, err := token.SignedString([]byte("my_secret_key"))
if err != nil {
return err
}
return c.JSON(http.StatusOK, TokenJWT{
Token: t,
})
}
when everyhting is succesfull, i would like to get the authenticated user through an URL /api/me that calls a Me function
Let me split your question into two parts: the first one is how to easily encode and decode user in or from JWT token and the second part is how to write a generic code which can retrieve user from everywhere.
From your example I mentioned that you created a MapClaims but to reduce parsing complexity it will be better to create a token using a custom claims type. If you are using dgrijalva/jwt-go, then according to documentation you can do something like that
type UserClaims struct {
Name string `json:"name"`
jwt.StandardClaims
}
// encode it as before, but with your created type
t := jwt.New(signer)
userClaims := &UserClaims{Name: "Burmese"}
t.Claims = userClaims
tokenString, err = t.SignedString(]byte("my_secret_key"))
then you can parse your user in your router/framework middleware with
tokenString := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJleHAiOjE1MDAwLCJpc3MiOiJ0ZXN0In0.HE7fK0xOQwFEr4WDgRWj4teRPZ6i3GLwD5YCm6Pwu_c"
token, err := jwt.ParseWithClaims(tokenString, &UserClaims{}, func(token *jwt.Token) (interface{}, error) {
return []byte("my_secret_key"), nil
})
if claims, ok := token.Claims.(*UserClaims); ok && token.Valid {
fmt.Printf("%v %v", claims.Name, claims.StandardClaims.ExpiresAt)
} else {
fmt.Println(err)
}
This example was adopted from an official documentation here
Now you know how to parse authenticated user struct with ease and the next logic move is to wrap it into your middleware. Whether there are a lot of implementation details like you can retrieve JWT from cookie, header or query, also defining some ordering on them, the gist the following: you should have wrapped abovementioned code into your middleware and after parsing the struct you can pass it via your request context. I don't use echo and other frameworks, but for pure net/http you can pass your parsed struct from middleware with
context.WithValue(ctx, UserCtxKey, claims)
Hope it helps!
This is a fairly common design pattern to create an authenticated client and then call various action methods on it. You could do something like the following:
type Client struct {
... // other members
token string // unexported unless there is a special reason to do otherwise
}
func NewClient(c echo.Context, email, password string) (*Client, error) {
user := users.User{}
cl := Client{}
... // your original method
cl.token = token
return &cl, nil
}
func (c *Client) DoSomething(...) ... { ... }
I need to retrieve the values of sub-claims from a JWT in Go.
I have (legacy) JWTs I need to parse in go, which contain a custom claim "data" which holds an Json-Object consisting of some fields (userid, username), so
{ [...standard claims]..., "data":{"id":"123", "name":"JohnDoe"} }
With using github.com/dgrijalva/jwt-go, I can parse the token and access the claims with this:
keyfunc := func(token *jwt.Token) (interface{}, error) {
return tknkey, nil
}
tkn, err := jwt.Parse(tknStr, keyfunc)
cl, _ := tkn.Claims.(jwt.MapClaims)
This works fine for the standard claims, and I also get the field names from the Json-Sub-Object in the "data" claim, but not the field values (all empty strings). I also tried setting up structs matching the claim hierarchy (outer and inner struct), with no success.
What would be the way to access the values of the sub-claims?
You can use jwt.MapClaims with "data": map[string]string with the following steps.
Steps 1.1 and 1.2 create the token
Steps 2.1 and 2.2 parse the token and extract the sub-claim values.
In the below example, jwt is github.com/golang-jwt/jwt/v4. Running code for this example is at github.com/grokify/goauth/examples/jwt/main.go.
Step 1.1: Create the claims
Create the custom MapClaims with a data map. Add a custom data.name property which we'll extract below.
claims := &jwt.MapClaims{
"iss": "issuer",
"exp": time.Now().Add(time.Hour).Unix(),
"data": map[string]string{
"id": "123",
"name": "JohnDoe",
},
}
Step 1.2: Create the JWT
For this example, we'll use a symmetric key.
token := jwt.NewWithClaims(
jwt.SigningMethodHS256,
claims)
secretKey := "foobar"
tokenString, err := token.SignedString([]byte(secretKey))
Step 2.1: Parse the token and cast claims to MapClaims.
Use the secretKey again since this example uses HS256.
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
return []byte(secretKey), nil
})
claims := token.Claims.(jwt.MapClaims)
Step 2.2: Extract custom sub-claim
Cast data to map[string]interface{} and cast data["name"] to string.
data := claims["data"].(map[string]interface{})
name := data["name"].(string)
Try this
type UserData struct {
Id string `json:"id"`
Name string `json:"name"`
}
type JWTClaim struct {
Data UserData `json:"data"`
jwt.StandardClaims
}
token, err := jwt.ParseWithClaims(
signedToken,
&JWTClaim{},
func(token *jwt.Token) (interface{}, error) {
return []byte(jwtKey), nil
},
)
Could anyone tell me why the following (from https://github.com/dgrijalva/jwt-go) example doesn't work?
token, err := jwt.Parse(myToken, func(token *jwt.Token) ([]byte, error) {
return myLookupKey(token.Header["kid"])
})
if err == nil && token.Valid {
deliverGoodness("!")
} else {
deliverUtterRejection(":(")
}
I get an error saying cannot use func literal (type func(*jwt.Token) ([]byte, error)) as type jwt.Keyfunc in argument to jwt.Parse
I've tried to use the code from couple of different jwt-go examples but always ended up with this same error.
The function Parse expects
type Keyfunc func(*Token) (interface{}, error)
You need to return interface{}, not byte[] in your function literal.
(maybe using a byte.Buffer to wrap the byte[], that you can then read as in "Convert arbitrary Golang interface to byte array")
Gert Cuykens points out in the comments to issue 36: commit e1571c8 should have updated the example.
Other examples like this gist also need to be updated.
As mentioned in another answer, the most recent version of is github.com/dgrijalva/jwt-go is v3.2.0+incompatible.
The docs are now outdated as the package's jwt.Keyfunc
function now has this signature:
type Keyfunc func (*Token) (interface{}, error)
When parsing JWTs, this jwt package also authenticates them. Two things are required to authenticate JWTs.
The JWT itself.
The cryptographic key that was used to sign the JWT. Typically, this is a public key.
This is where the jwt.Keyfunc fits in. The return value
of interface{} is later type asserted to a cryptographic key. For many use cases, this will be an RSA or ECDSA based
algorithm. This means the return type is typically *ecdsa.PublicKey
or *rsa.PublicKey. (HMAC keys can also be used, but I won't cover that
use case.)
If your public keys are in PEM format, you might be interested in using the functions built into the jwt
package: ParseECPublicKeyFromPEM
and ParseRSAPublicKeyFromPEM
.
Creating a public key data structure
If your public keys are in another format, you may need to build
the *ecdsa.PublicKey
and *rsa.PublicKey Go structs by populating their exported fields.
ECDSA
Here's the data structure to fill:
// PublicKey represents an ECDSA public key.
type PublicKey struct {
elliptic.Curve
X, Y *big.Int
}
The embedded elliptic.Curve is created by using the crypto/elliptic function associated with its length:
// Create the ECDSA public key.
publicKey = &ecdsa.PublicKey{}
// Set the curve type.
var curve elliptic.Curve
switch myCurve {
case p256:
curve = elliptic.P256()
case p384:
curve = elliptic.P384()
case p521:
curve = elliptic.P521()
}
publicKey.Curve = curve
For both X and Y, these are *big.Ints. If you have the bytes for these integers, creating a new *big.Int and
using the SetBytes method.
publicKey.X = big.NewInt(0).SetBytes(xCoordinate)
publicKey.Y = big.NewInt(0).SetBytes(yCoordinate)
RSA
Here's the data structure to fill:
// A PublicKey represents the public part of an RSA key.
type PublicKey struct {
N *big.Int // modulus
E int // public exponent
}
The modulus, N is a *big.Int. If you have the bytes for this integer, create a new *big.Int and using the
SetBytes method.
publicKey.N = big.NewInt(0).SetBytes(modulus)
The exponent is a regular integer. So that should be strait forward, but if you have the bytes for this integer instead
you can create an integer like this:
publicKey.E = int(big.NewInt(0).SetBytes(exponent).Uint64())
Create a jwt.Keyfunc
Now that the public keys are in the right data strucuture, it's time to create
a jwt.Keyfunc. As mentioned before, the
input for this function will be
a *jwt.Token and the output will be either
an *ecdsa.PublicKey or a
*rsa.PublicKey, but typed as an empty interface: interface{}, or
an error.
The *jwt.Token contains the JWT itself,
but the best way to identify which public key it's associated with is the kid. The kid is a string value contained
in the JWT header. Read about the
kid parameter in the RFC. It can be read from the JWT
like this:
// ErrKID indicates that the JWT had an invalid kid.
ErrKID := errors.New("the JWT has an invalid kid")
// Get the kid from the token header.
kidInter, ok := token.Header["kid"]
if !ok {
return nil, fmt.Errorf("%w: could not find kid in JWT header", ErrKID)
}
kid, ok := kidInter.(string)
if !ok {
return nil, fmt.Errorf("%w: could not convert kid in JWT header to string", ErrKID)
}
At this point, the input is a kid and the output is the public key. The simplest implementation of a
jwt.Keyfunc at this point is a function
that reads from a map[string]interface{} where the key string is a kid and value interface{} is its public key.
Here's an example:
// ErrKID indicates that the JWT had an invalid kid.
ErrKID := errors.New("the JWT has an invalid kid") // TODO This should be exported in the global scope.
// Create the map of KID to public keys.
keyMap := map[string]interface{}{"zXew0UJ1h6Q4CCcd_9wxMzvcp5cEBifH0KWrCz2Kyxc": publicKey}
// Create a mutex for the map of KID to public keys.
var mux sync.Mutex
// Create the jwt.Keyfunc
var keyFunc jwt.Keyfunc = func(token *jwt.Token) (interface{}, error) {
// Get the kid from the token header.
kidInter, ok := token.Header["kid"]
if !ok {
return nil, fmt.Errorf("%w: could not find kid in JWT header", ErrKID)
}
kid, ok := kidInter.(string)
if !ok {
return nil, fmt.Errorf("%w: could not convert kid in JWT header to string", ErrKID)
}
// Get the appropriate public key from the map of KID to public keys.
mux.Lock()
publicKey, ok := keyMap[kid]
mux.Unlock()
if !ok {
return nil, fmt.Errorf("%w: could not find a matching KID in the map of keys", ErrKID)
}
return publicKey, nil
}
You can now use the created keyFunc function-as-a-variable when parsing JWTs.
// Parse the JWT.
token, err := jwt.Parse(myToken, keyFunc)
if err != nil {
log.Fatalf("Failed to parse JWT.\nError: %s\n", err.Error())
}
// Confirm the JWT is valid.
if !token.Valid {
log.Fatalln("JWT failed validation.")
}
// TODO Proceed with authentic JWT.
Other JWT public key formats
JWTs' public keys can also be described by RFC 7517. This RFC describes
a JSON Web Key (JWK) and JSON Web Key Set (JWKs). Some identity providers, like Keycloak
or Amazon Cognito (AWS) provide these via HTTPS endpoints.
Here's an example JWKs:
{
"keys": [
{
"kid": "zXew0UJ1h6Q4CCcd_9wxMzvcp5cEBifH0KWrCz2Kyxc",
"kty": "RSA",
"alg": "PS256",
"use": "sig",
"n": "wqS81x6fItPUdh1OWCT8p3AuLYgFlpmg61WXp6sp1pVijoyF29GOSaD9xE-vLtegX-5h0BnP7va0bwsOAPdh6SdeVslEifNGHCtID0xNFqHNWcXSt4eLfQKAPFUq0TsEO-8P1QHRq6yeG8JAFaxakkaagLFuV8Vd_21PGJFWhvJodJLhX_-Ym9L8XUpIPps_mQriMUOWDe-5DWjHnDtfV7mgaOxbBvVo3wj8V2Lmo5Li4HabT4MEzeJ6e9IdFo2kj_44Yy9osX-PMPtu8BQz_onPgf0wjrVWt349Rj6OkS8RxlNGYeuIxYZr0TOhP5F-yEPhSXDsKdVTwPf7zAAaKQ",
"e": "AQAB",
"x5c": [
"MIICmzCCAYMCBgF4HR7HNDANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDDAZtYXN0ZXIwHhcNMjEwMzEwMTcwOTE5WhcNMzEwMzEwMTcxMDU5WjARMQ8wDQYDVQQDDAZtYXN0ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDCpLzXHp8i09R2HU5YJPyncC4tiAWWmaDrVZenqynWlWKOjIXb0Y5JoP3ET68u16Bf7mHQGc/u9rRvCw4A92HpJ15WyUSJ80YcK0gPTE0Woc1ZxdK3h4t9AoA8VSrROwQ77w/VAdGrrJ4bwkAVrFqSRpqAsW5XxV3/bU8YkVaG8mh0kuFf/5ib0vxdSkg+mz+ZCuIxQ5YN77kNaMecO19XuaBo7FsG9WjfCPxXYuajkuLgdptPgwTN4np70h0WjaSP/jhjL2ixf48w+27wFDP+ic+B/TCOtVa3fj1GPo6RLxHGU0Zh64jFhmvRM6E/kX7IQ+FJcOwp1VPA9/vMABopAgMBAAEwDQYJKoZIhvcNAQELBQADggEBALILq1Z4oQNJZEUt24VZcvknsWtQtvPxl3JNcBQgDR5/IMgl5VndRZ9OT56KUqrR5xRsWiCvh5Lgv4fUEzAAo9ToiPLub1SKP063zWrvfgi3YZ19bty0iXFm7l2cpQ3ejFV7WpcdLJE0lapFdPLo6QaRdgNu/1p4vbYg7zSK1fQ0OY5b3ajhAx/bhWlrN685owRbO5/r4rUOa6oo9l4Qn7jUxKUx4rcoe7zUM7qrpOPqKvn0DBp3n1/+9pOZXCjIfZGvYwP5NhzBDCkRzaXcJHlOqWzMBzyovVrzVmUilBcj+EsTYJs0gVXKzduX5zO6YWhFs23lu7AijdkxTY65YM0="
],
"x5t": "IYIeevIT57t8ppUejM42Bqx6f3I",
"x5t#S256": "TuOrBy2NcTlFSWuZ8Kh8W8AjQagb4fnfP1SlKMO8-So"
}
]
}
In the above example, a *rsa.PublicKey can be created from just the
n and e JSON attributes. It's kid attribute can be used to create an entry in the keyMap described in an earlier
section.
I've actually run into this use case before and created a Go package just for consuming JWKs and creating
jwt.Keyfunc. If this fits your use case,
check out the repository here: github.com/MicahParks/keyfunc.