# Membuat refresh token di Gofiber

#### Langkah-langkah Implementasi Refresh Token

1. **Update Helper JWT untuk Mendukung Refresh Token**:

   * Tambahkan fungsi `GenerateRefreshToken` untuk menghasilkan refresh token dengan klaim yang sama namun waktu kedaluwarsa yang lebih lama.

   ```go
   // src/helpers/jwt.go

   package helpers

   import (
       "time"

       "github.com/dgrijalva/jwt-go"
   )

   // GenerateToken generates a JWT token with dynamic claims
   func GenerateToken(secretKey string, payload map[string]interface{}) (string, error) {
       token := jwt.New(jwt.SigningMethodHS256)
       claims := token.Claims.(jwt.MapClaims)

       for key, value := range payload {
           claims[key] = value
       }

       claims["exp"] = time.Now().Add(time.Hour * 1).Unix()

       tokenString, err := token.SignedString([]byte(secretKey))
       if err != nil {
           return "", err
       }

       return tokenString, nil
   }

   // GenerateRefreshToken generates a refresh JWT token with dynamic claims
   func GenerateRefreshToken(secretKey string, payload map[string]interface{}) (string, error) {
       token := jwt.New(jwt.SigningMethodHS256)
       claims := token.Claims.(jwt.MapClaims)

       for key, value := range payload {
           claims[key] = value
       }

       claims["exp"] = time.Now().Add(time.Hour * 24).Unix()

       refreshTokenString, err := token.SignedString([]byte(secretKey))
       if err != nil {
           return "", err
       }

       return refreshTokenString, nil
   }
   ```
2. **Update Controller untuk Login dan Refresh Token**:

   * Update fungsi `LoginUser` untuk mengembalikan access token dan refresh token.
   * Tambahkan fungsi `RefreshToken` untuk menghasilkan token baru berdasarkan refresh token yang valid.

   ```go
   // src/controllers/UserController.go

   package controllers

   import (
       "gofiber/src/helpers"
       "gofiber/src/models"
       "os"

       "github.com/gofiber/fiber/v2"
       "golang.org/x/crypto/bcrypt"
   )

   func RegisterUser(c *fiber.Ctx) error {
       var user models.User
       if err := c.BodyParser(&user); err != nil {
           return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
               "error": "Failed to parse request body",
           })
       }

       hashPassword, _ := bcrypt.GenerateFromPassword([]byte(user.Password), bcrypt.DefaultCost)
       user.Password = string(hashPassword)

       models.PostUser(&user)

       return c.Status(fiber.StatusCreated).JSON(fiber.Map{
           "message": "Register successfully",
       })
   }

   func LoginUser(c *fiber.Ctx) error {
       var user models.User
       if err := c.BodyParser(&user); err != nil {
           return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
               "error": "Failed to parse request body",
           })
       }

       validateEmail := models.FindEmail(&user)
       if len(validateEmail) == 0 {
           return c.Status(fiber.StatusNotFound).JSON(fiber.Map{
               "message": "Email not found",
           })
       }

       var PasswordSecond string
       for _, user := range validateEmail {
           PasswordSecond = user.Password
       }

       if err := bcrypt.CompareHashAndPassword([]byte(PasswordSecond), []byte(user.Password)); err != nil || user.Password == "" {
           return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
               "message": "Invalid password",
           })
       }

       jwtKey := os.Getenv("SECRETKEY")
       payload := map[string]interface{}{
           "email": user.Email,
       }

       token, err := helpers.GenerateToken(jwtKey, payload)
       if err != nil {
           return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
               "error": "Could not generate access token",
           })
       }

       refreshToken, err := helpers.GenerateRefreshToken(jwtKey, payload)
       if err != nil {
           return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
               "error": "Could not generate refresh token",
           })
       }

       item := map[string]string{
           "Email":        user.Email,
           "Token":        token,
           "RefreshToken": refreshToken,
       }

       return c.Status(fiber.StatusCreated).JSON(fiber.Map{
           "message": "Login successfully",
           "data":    item,
       })
   }

   func RefreshToken(c *fiber.Ctx) error {
       var input struct {
           RefreshToken string `json:"refreshToken"`
       }
       if err := c.BodyParser(&input); err != nil {
           return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
               "error": "Failed to parse request body",
           })
       }

       jwtKey := os.Getenv("SECRETKEY")
       token, err := helpers.GenerateToken(jwtKey, map[string]interface{}{"refreshToken": input.RefreshToken})
       if err != nil {
           return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
               "error": "Could not generate access token",
           })
       }

       refreshToken, err := helpers.GenerateRefreshToken(jwtKey, map[string]interface{}{"refreshToken": input.RefreshToken})
       if err != nil {
           return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
               "error": "Could not generate refresh token",
           })
       }
       item := map[string]string{
           "Token":        token,
           "RefreshToken": refreshToken,
       }

       return c.Status(fiber.StatusCreated).JSON(fiber.Map{
           "message": "Refresh successfully",
           "data":    item,
       })
   }
   ```
3. **Update Routes untuk Mendukung Refresh Token**:

   * Tambahkan route baru untuk `refreshToken` di file routes.

   ```go
   // src/routes/main.go

   package routes

   import (
       "gofiber/src/controllers"
       "gofiber/src/middlewares"

       "github.com/gofiber/fiber/v2"
   )

   func Router(app *fiber.App) {
       // Product routes
       app.Get("/products", controllers.GetAllProducts)
       app.Get("/product/:id", controllers.GetProductById)
       app.Post("/product", controllers.CreateProduct)
       app.Put("/product/:id", controllers.UpdateProduct)
       app.Delete("/product/:id", controllers.DeleteProduct)

       // Category routes
       app.Get("/categories", middlewares.JwtMiddleware(), controllers.GetAllCategories)
       app.Get("/category/:id", controllers.GetCategoryById)
       app.Post("/category", controllers.CreateCategory)
       app.Put("/category/:id", controllers.UpdateCategory)
       app.Delete("/category/:id", controllers.DeleteCategory)

       // User Routes
       app.Post("/register", controllers.RegisterUser)
       app.Post("/login", controllers.LoginUser)
       app.Post("/refreshToken", controllers.RefreshToken)
   }
   ```

Dengan langkah-langkah ini, Anda telah berhasil mengimplementasikan fitur refresh token dalam aplikasi. Refresh token memungkinkan pengguna untuk mendapatkan token baru tanpa perlu login ulang ketika token akses mereka kedaluwarsa.

{% embed url="<https://github.com/zakimaliki/basic_gofiber_part_1/tree/0cdf52d112388cee51fc6f21556e511a5ade7449>" %}
