Package xsrftoken provides methods for generating and validating secure XSRF tokens.
import "golang.org/x/net/xsrftoken"// Timeout is the duration for which XSRF tokens are valid
const Timeout = 24 * time.HourTimeout is exported so clients may set cookie timeouts that match generated tokens.
// Generate returns a URL-safe secure XSRF token that expires in 24 hours
func Generate(key, userID, actionID string) string
// Valid reports whether a token is valid and unexpired
func Valid(token, key, userID, actionID string) bool
// ValidFor reports whether a token is valid with a custom timeout
func ValidFor(token, key, userID, actionID string, timeout time.Duration) boolGenerate returns a URL-safe secure XSRF token that expires in 24 hours.
Valid reports whether a token is a valid, unexpired token returned by Generate. The token is considered expired and invalid if it is older than the default Timeout (24 hours).
ValidFor reports whether a token is a valid, unexpired token returned by Generate with a custom timeout duration. The token is considered expired and invalid if it is older than the specified timeout.
import (
"golang.org/x/net/xsrftoken"
"net/http"
)
const secretKey = "your-secret-key-here"
func renderForm(w http.ResponseWriter, r *http.Request, userID string) {
// Generate XSRF token
token := xsrftoken.Generate(secretKey, userID, "POST /submit")
// Include token in form
html := `
<form method="POST" action="/submit">
<input type="hidden" name="xsrf_token" value="` + token + `">
<input type="text" name="data">
<button type="submit">Submit</button>
</form>
`
w.Write([]byte(html))
}
func handleSubmit(w http.ResponseWriter, r *http.Request, userID string) {
// Validate XSRF token
token := r.FormValue("xsrf_token")
if !xsrftoken.Valid(token, secretKey, userID, "POST /submit") {
http.Error(w, "Invalid XSRF token", http.StatusForbidden)
return
}
// Process form submission
// ...
}func setXSRFCookie(w http.ResponseWriter, userID string) string {
token := xsrftoken.Generate(secretKey, userID, "")
// Set cookie with matching timeout
http.SetCookie(w, &http.Cookie{
Name: "xsrf_token",
Value: token,
MaxAge: int(xsrftoken.Timeout.Seconds()),
HttpOnly: true,
Secure: true,
SameSite: http.SameSiteStrictMode,
})
return token
}
func validateXSRFCookie(r *http.Request, userID string) bool {
cookie, err := r.Cookie("xsrf_token")
if err != nil {
return false
}
return xsrftoken.Valid(cookie.Value, secretKey, userID, "")
}func generateActionToken(userID, action string) string {
// Generate token specific to user and action
return xsrftoken.Generate(secretKey, userID, action)
}
func validateActionToken(token, userID, action string) bool {
return xsrftoken.Valid(token, secretKey, userID, action)
}
// Usage:
// token := generateActionToken("user123", "POST /delete")
// valid := validateActionToken(token, "user123", "POST /delete")import "time"
func generateShortLivedToken(userID string) string {
return xsrftoken.Generate(secretKey, userID, "quick-action")
}
func validateShortLivedToken(token, userID string) bool {
// Validate with 5-minute timeout instead of default 24 hours
return xsrftoken.ValidFor(token, secretKey, userID, "quick-action", 5*time.Minute)
}func XSRFMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
userID := getUserID(r) // Get user ID from session/auth
if r.Method == "GET" {
// For GET requests, generate and set token
token := xsrftoken.Generate(secretKey, userID, r.URL.Path)
r = r.WithContext(context.WithValue(r.Context(), "xsrf_token", token))
} else {
// For POST/PUT/DELETE, validate token
token := r.Header.Get("X-XSRF-Token")
if token == "" {
token = r.FormValue("xsrf_token")
}
if !xsrftoken.Valid(token, secretKey, userID, r.URL.Path) {
http.Error(w, "Invalid XSRF token", http.StatusForbidden)
return
}
}
next.ServeHTTP(w, r)
})
}