Implementing JWT Authentication in Go with Gin Framework
package auth
import (
"net/http"
"time"
"github.com/dgrijalva/jwt-go"
"github.com/gin-gonic/gin"
)
const secretKey = "application_secret_key"
type AuthController struct{}
type UserCredentials struct {
Username string `json:"username"`
Password string `json:"password"`
}
type TokenClaims struct {
UserID string `json:"user_id"`
jwt.StandardClaims
}
func (ac AuthController) Authenticate(c *gin.Context) {
var creds UserCredentials
if err := c.ShouldBindJSON(&creds); err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest,
gin.H{"message": "Invalid credentials format"})
return
}
if !validateCredentials(creds) {
c.AbortWithStatusJSON(http.StatusUnauthorized,
gin.H{"message": "Authentication failed"})
return
}
token, err := createToken(creds.Username)
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError,
gin.H{"message": "Token generation error"})
return
}
c.JSON(http.StatusOK, gin.H{"access_token": token})
}
func createToken(userID string) (string, error) {
expiry := time.Now().Add(30 * time.Minute)
claims := &TokenClaims{
UserID: userID,
StandardClaims: jwt.StandardClaims{
ExpiresAt: expiry.Unix(),
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString([]byte(secretKey))
}
func (ac AuthController) Protect() gin.HandlerFunc {
return func(c *gin.Context) {
authHeader := c.GetHeader("Authorization")
if authHeader == "" {
c.AbortWithStatusJSON(http.StatusUnauthorized,
gin.H{"message": "Missing authorization header"})
return
}
claims, err := verifyToken(authHeader)
if err != nil {
c.AbortWithStatusJSON(http.StatusUnauthorized,
gin.H{"message": "Invalid token"})
return
}
c.Set("user", claims.UserID)
c.Next()
}
}
func verifyToken(tokenString string) (*TokenClaims, error) {
claims := &TokenClaims{}
token, err := jwt.ParseWithClaims(tokenString, claims,
func(t *jwt.Token) (interface{}, error) {
return []byte(secretKey), nil
})
if err != nil || !token.Valid {
return nil, err
}
return claims, nil
}
func validateCredentials(creds UserCredentials) bool {
// Replace with actual authentication logic
return creds.Username == "admin" && creds.Password == "secure123"
}
To use this authentication system in your Gin routes:
// Public route for authentication
router.POST("/login", authController.Authenticate)
// Protected route example
router.GET("/dashboard", authController.Protect(), func(c *gin.Context) {
userID := c.MustGet("user").(string)
c.JSON(http.StatusOK, gin.H{"message": "Welcome " + userID})
})