gofiber / jwt

⚠️ Deprecated repository, available within Fiber Contrib.
https://github.com/gofiber/contrib/tree/main/jwt
MIT License
393 stars 31 forks source link

How to enable refresh token? #130

Open rngallen opened 1 year ago

rngallen commented 1 year ago

How can I have refresh token when user authenticated?

TomasVaras commented 1 year ago

im trying to implement just that, this middleware only checks for the token on the header so I don't think you could implement a refresh token strategy with this middleware.

So lets say you have a jwt token that lasts for 30 min and you have a refresh token for 24 hours, you could do something like this.

func Protected() fiber.Handler {

    return func(c *fiber.Ctx) error {

        token := c.Cookies("token")

        err := utilities.JwtChecker(token)

        if err != nil {

            refreshToken := c.Cookies("refresh_token")

            if refreshToken == "" {
                return c.SendStatus(fiber.StatusUnauthorized)
            }

            refreshClaims := new(utilities.Claims)

            err := utilities.JwtDecoder(refreshToken, refreshClaims)

            if err != nil {
                return c.SendStatus(fiber.StatusUnauthorized)
            }

            //go find the user by userid

            var user db.UserSchema

            // if the user does not exist wich its going to be
            // strange if it reaches this point, just send and internal status error

            if err := db.GetUserById(refreshClaims.UserId, &user); err != nil {
                return c.SendStatus(fiber.StatusInternalServerError)
            }

            // generate new claims

            claims := jwt.MapClaims{
                "name":    user.Name,
                "email":   user.Email,
                "userId":  user.UserId,
                "project": user.Project,
                "exp":     time.Now().Add(time.Minute * 30).Unix(),
            }

            // create and sign the token

            token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

            signinKey := []byte(os.Getenv("JWT_KEY"))

            t, tokenErr := token.SignedString(signinKey)

            if tokenErr != nil {
                return c.SendStatus(fiber.StatusInternalServerError)
            }

            c.Cookie(&fiber.Cookie{
                Name:     "token",
                Value:    t,
                HTTPOnly: true,
                Expires:  time.Now().Add(time.Minute * 30),
            })

            return c.Next()

        }

        return c.Next()

    }
}

also you could replace the refresh token if its close to expiring

func RefreshTokenUpdate() fiber.Handler {

    return func(c *fiber.Ctx) error {

        refreshToken := c.Cookies("refresh_token")

        if refreshToken == "" {
            return c.SendStatus(fiber.StatusUnauthorized)
        }

        refreshClaims := new(utilities.Claims)

        err := utilities.JwtDecoder(refreshToken, refreshClaims)

        if err != nil {
            return c.SendStatus(fiber.StatusUnauthorized)
        }

        expTime := time.Unix(refreshClaims.ExpiresAt.Unix(), 0)

        diff := expTime.Sub(time.Now())

        // fmt.Printf("Token expires in %.2f hours\n", diff.Hours())

        if diff <= 5*time.Hour {
            // create new refresh token

            refreshClaims.ExpiresAt = jwt.NewNumericDate(time.Now().Add(time.Hour * 24))

            newRefreshToken := jwt.NewWithClaims(jwt.SigningMethodHS256, refreshClaims)

            signinKey := []byte(os.Getenv("JWT_KEY"))

            rt, rTokenErr := newRefreshToken.SignedString(signinKey)

            if rTokenErr != nil {
                return c.SendStatus(fiber.StatusInternalServerError)
            }

            c.Cookie(&fiber.Cookie{
                Name:     "refresh_token",
                Value:    rt,
                Expires:  time.Now().Add(24 * time.Hour),
                HTTPOnly: true,
            })
        }

        return c.Next()

    }

}