Decode JWT without validation and find scope - go

I need to decode my JWT token and check if the scope is a "Doctor".
I know very little about GO, but I just need to write a tiny snippet in my application to extend an existing application so it needs to be written in GO.
This was my attempt at decoding the token and checking if "Doctor" was in the decoded token as I wasn't able to access the scope exclusively.
for k, v := range props {
token_value := fmt.Sprint(v)
token_key := fmt.Sprint(cfg.AuthKey)
if (k == "custom_token_header") && strings.Contains(token_value, token_key) {
if token, _ := jwt.Parse(token_value, nil); token != nil {
parsed_token := fmt.Sprint(token)
log.Infof("Parsed token: " ,parsed_token)
if strings.Contains(parsed_token, "Doctor") {
log.Infof("user is a Doctor, perform checks...")
loc, _ := time.LoadLocation("GMT")
now := time.Now().In(loc)
hr, _, _ := now.Clock()
if hr >= 9 && hr < 5 {
log.Infof("success, inside of work hours!!")
return &v1beta1.CheckResult{
Status: status.OK,
}, nil
}
log.Infof("failure; outside of work hours!!")
return &v1beta1.CheckResult{
Status: status.WithPermissionDenied("Unauthorized..."),
}, nil
}
}
log.Infof("success, as you're not a doctor!!")
return &v1beta1.CheckResult{
Status: status.OK,
}, nil
}
}
It's working fine outside of my app, but when run inside my app it's being strange and giving back this <nil> map[] <nil> false for where the claims would be, but when run outside the app it gives me
map[alg:RS256 kid:NUVGODIxQThBQkY2NjExQjgzMEJEMjVBQTc3QThBNTY4QTY3MzhEMA typ:JWT] map[aud:https://rba.com/doctor azp:3XFBbjTL6tsL9wH6iZQtkz3rKgGeiLwh exp:1.55546266e+09 gty:client-credentials iat:1.55537626e+09 iss:https://jor2.eu.auth0.com/ scope:Doctor sub:3XFBbjTL6tsL9wH6iZQtkz3rKgGeiLwh#clients] false
Thanks to devdotlog I was able to get this working with this change:
for k, v := range props {
tokenString := fmt.Sprint(v)
tokenKey := fmt.Sprint(cfg.AuthKey)
if (k == "custom_token_header") && strings.Contains(tokenString, tokenKey) {
tokenString = strings.Replace(tokenString, "Bearer ", "", -1)
token, _, err := new(jwt.Parser).ParseUnverified(tokenString, jwt.MapClaims{})
if err != nil {
fmt.Println(err)
return nil, nil
}
if claims, ok := token.Claims.(jwt.MapClaims); ok {
tokenScope := fmt.Sprint(claims["scope"])
log.Infof("Scope: ", tokenScope)
if tokenScope == "Doctor" {
log.Infof("user is a Doctor, perform checks...")
loc, _ := time.LoadLocation("GMT")
now := time.Now().In(loc)
hr, _, _ := now.Clock()
if hr >= 9 && hr < 5 {
log.Infof("success, inside of work hours!!")
return &v1beta1.CheckResult{
Status: status.OK,
}, nil
}
log.Infof("failure; outside of work hours!!")
return &v1beta1.CheckResult{
Status: status.WithPermissionDenied("Unauthorized..."),
}, nil
}
fmt.Println(claims["scope"])
} else {
fmt.Println(err)
}
log.Infof("success, as you're not a doctor!!")
return &v1beta1.CheckResult{
Status: status.OK,
}, nil
}
}

You use github.com/dgrijalva/jwt-go. That's right?
You use ParseUnverified(https://godoc.org/github.com/dgrijalva/jwt-go#Parser.ParseUnverified) without validation.
Below code is ParseUnverified()' example.
package main
import (
"fmt"
"github.com/dgrijalva/jwt-go"
)
func main() {
// This token is expired
var tokenString = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJleHAiOjE1MDAwLCJpc3MiOiJ0ZXN0In0.HE7fK0xOQwFEr4WDgRWj4teRPZ6i3GLwD5YCm6Pwu_c"
token, _, err := new(jwt.Parser).ParseUnverified(tokenString, jwt.MapClaims{})
if err != nil {
fmt.Println(err)
return
}
if claims, ok := token.Claims.(jwt.MapClaims); ok {
fmt.Println(claims["foo"], claims["exp"])
} else {
fmt.Println(err)
}
}
ParseUnverified() only use for debug.
WARNING: Don't use this method unless you know what you're doing
This method parses the token but doesn't validate the signature. It's only ever useful in cases where you know the signature is valid (because it has been checked previously in the stack) and you want to extract values from it.

Related

Can't get Golang library to return anything but nil to controller

Golang toddler here, so I'd imagine I'm missing something obvious. After experimenting for a couple of days though, I decided to reach out for some help. :-)
The code I'm posting is working, except for the situation when a user requests a new client certificate/key package be created (this is an OpenVPN server administrative WebUI), when a client of the same name already exists. And even in that case, no new client package is created, but an incorrect alert message is displayed indicating that it has been.
I know I need to rework the controller to display different alert banners, based on whether the name exists or not. However, I'm stuck on getting anything besides "nil" back from the library.
The Golang controller code is as follows:
func (c *CertificatesController) Post() {
c.TplName = "certificates.html"
flash := beego.NewFlash()
cParams := NewCertParams{}
if err := c.ParseForm(&cParams); err != nil {
beego.Error(err)
flash.Error(err.Error())
flash.Store(&c.Controller)
} else {
if vMap := validateCertParams(cParams); vMap != nil {
c.Data["validation"] = vMap
} else {
if err := lib.CreateCertificate(cParams.Name, cParams.Passphrase); err != nil {
beego.Error(err)
flash.Error(err.Error())
flash.Store(&c.Controller)
} else {
fmt.Println(err)
flash.Success("Certificate for the name \"" + cParams.Name + "\" created")
flash.Store(&c.Controller)
}
}
}
c.showCerts()
}
And the library function that's called via lib.CreateCertificate:
func CreateCertificate(name string, passphrase string) error {
rsaPath := models.GlobalCfg.OVConfigPath + "easy-rsa"
rsaIndex := models.GlobalCfg.OVConfigPath + "easy-rsa/pki/index.txt"
pass := false
if passphrase != "" {
pass = true
}
certs, err := ReadCerts(rsaIndex)
if err != nil {
// beego.Debug(string(output))
beego.Error(err)
// return err
}
Dump(certs)
exists := false
for _, v := range certs {
if v.Details.Name == name {
exists = true
}
}
if !exists && !pass {
cmd := exec.Command("/bin/bash", "-c",
fmt.Sprintf(
"%s/easyrsa --batch build-client-full %s nopass",
rsaPath, name))
cmd.Dir = models.GlobalCfg.OVConfigPath
output, err := cmd.CombinedOutput()
if err != nil {
beego.Debug(string(output))
beego.Error(err)
return err
}
return nil
}
if !exists && pass {
cmd := exec.Command("/bin/bash", "-c",
fmt.Sprintf(
"%s/easyrsa --passout=pass:%s build-client-full %s",
rsaPath, passphrase, name))
cmd.Dir = models.GlobalCfg.OVConfigPath
output, err := cmd.CombinedOutput()
if err != nil {
beego.Debug(string(output))
beego.Error(err)
return err
}
return nil
}
if exists {
return err
}
return err
}
I've gone so far as changing every return in the library to err, and inserting a fmt.Println(err) in the controller's second "else" statement, but nil is all I ever get back.
So, I was able to figure out how to deal with this. A bit more googling and I found a post that was at least adjacent to what I was trying to accomplish. In the end, I only needed to add/change 3 lines in my certificates library. I needed to import the "errors" library, add a custom error in the form newError := errors.New("Error! There is already a valid or invalid certificate for that name") and change only the last return to return newError. I definitely learned a thing-or-two about how Go handles errors!
Here's the updated code for the certificates library:
func CreateCertificate(name string, passphrase string) error {
rsaPath := models.GlobalCfg.OVConfigPath + "easy-rsa"
rsaIndex := models.GlobalCfg.OVConfigPath + "easy-rsa/pki/index.txt"
pass := false
newError := errors.New("Error! There is already a valid or invalid certificate for that name")
if passphrase != "" {
pass = true
}
certs, err := ReadCerts(rsaIndex)
if err != nil {
// beego.Debug(string(output))
beego.Error(err)
// return err
}
Dump(certs)
exists := false
for _, v := range certs {
if v.Details.Name == name {
exists = true
}
}
if !exists && !pass {
cmd := exec.Command("/bin/bash", "-c",
fmt.Sprintf(
"%s/easyrsa --batch build-client-full %s nopass",
rsaPath, name))
cmd.Dir = models.GlobalCfg.OVConfigPath
output, err := cmd.CombinedOutput()
if err != nil {
beego.Debug(string(output))
beego.Error(err)
return err
}
return nil
}
if !exists && pass {
cmd := exec.Command("/bin/bash", "-c",
fmt.Sprintf(
"%s/easyrsa --passout=pass:%s build-client-full %s",
rsaPath, passphrase, name))
cmd.Dir = models.GlobalCfg.OVConfigPath
output, err := cmd.CombinedOutput()
if err != nil {
beego.Debug(string(output))
beego.Error(err)
return err
}
return nil
}
return newError
}
Now, if I try to add an OpenVPN client with a name that already exists:

Go Struct Fields Undefined

Learning Go as I work through creating a REST API. Getting the error undefined: authDetails when I use it the two times at the bottom to access the fields. I understand that it's set in a branch that may not be executed. I've tried moving it outside of the branch, or declaring it above with var authDetails auth.AccessDetails and then setting the values afterwards. I've also tried moving the assignment outside of the braces, but no matter what I do it doesn't seem to carry the values from within the conditional block out to where I try to use them.
I think I'm misunderstanding something regarding scope, if someone could assist me in understanding what the problem is it would be a huge help.
The Struct definition is:
type AccessDetails struct {
AccessUuid string
UserId uint64
}
and the code is:
func (server *Server) GetTokenUserIDFromRequest(r *http.Request) (uint64, error) {
var authDetails auth.AccessDetails
tokenString := auth.ExtractToken(r)
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return 0, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
}
return []byte(os.Getenv("API_SECRET")), nil
})
if err != nil {
return 0, err
}
claims, ok := token.Claims.(jwt.MapClaims)
if ok && token.Valid {
accessUuid, ok := claims["access_uuid"].(string)
if !ok {
return 0, errors.New("token not valid, cannot retrieve access_uuid")
}
userid, err := strconv.ParseUint(fmt.Sprintf("%.0f", claims["user_id"]), 10, 64)
if err != nil {
return 0, err
}
authDetails := &auth.AccessDetails{
AccessUuid: accessUuid,
UserId: userid,
}
}
redisuserid, err := server.RedisClient.Get(authDetails.AccessUuid).Result()
if err != nil {
return 0, err
}
userID, _ := strconv.ParseUint(redisuserid, 10, 64)
if userID != authDetails.UserId {
return 0, errors.New("userid from token does not match userid from database")
}
return userID, nil
}
You are redeclaring authDetails in the if-block instead of setting the value declared at the outer scope. The relevant section in the language specification is:
https://golang.org/ref/spec#Short_variable_declarations
Instead of authDetails:=... use authDetails=..., so it becomes an assignment, not a declaration.

