Securing a Go Web Application with JWT

Table of Contents

  1. Introduction
  2. Prerequisites
  3. Setting Up a Go Web Application
  4. Implementing JWT Authentication
  5. Securing Your Web Application with JWT
  6. Conclusion

Introduction

In this tutorial, we will learn how to secure a Go web application using JSON Web Tokens (JWT). JWT is a popular standard for authentication and authorization in web applications. By the end of this tutorial, you will be able to implement JWT authentication in your Go web application and understand how to secure your application endpoints.

Prerequisites

To follow along with this tutorial, you should have a basic understanding of Go programming language and web development concepts. Familiarity with HTTP requests and responses, RESTful APIs, and JSON would be beneficial.

You will also need the following software installed on your system:

  1. Go programming language (version 1.16 or above)

  2. A text editor or integrated development environment (IDE) of your choice

Setting Up a Go Web Application

Before we dive into JWT authentication, let’s set up a simple Go web application to work with.

  1. Create a new directory for your project.
  2. Open a terminal or command prompt and navigate to the project directory.

  3. Initialize a new Go module using the following command:

    ```shell
    go mod init example.com/mywebapp
    ```
    
    This will create a new go.mod file for managing dependencies.
    
  4. Create a new main.go file and open it in your text editor or IDE.

  5. In the main.go file, add the following code to set up a basic web server:

    ```go
    package main
    
    import (
        "fmt"
        "net/http"
    )
    
    func main() {
        http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
            fmt.Fprint(w, "Welcome to my web application!")
        })
    
        fmt.Println("Server listening on port 8080")
        http.ListenAndServe(":8080", nil)
    }
    ```
    
    This code sets up a basic HTTP server that responds with "Welcome to my web application!" for all requests to the root ("/") URL.
    
  6. Save the main.go file and return to the terminal or command prompt.

  7. Start the web server by running the following command in the terminal:

    ```shell
    go run main.go
    ```
    
    You should see the message "Server listening on port 8080" indicating that the web server is running successfully.
    
  8. Open your web browser and navigate to http://localhost:8080. You should see the “Welcome to my web application!” message displayed.

    Congratulations! You have set up a basic Go web application. Now let’s move on to implementing JWT authentication.

Implementing JWT Authentication

To implement JWT authentication in Go, we will use a popular JWT library called “github.com/dgrijalva/jwt-go”.

  1. Make sure you have the necessary dependencies installed by running the following command in the terminal:

    ```shell
    go get github.com/dgrijalva/jwt-go
    ```
    
  2. In your main.go file, import the “github.com/dgrijalva/jwt-go” package:

    ```go
    import (
        "fmt"
        "net/http"
        "github.com/dgrijalva/jwt-go"
    )
    ```
    
  3. Next, we need to generate a JWT token when the user successfully logs in. We will create a new “/login” endpoint that generates and returns the token.

    ```go
    func loginHandler(w http.ResponseWriter, r *http.Request) {
        // Check the user credentials and authenticate
    
        // Create a new token
        token := jwt.New(jwt.SigningMethodHS256)
    
        // Set the claims (payload) of the token
        claims := token.Claims.(jwt.MapClaims)
        claims["username"] = "[email protected]"
        claims["exp"] = time.Now().Add(time.Hour * 24).Unix()
    
        // Generate the token
        tokenString, err := token.SignedString([]byte("secret_key"))
        if err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
            return
        }
    
        // Return the token as a response
        fmt.Fprint(w, tokenString)
    }
    
    func main() {
        http.HandleFunc("/login", loginHandler)
        // ...
    }
    ```
    
    In this code, we create a new JWT token using the "jwt.New" function and set the claims (payload) of the token. In this example, we set the "username" claim to "[email protected]" and the "exp" (expiration) claim to 24 hours from the current time.
    
    Finally, we generate the token using the "SignedString" method and return it as the response.
    
  4. Save the main.go file and restart the web server for the changes to take effect.

    ```shell
    go run main.go
    ```
    
  5. Open a new terminal or command prompt and send a POST request to http://localhost:8080/login using a tool like cURL or Postman. You should see the JWT token printed in the response.

    ```shell
    curl -X POST http://localhost:8080/login
    ```
    
    Note: In a real-world scenario, you would validate the user's credentials before generating the JWT token.
    

    Congratulations! You have implemented JWT authentication in your Go web application. Now, let’s secure your web application using the generated JWT token.

Securing Your Web Application with JWT

To secure your web application using JWT, we will add middleware that verifies the JWT token for protected routes.

  1. In the main.go file, define a new middleware function called “authenticate” that verifies the JWT token:

    ```go
    func authenticate(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            // Get the JWT token from the "Authorization" header
            tokenString := r.Header.Get("Authorization")
            if tokenString == "" {
                http.Error(w, "Unauthorized", http.StatusUnauthorized)
                return
            }
    
            // Parse the JWT token
            token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
                // Check the signing method
                if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
                    return nil, fmt.Errorf("invalid signing method")
                }
    
                // Return the secret key used for signing
                return []byte("secret_key"), nil
            })
    
            if err != nil || !token.Valid {
                http.Error(w, "Unauthorized", http.StatusUnauthorized)
                return
            }
    
            // Token is valid, call the next handler
            next.ServeHTTP(w, r)
        })
    }
    ```
    
    This middleware function extracts the JWT token from the "Authorization" header, parses and validates it using the secret key, and then calls the next handler if the token is valid. Otherwise, it returns an "Unauthorized" error.
    
  2. Now, let’s update our root (“/”) endpoint to be a protected route. Modify the “/” handler as follows:

    ```go
    func homeHandler(w http.ResponseWriter, r *http.Request) {
        fmt.Fprint(w, "Welcome to the secured home page!")
    }
    
    func main() {
        // ...
    
        http.HandleFunc("/", authenticate(homeHandler))
    
        // ...
    }
    ```
    
    We wrap the "homeHandler" function with the "authenticate" middleware using the "http.HandleFunc" function.
    
  3. Save the main.go file and restart the web server for the changes to take effect.

    ```shell
    go run main.go
    ```
    
  4. Try accessing http://localhost:8080 in your web browser. You should receive an “Unauthorized” error since you haven’t provided a JWT token in the request header.

  5. Now, let’s access the protected route by including the JWT token in the request header. Open a new terminal or command prompt and send a GET request to http://localhost:8080 with the JWT token in the “Authorization” header:

    ```shell
    curl -H "Authorization: Bearer <JWT token>" http://localhost:8080
    ```
    
    Replace "<JWT token>" with the actual JWT token generated in the previous step.
    
    You should now see the message "Welcome to the secured home page!" indicating that you have successfully accessed the protected route.
    

    Congratulations! You have successfully secured your Go web application using JWT authentication.

Conclusion

In this tutorial, we learned how to secure a Go web application with JSON Web Tokens (JWT). We started by setting up a basic Go web application, then implemented JWT authentication using the “github.com/dgrijalva/jwt-go” library. Finally, we secured our web application by adding middleware to verify the JWT token for protected routes.

By applying the concepts taught in this tutorial, you can enhance the security of your Go web applications and protect sensitive resources from unauthorized access. Remember to handle token validation, token expiration, and other security considerations as required by your specific application.

Feel free to explore additional features and capabilities of JWT and experiment with different authentication and authorization mechanisms in Go. Happy coding!