make jwt encode faster
Asked Answered
D

2

8

I have a /token endpoint that is working with a password grant. Because it's encoding a JWT token, it has high latency of about 1 second. Is there a way to make signing the JWT faster?

I'm using Go with the github.com/dgrijalva/jwt-go library.

package main

import (
    "crypto/rsa"
    "git.snappfood.ir/golang/framework/assert"
    "io/ioutil"
    "time"

    
    "github.com/dgrijalva/jwt-go"
    "github.com/sirupsen/logrus"
)

var (
    private *rsa.PrivateKey
    public  *rsa.PublicKey
)

func main() {
    var err error
    var priv, pub []byte
    pub, err = ioutil.ReadFile("public.pem")
    if err!=nil{
        panic(err)
    }
    priv, err = ioutil.ReadFile("private.pem")
    if err!=nil{
        panic(err)
    }

    public, err = jwt.ParseRSAPublicKeyFromPEM(pub)
    if err!=nil{
        panic(err)
    }

    private, err = jwt.ParseRSAPrivateKeyFromPEM(priv)
    if err!=nil{
        panic(err)
    }

    data := map[string]interface{}{
        "jti": "dara",
        "scopes": func() []string {
            return []string{"sara", "dara"}
        }(),
        "aud": "aud",
        "sub": "",
    }
    cl := jwt.MapClaims{}

    for k, v := range data {
        cl[k] = v
    }
    cl["iat"] = time.Now().Add(-6 * time.Hour).Unix()
    cl["exp"] = time.Now().UTC().Add(1 * time.Hour).Unix()

    t := jwt.NewWithClaims(jwt.GetSigningMethod("RS256"), cl)

    t2 := time.Now()
    tokenString, err := t.SignedString(private)
    assert.Nil(err)
    logrus.Warn(time.Since(t2))
    logrus.Warn(tokenString)

}
Ditter answered 7/6, 2020 at 11:7 Comment(4)
SignedString boils down to a call to rsa.SignPKCS1v15 in your case. The timing semantics of this function are controlled by its rand.Reader -- its (first) argument. In the case of jwt-go, this is crypto/rand.Reader. The implementation of crypto/rand.Reader depends on your platform. It may be blocking for a long time because of low entropy on your system. Try measuring across platforms.Vanadinite
Thanks for your description @Vanadinite . I'm using Ubuntu server and I want to reduce the time for encoding , how can I increase the entropy ? or is there another way ?Ditter
How did you reach the conclusion that it was the JWT generation that took 1 second? That sounds very unlikely to me. Did you see in profiling that the JWT encoding is what takes the most of time?Ara
I cant tell why it takes 1 second which is really slow. I am also signing JWTs in a project and there is no measurable impact. As a hint your used library github.com/dgrijalva/jwt-go is archived and no longer maintend. I would suggest switching to https://github.com/golang-jwt/jwt even though this might not affect your problem.Cousins
Z
3

Without jumping into library details, it's small but you don't need to initialize a map[string]interface then loop over it to populate a jwt.MapClaims{}. You can just start with a jwt.MapClaims{} like this:

cl := jwt.MapClaims{
    "jti": "dara",
    "scopes": func() []string {
        return []string{"sara", "dara"}
    }(),
    "aud": "aud",
    "sub": "",
    // no need to do these separately:
    "iat": time.Now().Add(-6 * time.Hour).Unix(),
    "exp": time.Now().UTC().Add(1 * time.Hour).Unix(),
}

Consider using Benchmark Tests to experiment with different approaches.


EDIT:

I think time.Now() can be slow sometimes depending on the machine/os and can be a possible factor. So make sure to benchmark time.Now() and look for issues such as this if you want to dig deeper

Zendejas answered 26/1, 2023 at 0:56 Comment(0)
F
-2

In Golang you can always step down to C level. But with that comes a large increase of complexity of shipping your app. But if any ms counts for you, it might be the way out.

But at the same time, (I have not profiled anything) it is still Go. You could easily parallelise the private/public ParseRSAPrivateKeyFromPEM calls to shave a few ms off

Forevermore answered 17/9, 2020 at 11:4 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.