In this tutorial, we'll explore the implementation of JSON Web Tokens (JWTs) in your Go web application to enhance user authentication and secure your API routes
To access the entire codebase, simply visit the GitHub Repository. Happy coding! 🚀
Let's begin by generating a JWT token using the generateToken.go
script. This script creates a unique user ID, generates a token, and prints it out for you. This token will serve as your digital authentication pass.
package main
import (
...
)
func main() {
if err := godotenv.Load(); err != nil {
fmt.Println("Error loading .env file")
return
}
uniqueID := generateUniqueID()
token, _ := createToken(uniqueID)
fmt.Println("Your Token:")
fmt.Println(token)
}
Once you've run this script, you'll obtain your token, ready for use in securing your API routes.
As you see Token is generated. Copy it to use later.
Also do not forget to add your SECRET_KEY
to the .env
file. Or you may specify in the editor. I prefer to use .env
for security concerns.
To secure your API routes, we'll use the JWT token in conjunction with the TokenVerifyMiddleware
.
This middleware ensures that only users with a valid token can access the specified routes. Let's take a look at the code:
package middleware
import (
...
"net/http"
"os"
"strings"
"github.com/dgrijalva/jwt-go"
)
func TokenVerifyMiddleware(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
secretKey := os.Getenv("SECRET_KEY")
authHeader := r.Header.Get("Authorization")
if authHeader == "" {
http.Error(w, "Authorization header is missing", http.StatusForbidden)
return
}
// Extract the token from the Authorization header
parts := strings.Split(authHeader, " ")
if len(parts) != 2 {
http.Error(w, "Malformed token", http.StatusForbidden)
return
}
tokenPart := parts[1]
token, err := jwt.Parse(tokenPart, 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 || !token.Valid {
http.Error(w, "Invalid or expired token", http.StatusForbidden)
return
}
next.ServeHTTP(w, r)
}
}
Now, let's secure our API routes using the TokenVerifyMiddleware
:
import (
...
"github.com/aozen/cocktail-recipe/internal/middleware"
)
func SecureAPI(handler http.HandlerFunc) http.HandlerFunc {
return middleware.TokenVerifyMiddleware(handler)
}
func SetupRoutes(r *mux.Router, db *mongo.Database) {
collection = db.Collection("cocktails")
r.HandleFunc("/api/cocktails", SecureAPI(getCocktails)).Methods("GET")
// ... Other routes protected by SecureAPI ...
}
With this setup, only users with a valid token can access the secured routes.
For demonstration purposes, let's use Postman to test our API routes. Open Postman and follow these steps:
Accessing Without Token:
/api/cocktails
) without providing a token in the Authorization header. Observe the "Authorization header is missing" error response.Accessing With Token:
/api/cocktails
). You should now receive a successful response.Feel free to explore more features and adapt the code based on your project's requirements. Secure coding made simple! 🍹
Feel free to reach out if you have any questions or need further assistance. Whether through email or your preferred communication channel, I'm here to help! Happy coding and enjoy the enhanced security of your Go web application! 🔐