I am working on a SAAS based product. I am using JWT method to authenticate the logged in users in the system. The product is developed on Go on the backend with gin framework for routing.
Problem
When a user log in then its JWT token is generated and works well. Now the user did not logged out but closed the browser tab or window. Before he is back, the go app is re-installed with install command. Now the user come back and access his account, the token is expired and he could not see any of his details.
Following is the code to generate token while login:
func CreateToken(user models.User, c *gin.Context) (string, error){
var ip, userAgent string
keyError := 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 * 8760).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
}
func InitKeys()(err error){
SignKey, err = ioutil.ReadFile(GetBasePath()+PrivateKeyPath)
if err != nil {
return err
}
VerifyKey, err = ioutil.ReadFile(GetBasePath()+PublicKeyPath)
if err != nil {
return err
}
return nil
}
Now to decode and match the token following function is used:
func ParseJWTToken(c *gin.Context){
merchantDb := models.MerchantDatabase{ c.Keys["merchant_db"].(string) }
merchantDatabase := make(map[string]interface{})
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,
err,
}
controllers.GetResponse(c, response)
c.Abort()
}else{
var userAgent string
var userAgentCheck bool
if values, _ := c.Request.Header["User-Agent"]; len(values) > 0 {
userAgent = values[0]
}
_ = config.InitKeys()
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 == "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 && 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,
"Missing Authorization Header",
}
controllers.GetResponse(c, response)
c.Abort()
}
}
I am not able to detect what I am missing. Please look into the code and guide me what should I do in this case.