# Membuat middleware menggunahkan JWT(JSON Web Token) di Gofiber

#### Konsep JWT (JSON Web Token)

JWT adalah metode yang digunakan untuk mengamankan komunikasi antara client dan server dengan cara membuat token yang berisi klaim-klaim tertentu, seperti user ID atau email. Token ini kemudian dikirim bersama setiap permintaan untuk memverifikasi identitas pengguna.

#### Langkah-langkah Menggunakan JWT dengan `github.com/dgrijalva/jwt-go`

1. **Install Package JWT**: Jalankan perintah berikut untuk menginstall paket `jwt-go`:

   ```bash
   go get github.com/dgrijalva/jwt-go
   ```
2. **Setup Environment Variables**: Tambahkan variabel lingkungan untuk menyimpan kunci rahasia JWT. Buat file `.env` dan tambahkan:

   ```
   SECRETKEY=your_secret_key_here
   ```
3. **Helper JWT**: Buat helper untuk menghasilkan token JWT.

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

   package helpers

   import (
       "time"

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

   func GenerateToken(secretKey, email string) (string, error) {
       token := jwt.New(jwt.SigningMethodHS256)
       claims := token.Claims.(jwt.MapClaims)
       claims["email"] = email
       claims["exp"] = time.Now().Add(time.Hour * 1).Unix()
       return token.SignedString([]byte(secretKey))
   }
   ```
4. **Middleware JWT**: Buat middleware untuk memeriksa validitas token JWT.

   ```go
   // src/middlewares/jwt.go

   package middlewares

   import (
       "fmt"
       "os"
       "strings"

       "github.com/dgrijalva/jwt-go"
       "github.com/gofiber/fiber/v2"
   )

   func ExtractToken(c *fiber.Ctx) string {
       bearerToken := c.Get("Authorization")
       if strings.HasPrefix(bearerToken, "Bearer ") {
           return strings.TrimPrefix(bearerToken, "Bearer ")
       }
       return ""
   }

   func JwtMiddleware() fiber.Handler {
       secretKey := os.Getenv("SECRETKEY")
       return func(c *fiber.Ctx) error {
           tokenString := ExtractToken(c)
           if tokenString == "" {
               return c.Status(fiber.StatusUnauthorized)
               .JSON(fiber.Map{"error": "Unauthorized"})
           }

           _, err := jwt.Parse(tokenString, func(token *jwt.Token) 
           (interface{}, error) {
               if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
                   return nil, fmt.Errorf("unexpected signing method: %v", 
                   token.Header["alg"])
               }
               return []byte(secretKey), nil
           })

           if err != nil {
               return c.Status(fiber.StatusUnauthorized)
               .JSON(fiber.Map{"error": "Unauthorized"})
           }

           return c.Next()
       }
   }
   ```
5. **Model User**: Buat model untuk user.

   ```go
   // src/models/Users.go

   package models

   import (
       "gofiber/src/configs"

       "gorm.io/gorm"
   )

   type User struct {
       gorm.Model
       Email    string `json:"email"`
       Password string `json:"password"`
   }

   func PostUser(user *User) error {
       return configs.DB.Create(user).Error
   }

   func FindEmail(email string) (*User, error) {
       var user User
       result := configs.DB.Where("email = ?", email).First(&user)
       return &user, result.Error
   }
   ```
6. **Controller User**: Buat controller untuk registrasi dan login user.

   ```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)

       if err := models.PostUser(&user); err != nil {
           return c.Status(fiber.StatusInternalServerError)
           .JSON(fiber.Map{"error": "Failed to create user"})
       }

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

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

       user, err := models.FindEmail(input.Email)
       if err != nil {
           return c.Status(fiber.StatusNotFound)
           .JSON(fiber.Map{"message": "Email not found"})
       }

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

       token, err := helpers.GenerateToken(os.Getenv("SECRETKEY"), user.Email)
       if err != nil {
           return c.Status(fiber.StatusInternalServerError)
           .JSON(fiber.Map{"error": "Failed to generate token"})
       }

       return c.JSON(fiber.Map{"message": "Login successfully", "token": token})
   }
   ```
7. **Router**: Tambahkan rute untuk registrasi dan login user.

   ```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)
   }
   ```
8. **Migrasi Database**: Tambahkan migrasi untuk model `User`.

   ```go
   // src/helpers/migration.go

   package helpers

   import (
       "gofiber/src/configs"
       "gofiber/src/models"
   )

   func Migration() {
       configs.DB.AutoMigrate(&models.Product{}, &models.Category{}, &models.User{})
   }
   ```

Dengan mengikuti langkah-langkah di atas, Anda dapat mengimplementasikan keamanan JWT untuk autentikasi dan menambahkan header keamanan menggunakan Helmet untuk meningkatkan keamanan aplikasi Fiber Anda.

Sumber : [Dokumentasi](https://github.com/dgrijalva/jwt-go)

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