JWT Tokens in Go (Golang): Complete Guide
JSON Web Tokens (JWT) is an open standard (RFC 7519) for creating access tokens based on JSON. JWT is widely used for authentication and information exchange between a client and a server. In the Go (Golang) language, working with JWT tokens is implemented simply and efficiently thanks to the golang-jwt/jwt library.
In this article, we will thoroughly examine the creation, signing, verification, and use of JWT tokens in Go. The material will be useful for both beginners and experienced developers who want to implement secure authentication in their Golang projects.
Installing the golang-jwt Library
To work with JWT in Go, the package github.com/golang-jwt/jwt/v5 is used. Install it with the command:
go get github.com/golang-jwt/jwt/v5After installation, you can import the package into your code:
import ( "github.com/golang-jwt/jwt/v5")JWT Token Structure
A JWT token consists of three parts, separated by dots:
- Header — contains the token type (JWT) and the signing algorithm (e.g., HS256 or RS256).
- Payload — contains data (claims) such as user ID, role, expiration time, etc.
- Signature — created based on the header and payload using a secret key or an RSA/ECDSA key pair.
Creating a JWT Token in Go
Let's look at an example of creating a JWT token with the HMAC-SHA256 (HS256) algorithm. A secret key is required for this.
package main
import ( "fmt" "time" "github.com/golang-jwt/jwt/v5")
func main() { // Secret key (should be stored in a secure place) secretKey := []byte("my_secret_key_12345")
// Create claims claims := jwt.MapClaims{ "user_id": 123, "role": "admin", "exp": time.Now().Add(time.Hour * 24).Unix(), // token valid for 24 hours "iat": time.Now().Unix(), }
// Create token token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
// Sign the token with the secret key tokenString, err := token.SignedString(secretKey) if err != nil { fmt.Println("Error creating token:", err) return }
fmt.Println("Created JWT token:") fmt.Println(tokenString)}Verifying and Parsing a JWT Token
To verify the authenticity of the token, the same secret key is used. It is important to check the expiration time and signature.
package main
import ( "fmt" "github.com/golang-jwt/jwt/v5")
func main() { tokenString := "your_token_here" secretKey := []byte("my_secret_key_12345")
// Parse and verify the token token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { // Check the signing algorithm if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) } return secretKey, nil })
if err != nil { fmt.Println("Error verifying token:", err) return }
// Extract claims if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid { fmt.Println("Token is valid!") fmt.Printf("User ID: %v", claims["user_id"]) fmt.Printf("Role: %v", claims["role"]) } else { fmt.Println("Token is invalid") }}Using Structured Claims
For convenience, you can define your own claims structure that implements the jwt.Claims interface:
type CustomClaims struct { UserID int `json:"user_id"` Role string `json:"role"` jwt.RegisteredCl