1

I am working on a SAAS based product which is built in Angular5 at front end. It uses Go's rest APIs to connect to DB and all back end functionality. I am using JWT token to authenticate the users on this system.

On the back end, I am using Gin framework for API routing and response handling.

The problem I am facing is that when ever I compile latest code on server. The token expires and it asks me to login again in order to generate new token.

The code I am using to generate JWT is given below:

package main

import (
    "github.com/dgrijalva/jwt-go"
    "github.com/gin-gonic/contrib/sessions"
)

func CreateToken(user models.User, c *gin.Context) (string, error){
    var ip, userAgent string
    keyError := config.InitKeys()
    if keyError != nil{
        return "", keyError
    }
    if values, _ := c.Request.Header["Ip"]; len(values) > 0 {
        ip = values[0]
    }

    if values, _ := c.Request.Header["User-Agent"]; len(values) > 0{
        userAgent = values[0]
    }


    token := jwt.NewWithClaims(jwt.SigningMethodHS256, &jwt.MapClaims{
        "email": user.EmailId,
        "exp":   time.Now().Add(time.Hour * 8).Unix(),
        "role": user.Role,
        "name":  user.FirstName+" "+user.LastName,
        "ip": ip,
        "user_agent": userAgent,
        "id": user.Id,
    })

    config.CurrentUserId    = user.Id
    models.CurrentUser      = user

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

    return tokenString, err
}

And code to compare it with the token that is being sent in the header from front end is:

if values, _ := c.Request.Header["Authorization"]; len(values) > 0 {
        bearer := strings.Split(c.Request.Header["Authorization"][0], "Bearer")
        bearerToken := strings.TrimSpace(bearer[1])
        _, err := merchantDb.GetSession(bson.M{"token": bearerToken})
        if err != nil{
            errMsg := "Failed: Unauthorized Access."
            response := controllers.ResponseController{
                config.FailureCode,
                config.FailureFlag,
                errMsg,
                nil,
            }
            controllers.GetResponse(c, response)
            c.Abort()
        }else{

            var ip, userAgent string
            var ipCheck, userAgentCheck bool

            if values, _ := c.Request.Header["Ip"]; len(values) > 0 {
                ip = values[0]
            }

            if values, _ := c.Request.Header["User-Agent"]; len(values) > 0{
                userAgent = values[0]
            }

            token, err := jwt.Parse(bearerToken, func(token *jwt.Token) (interface{}, error) {
                return config.SignKey, nil
            })
            if len (token.Claims.(jwt.MapClaims)) > 0{
                for key, claim := range token.Claims.(jwt.MapClaims) {
                    if key == "ip" {
                        if claim == ip{
                            ipCheck = true
                        }
                    }

                    if key == "user_agent"{
                        if claim == userAgent{
                            userAgentCheck = true
                        }
                    }   

                    if key == "role"{
                        role = claim.(string)
                    }

                    if key == "id"{
                        userId = claim.(float64)
                    }
                    if key == "name"{
                        userName = claim.(string)
                    }
                }
            }
            merchantDatabase["userid"] = userId
            merchantDatabase["role"] = role
            merchantDatabase["username"] = userName
            c.Keys = merchantDatabase
            if err == nil && token.Valid && ipCheck == true && userAgentCheck == true {
                c.Next()
            } else {
                errMsg := "Failed: Invalid Token."
                response := controllers.ResponseController{
                    config.FailureCode,
                    config.FailureFlag,
                    errMsg,
                    nil,
                }
                controllers.GetResponse(c, response)
                c.Abort()
            }
        }
    }else{
        errMsg := "Failed: Unauthorized Access."
        response := controllers.ResponseController{
            config.FailureCode,
            config.FailureFlag,
            errMsg,
            nil,
        }
        controllers.GetResponse(c, response)
        c.Abort()
    }

This issue is consuming a lot of time. If issue is known to anyone, Please reply to this post.

Thanks!

Grokify
  • 15,092
  • 6
  • 60
  • 81
Amandeep kaur
  • 985
  • 3
  • 15
  • 35
  • 1
    I can't see the check for exp anywhere in your code, what's the exact error message are you getting? – vitr Mar 31 '18 at 07:52
  • @vitr jwt.Parse is giving "signature is invalid" when I logged it in console. Also in token object, returned by jwt.Parse(), it gives token.Valid field as false. – Amandeep kaur Apr 02 '18 at 06:28
  • @vitr Also following is the value of exp I am getting after logging jwt claims: map[email:EMAIL exp:1.522677136e+09 ip:IP user_agent:Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:59.0) Gecko/20100101 Firefox/59.0] – Amandeep kaur Apr 02 '18 at 06:39
  • look inside jwt.Parse code, what package do you use? as you didn't include any imports in your code. Obviously, *'signature is invalid'* isn't the same case as *'expired'* – vitr Apr 02 '18 at 10:43
  • @vitr I have edited the code for package inclusion. – Amandeep kaur Apr 03 '18 at 04:03

1 Answers1

2

I suspect, there is something wrong with your session

_, err := merchantDb.GetSession(bson.M{"token": bearerToken})

or something else, as you didn't share the full code. Perhaps, your SigningKeys are not consistent between the builds. I wrote a small test for you to prove that jwt tokens don't expire between go builds

package main

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

func CreateToken() (string, error) {

    token := jwt.NewWithClaims(jwt.SigningMethodHS256, &jwt.MapClaims{
        "email":      "test@email.com",
        "exp":        time.Now().Add(time.Hour * 240).Unix(),
        //"exp":        time.Now().Add(-time.Hour * 8).Unix(),
        "role":       "test role",
        "name":       "test name",
        "ip":         "1.1.1.1",
        "user_agent": "test agent",
        "id":         "123",
    })

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

    return tokenString, err
}
func main() {

    //tokenString,_ := CreateToken()
    tokenString := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InRlc3RAZW1haWwuY29tIiwiZXhwIjoxNTIzNjAwOTM1LCJpZCI6IjEyMyIsImlwIjoiMS4xLjEuMSIsIm5hbWUiOiJ0ZXN0IG5hbWUiLCJyb2xlIjoidGVzdCByb2xlIiwidXNlcl9hZ2VudCI6InRlc3QgYWdlbnQifQ.UCD3P5-ua3qgTvy_-7hmHEVPPZwFCbhmRJNqndBwtes"
    token, _ := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
        return []byte("AllYourBase"), nil
    })
    fmt.Println(token)
    fmt.Println(token.Valid)
}

As you can check, the tokenString will be valid for the next 10 days wherever you run this code

vitr
  • 6,766
  • 8
  • 30
  • 50
  • its worked for me, i removed below code `_, ok := token.Method.(*jwt.SigningMethodHMAC)` while parsing token, I was also providing Method, but once I removed that , it worked for me – Ankit Gupta Mar 10 '23 at 14:09