Make Discord weatherBot with wego package

I'm trying to familiarize with Goland and i'd like to make my first bot Discord with it.
I'm making a discord bot and i'm trying to make a weather command using the wego package that's use the forecast's API, here's the package and a screenshot of what it looks like in the readme: here
Here's my code :
package main
import (
"flag"
"fmt"
"github.com/bwmarrin/discordgo"
"github.com/schachmat/ingo"
_ "github.com/schachmat/wego/backends"
_ "github.com/schachmat/wego/frontends"
"github.com/schachmat/wego/iface"
"log"
"os"
"sort"
"strconv"
"strings"
)
var (
commandPrefix string
botID string
)
func pluginLists() {
bEnds := make([]string, 0, len(iface.AllBackends))
for name := range iface.AllBackends {
bEnds = append(bEnds, name)
}
sort.Strings(bEnds)
fEnds := make([]string, 0, len(iface.AllFrontends))
for name := range iface.AllFrontends {
fEnds = append(fEnds, name)
}
sort.Strings(fEnds)
fmt.Fprintln(os.Stderr, "Available backends:", strings.Join(bEnds, ", "))
fmt.Fprintln(os.Stderr, "Available frontends:", strings.Join(fEnds, ", "))
}
func main() {
discord, err := discordgo.New("Bot My_Api_Key")
errCheck("error creating discord session", err)
user, err := discord.User("#me")
errCheck("error retrieving account", err)
botID = user.ID
discord.AddHandler(commandHandler)
discord.AddHandler(func(discord *discordgo.Session, ready *discordgo.Ready) {
err = discord.UpdateStatus(0, "A friendly helpful bot!")
if err != nil {
fmt.Println("Error attempting to set my status")
}
servers := discord.State.Guilds
fmt.Printf("GoBot has started on %d servers", len(servers))
})
err = discord.Open()
errCheck("Error opening connection to Discord", err)
defer discord.Close()
commandPrefix = "!"
<-make(chan struct{})
for _, be := range iface.AllBackends {
be.Setup()
}
for _, fe := range iface.AllFrontends {
fe.Setup()
}
// initialize global flags and default config
location := flag.String("location", "48.839661,2.375300", "`LOCATION` to be queried")
flag.StringVar(location, "l", "48.839661,2.375300", "`LOCATION` to be queried (shorthand)")
numdays := flag.Int("days", 1, "`NUMBER` of days of weather forecast to be displayed")
flag.IntVar(numdays, "d", 1, "`NUMBER` of days of weather forecast to be displayed (shorthand)")
unitSystem := flag.String("units", "metric", "`UNITSYSTEM` to use for output.\n \tChoices are: metric, imperial, si, metric-ms")
flag.StringVar(unitSystem, "u", "metric", "`UNITSYSTEM` to use for output. (shorthand)\n \tChoices are: metric, imperial, si, metric-ms")
selectedBackend := flag.String("backend", "forecast.io", "`BACKEND` to be used")
flag.StringVar(selectedBackend, "b", "forecast.io", "`BACKEND` to be used (shorthand)")
selectedFrontend := flag.String("frontend", "ascii-art-table", "`FRONTEND` to be used")
flag.StringVar(selectedFrontend, "f", "ascii-art-table", "`FRONTEND` to be used (shorthand)")
// print out a list of all backends and frontends in the usage
tmpUsage := flag.Usage
flag.Usage = func() {
tmpUsage()
pluginLists()
}
// read/write config and parse flags
if err := ingo.Parse("wego"); err != nil {
log.Fatalf("Error parsing config: %v", err)
}
// non-flag shortcut arguments overwrite possible flag arguments
for _, arg := range flag.Args() {
if v, err := strconv.Atoi(arg); err == nil && len(arg) == 1 {
*numdays = v
} else {
*location = arg
}
}
// get selected backend and fetch the weather data from it
be, ok := iface.AllBackends[*selectedBackend]
if !ok {
log.Fatalf("Could not find selected backend \"%s\"", *selectedBackend)
}
r := be.Fetch(*location, *numdays)
// set unit system
unit := iface.UnitsMetric
if *unitSystem == "imperial" {
unit = iface.UnitsImperial
} else if *unitSystem == "si" {
unit = iface.UnitsSi
} else if *unitSystem == "metric-ms" {
unit = iface.UnitsMetricMs
}
// get selected frontend and render the weather data with it
fe, ok := iface.AllFrontends[*selectedFrontend]
if !ok {
log.Fatalf("Could not find selected frontend \"%s\"", *selectedFrontend)
}
fe.Render(r, unit)
}
func errCheck(msg string, err error) {
if err != nil {
fmt.Printf("%s: %+v", msg, err)
panic(err)
}
}
func commandHandler(discord *discordgo.Session, message *discordgo.MessageCreate) {
user := message.Author
if user.ID == botID || user.Bot {
//Do nothing because the bot is talking
return
}
if message.Content == "test" {
discord.ChannelMessageSend(message.ChannelID, "test")
}
fmt.Printf("Message: %+v || From: %s\n", message.Message, message.Author)
}
So this does nothing, it just show the message that an user wrote in a channel. I saw that the print of the wego in the terminal is located in src/github.com/schachmat/frontends/emoji.go but i don't know how to use it with my bot, i'd like to print that when an user type "!weather".
I'm lost and don't know what to do.
Sorry for the english, i tried my best, and it's my first post on StackOverflow :)

JWT token expired when Go app is installed

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.

Go's JWT token expires when I compile new code

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!
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

Resources