Explorar el Código

refresh token api

Tanveer Hassan hace 6 años
padre
commit
c6b19b5572
Se han modificado 3 ficheros con 93 adiciones y 18 borrados
  1. 48 18
      handler.go
  2. 2 0
      main.go
  3. 43 0
      token.go

+ 48 - 18
handler.go

@@ -1,8 +1,8 @@
 package main
 
 import (
+	"fmt"
 	"net/http"
-	"time"
 
 	"github.com/dgrijalva/jwt-go"
 	"github.com/labstack/echo"
@@ -18,31 +18,61 @@ func (h *handler) login(c echo.Context) error {
 
 	// Check in your db if the user exists or not
 	if username == "jon" && password == "password" {
-		// Create token
-		token := jwt.New(jwt.SigningMethodHS256)
-
-		// Set claims
-		// This is the information which frontend can use
-		// The backend can also decode the token and get admin etc.
-		claims := token.Claims.(jwt.MapClaims)
-		claims["name"] = "Jon Doe"
-		claims["admin"] = true
-		claims["exp"] = time.Now().Add(time.Hour * 72).Unix()
-
-		// Generate encoded token and send it as response.
-		// The signing string should be secret (a generated UUID works too)
-		t, err := token.SignedString([]byte("secret"))
+		tokens, err := generateTokenPair()
 		if err != nil {
 			return err
 		}
-		return c.JSON(http.StatusOK, map[string]string{
-			"token": t,
-		})
+
+		return c.JSON(http.StatusOK, tokens)
 	}
 
 	return echo.ErrUnauthorized
 }
 
+// This is the api to refresh tokens
+// Most of the code is taken from the jwt-go package's sample codes
+// https://godoc.org/github.com/dgrijalva/jwt-go#example-Parse--Hmac
+func (h *handler) token(c echo.Context) error {
+	type tokenReqBody struct {
+		RefreshToken string `json:"refresh_token"`
+	}
+	tokenReq := tokenReqBody{}
+	c.Bind(&tokenReq)
+
+	// Parse takes the token string and a function for looking up the key.
+	// The latter is especially useful if you use multiple keys for your application.
+	// The standard is to use 'kid' in the head of the token to identify
+	// which key to use, but the parsed token (head and claims) is provided
+	// to the callback, providing flexibility.
+	token, err := jwt.Parse(tokenReq.RefreshToken, func(token *jwt.Token) (interface{}, error) {
+		// Don't forget to validate the alg is what you expect:
+		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
+			return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
+		}
+
+		// hmacSampleSecret is a []byte containing your secret, e.g. []byte("my_secret_key")
+		return []byte("secret"), nil
+	})
+
+	if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
+		// Get the user record from database or
+		// run through your business logic to verify if the user can log in
+		if int(claims["sub"].(float64)) == 1 {
+
+			newTokenPair, err := generateTokenPair()
+			if err != nil {
+				return err
+			}
+
+			return c.JSON(http.StatusOK, newTokenPair)
+		}
+
+		return echo.ErrUnauthorized
+	}
+
+	return err
+}
+
 // Most of the code is taken from the echo guide
 // https://echo.labstack.com/cookbook/jwt
 func (h *handler) private(c echo.Context) error {

+ 2 - 0
main.go

@@ -20,5 +20,7 @@ func main() {
 
 	e.GET("/admin", h.private, isLoggedIn, isAdmin)
 
+	e.POST("/token", h.token)
+
 	e.Logger.Fatal(e.Start(":1323"))
 }

+ 43 - 0
token.go

@@ -0,0 +1,43 @@
+package main
+
+import (
+	"time"
+
+	"github.com/dgrijalva/jwt-go"
+)
+
+func generateTokenPair() (map[string]string, error) {
+	// Create token
+	token := jwt.New(jwt.SigningMethodHS256)
+
+	// Set claims
+	// This is the information which frontend can use
+	// The backend can also decode the token and get admin etc.
+	claims := token.Claims.(jwt.MapClaims)
+	claims["sub"] = 1
+	claims["name"] = "Jon Doe"
+	claims["admin"] = true
+	claims["exp"] = time.Now().Add(time.Minute * 15).Unix()
+
+	// Generate encoded token and send it as response.
+	// The signing string should be secret (a generated UUID works too)
+	t, err := token.SignedString([]byte("secret"))
+	if err != nil {
+		return nil, err
+	}
+
+	refreshToken := jwt.New(jwt.SigningMethodHS256)
+	rtClaims := refreshToken.Claims.(jwt.MapClaims)
+	rtClaims["sub"] = 1
+	rtClaims["exp"] = time.Now().Add(time.Hour * 24).Unix()
+
+	rt, err := refreshToken.SignedString([]byte("secret"))
+	if err != nil {
+		return nil, err
+	}
+
+	return map[string]string{
+		"access_token":  t,
+		"refresh_token": rt,
+	}, nil
+}