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.

    // 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.

    // 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.

    // 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.

Last updated