Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Go and JWT - Simple authentication

Tags:

I'm currently making an API (with go) and I'm working on the session part. After research about what to use for session, I found JWT really interesting.

However I'm not really sure to understand how to use it after some tutorials. So this is my idea:

func main() {      router := mux.NewRouter().StrictSlash(true)      router.HandleFunc("/login", login)     router.HandleFunc("/logout", logout)     router.HandleFunc("/register", register)      http.ListenAndServe(":8080", router)   } 

After those requests handled, I create the differents functions.

func login(w http.ResponseWriter, r *http.Request) {     /*                                                                                                                                                                                                        Here I just have to search in my database (SQL, I know how to do it). If the user is registered, I create a token and give it to him, but how can I do it?                                                */  }   func logout(w http.ResponseWriter, r *http.Request) {     /*                                                                                                                                                                                                        I get a token and stop/delete it?                                                                                                                                                                         */  }   func register(w http.ResponseWriter, r *http.Request) {     /*                                                                                                                                                                                                        I search if the user isn't register and then, if it isn't, I create a user in the database (I know how to do it). I connect him but again, how to make a new token?                                       */  } 

Lot of tutorials on the web seems really hard but I just want something simple. I just want an handle package (code above) which work with a service package to have something like an engine token authentication.

A second point I'm not sure to understand is the saving of the token. If a user connects himself, then what would be best? Each time the user runs their app, the app connects itself and get a new token from saved information (user/password) or the app just save the token forever? And what about the server, is the token managed and saved automatically with JWT or do I have to put it in my sql database?

Thank for your help !

EDIT 1

Thank you ! So after I read your answer, I encapsulated my code (token.go) like it

package services  import (     "fmt"     "github.com/dgrijalva/jwt-go"     "time"     "../models" )  var tokenEncodeString string = "something"  func createToken(user models.User) (string, error) {     // create the token                                                                                                                                                                                       token := jwt.New(jwt.SigningMethodHS256)      // set some claims                                                                                                                                                                                        token.Claims["username"] = user.Username;     token.Claims["password"] = user.Password;     token.Claims["exp"] = time.Now().Add(time.Hour * 72).Unix()      //Sign and get the complete encoded token as string                                                                                                                                                       return (token.SignedString(tokenEncodeString)) }  func parseToken(unparsedToken string) (bool, string) {     token, err := jwt.Parse(unparsedToken, func(token *jwt.Token) (interface{}, error) {             // Don't forget to validate the alg is what you expect:                                                                                                                                                   if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {                     return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])             }             return myLookupKey(token.Header["kid"]), nil     })      if err == nil && token.Valid {             return true, unparsedToken     } else {             return false, ""     }  } 

However, I got the following error: "token.go: undefined: myLookupKey" I looked on internet and I found an encapsulated function which have this prototype:

func ExampleParse(myToken string, myLookupKey func(interface{}) (interface{}, error)) {  /* same code in my func parseToken() */ } 

So what are the difference between my function and this one? How can I use this one?

Thanks !

like image 501
Emixam23 Avatar asked Mar 26 '16 13:03

Emixam23


2 Answers

To start, you need to import a JWT library in Golang (go get github.com/dgrijalva/jwt-go). You can find that library documentation in below link.

https://github.com/dgrijalva/jwt-go

Firstly, you need to create a token

// Create the token token := jwt.New(jwt.SigningMethodHS256) // Set some claims token.Claims["foo"] = "bar" token.Claims["exp"] = time.Now().Add(time.Hour * 72).Unix() // Sign and get the complete encoded token as a string tokenString, err := token.SignedString(mySigningKey) 

Secondly, parse that token

token, err := jwt.Parse(myToken, func(token *jwt.Token) (interface{}, error) {     // Don't forget to validate the alg is what you expect:     if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {         return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])     }     return myLookupKey(token.Header["kid"]), nil })  if err == nil && token.Valid {     deliverGoodness("!") } else {     deliverUtterRejection(":(") } 

Also, there are some examples for use JWT in GOlang like this https://github.com/slok/go-jwt-example

EDIT-1

package main  import (     "fmt"     "time"      "github.com/dgrijalva/jwt-go" )  const (     mySigningKey = "WOW,MuchShibe,ToDogge" )  func main() {     createdToken, err := ExampleNew([]byte(mySigningKey))     if err != nil {         fmt.Println("Creating token failed")     }     ExampleParse(createdToken, mySigningKey) }  func ExampleNew(mySigningKey []byte) (string, error) {     // Create the token     token := jwt.New(jwt.SigningMethodHS256)     // Set some claims     token.Claims["foo"] = "bar"     token.Claims["exp"] = time.Now().Add(time.Hour * 72).Unix()     // Sign and get the complete encoded token as a string     tokenString, err := token.SignedString(mySigningKey)     return tokenString, err }  func ExampleParse(myToken string, myKey string) {     token, err := jwt.Parse(myToken, func(token *jwt.Token) (interface{}, error) {         return []byte(myKey), nil     })      if err == nil && token.Valid {         fmt.Println("Your token is valid.  I like your style.")     } else {         fmt.Println("This token is terrible!  I cannot accept this.")     } } 
like image 184
coditori Avatar answered Oct 19 '22 01:10

coditori


Just to make update of @massoud-afrashteh answer. In version 3 of jwt-go setting clams should be

// Set some claims claims := make(jwt.MapClaims) claims["foo"] = "bar" claims["exp"] = time.Now().Add(time.Hour * 72).Unix() token.Claims = claims 
like image 34
Paval Avatar answered Oct 19 '22 00:10

Paval