
Tired of handling user sessions and storing credentials in your app? Secure user authentication is difficult, but JSON Web Tokens (JWT) can be stateless, quick, and scalable. This article covers developing safe authentication using JWT in Go, from token generation to validation and handling.
What is JWT and Why Use It?
A concise, URL-safe mechanism to express claims between two parties is JWT. It allows safe authentication by passing information as a digitally signed JSON object. JWT authentication does not save session data on the server, unlike session-based authentication.
JWT's statelessness is its main benefit. Servers do not need to remember session state after token issuance. Instead, it uses the token for information, decreasing server load and scaling. A secret key or public/private key pair may sign JWTs, making them secure for user authentication.
Setting Up JWT Authentication in Go
We will use the popular github.com/golang-jwt/jwt package to start JWT authentication in Go. Start a Go project and install the package:
go get github.com/golang-jwt/jwt
Write code to produce a JWT. A typical JWT has a header, payload (claims), and signature. Go lets you declare claims like the user's ID and token expiry period and sign them with a secret key:
package main
import (
"fmt"
"time"
"github.com/golang-jwt/jwt"
)
var mySigningKey = []byte("secret")
func GenerateJWT(userID string) (string, error) {
claims := jwt.MapClaims{
"userID": userID,
"exp": time.Now().Add(time.Hour * 2).Unix(),
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString(mySigningKey)
}
func main() {
token, err := GenerateJWT("12345")
if err != nil {
fmt.Println("Error generating token:", err)
return
}
fmt.Println("Generated Token:", token)
}
This example code uses GenerateJWT to produce a token containing the user's ID and a 2-hour expiry. Signing using a secret key returns the token as a string.
Validating and Securing the JWT
After generating the JWT, validate it to verify the token. Validation checks the signature and token claims like expiry time.
How to validate the token:
func ValidateJWT(tokenString string) (*jwt.Token, error) {
token, err := jwt.Parse(tokenString, 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 mySigningKey, nil
})
if err != nil {
return nil, err
}
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
if claims["exp"].(float64) < float64(time.Now().Unix()) {
return nil, fmt.Errorf("token has expired")
}
return token, nil
}
return nil, fmt.Errorf("invalid token")
}
This method validates the expiry time and signature using mySigningKey. Invalid or expired tokens return errors.
For secure routes, middleware can verify each request's JWT:
func AuthMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
tokenString := r.Header.Get("Authorization")
_, err := ValidateJWT(tokenString)
if err != nil {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
next.ServeHTTP(w, r)
})
}
Refreshing Tokens for Secure Sessions
Stateless JWTs have an expiry period but no server-stored session data. Implement a refresh token system to prevent frequent logins. The client may request a refresh token, a longer-lived token, while a JWT is expiring.
Check out this refresh token flow:
At first, users get both an access token (JWT) and a refresh token when logging in.
Next, to get a new access token, submit the refresh token to the server when the token expires.
And at last, to avoid cross-site scripting attacks, save the refresh token securely in an HTTP-only cookie with a longer expiry period.
Conclusion
Go's JWT-based authentication makes development of secure, scalable apps without session storage easy. JWT's statelessness, token validation, and safe handling keep your application quick and secure. Refresh tokens reduce logins, improving security and user experience. Start using JWT in Go apps immediately for strong authentication!
227 views