Introduction
In modern web development, secure and scalable authentication is essential. JSON Web Tokens (JWT) have become a standard approach to achieving this. In this blog, we’ll explore what JWT is, how it works, and how to implement it in Golang.
What is a JWT?
A JSON Web Token (JWT) is a compact, URL-safe way of representing claims to be securely transferred between two parties. It is commonly used to authenticate and authorize users in APIs and distributed systems.
Structure of a JWT
A JWT consists of three parts separated by dots (.):
Header.Payload.Signature
Example:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.reGQzG3OKdoIMWLDKOZ4TICJit3EW69cQE72E2CfzRE
Each part is:
1.Header
: Specifies the token type (JWT) and signing algorithm (HS256).
{
"alg": "HS256",
"typ": "JWT"
}
2.Payload
: Contains claims (user data like id, role, or name).
{
"sub": "1234567890",
"name": "John Doe",
"admin": true,
"iat": 1516239022
}
3.Signature
: Ensures the token’s integrity using a cryptographic signing process. Let’s explore this in detail.
The signature is created by:
- Concatenating the Encoded Header and Payload:
base64UrlEncode(header) + "." + base64UrlEncode(payload)
- Signing the Result:
- A cryptographic signing algorithm (e.g.,
HMACSHA256
,RS256
) is used with a secret or private key.- Appending the Signature: The final JWT becomes
header.payload.signature
How JWT Works
- The client sends login credentials to the server.
- If valid, the server generates a JWT and returns it to the client.
- The client stores the JWT (e.g., in localStorage or cookies).
- For every request, the client includes the JWT in the Authorization header:
Authorization: Bearer <token>
- The server validates the JWT on each request.
- Recalculating the signature using the received header and payload.
- Comparing the recalculated signature with the received signature.
Implementing JWT in Golang
Golang developers can leverage the excellent golang-jwt/jwt library for handling JWTs. This library provides robust features for creating, signing, and validating JWTs. You can find it here.
However, managing JWTs often requires repetitive tasks like configuring signing methods, parsing tokens, and validating claims. To simplify this, I’ve written a custom package that wraps the golang-jwt functionality. You can check out my package here.
Below is an example of how to use my custom JWT package.
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/golang-jwt/jwt/v5"
jwtutil "github.com/kittipat1413/go-common/util/jwt"
)
type MyCustomClaims struct {
jwt.RegisteredClaims
UserID string `json:"uid"`
}
func main() {
ctx := context.Background()
signingKey := []byte("super-secret-key")
manager, err := jwtutil.NewJWTManager(jwtutil.HS256, signingKey)
if err != nil {
log.Fatalf("Failed to create JWTManager: %v", err)
}
// Prepare custom claims
claims := &MyCustomClaims{
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(15 * time.Minute)),
Issuer: "example-HS256",
Subject: "example-subject",
},
UserID: "abc123",
}
// Create the token
tokenStringHS256, err := manager.CreateToken(ctx, claims)
if err != nil {
log.Fatalf("Failed to create token: %v", err)
}
fmt.Println("Generated Token:", tokenStringHS256)
// Validate the token
parsedClaims := &MyCustomClaims{}
err = manager.ParseAndValidateToken(ctx, tokenStringHS256, parsedClaims)
if err != nil {
log.Fatalf("Failed to validate token: %v", err)
}
fmt.Printf("Token is valid! UserID: %s, Issuer: %s\n", parsedClaims.UserID, parsedClaims.Issuer)
}
You can explore the full implementation and documentation of my package on GitHub: here.
Best Practices for JWT
- Use HTTPS: Always transmit tokens over secure channels.
- Set Expiration Times: Include a reasonable exp to limit token misuse.
- Secure the Secret Key: Store keys securely using environment variables or secret managers.
- Avoid Sensitive Data in Payload: Only include non-critical information.
- Use Refresh Tokens: Pair JWT with refresh tokens to securely extend sessions.
Conclusion 🥂
JWT is a powerful tool for secure, stateless authentication. The signature ensures token integrity and authenticity, making JWT ideal for APIs and distributed systems. With libraries like jwt-go
, you can easily implement JWT in your Golang projects.
☕ Support My Work ☕
If you enjoy my work, consider buying me a coffee! Your support helps me keep creating valuable content and sharing knowledge. ☕
Top comments (0)