### Basic nosurf Integration Example Source: https://github.com/justinas/nosurf/blob/master/README.md This example demonstrates how to integrate nosurf into a standard Go HTTP application. It wraps a custom http.Handler with nosurf.New() to provide CSRF protection for all non-safe HTTP methods. Ensure you include the CSRF token in your HTML forms. ```go package main import ( "fmt" "github.com/justinas/nosurf" "html/template" "net/http" ) var templateString string = ` {{ if .name }}

Your name: {{ .name }}

{{ end }}
` var templ = template.Must(template.New("t1").Parse(templateString)) func myFunc(w http.ResponseWriter, r *http.Request) { context := make(map[string]string) context["token"] = nosurf.Token(r) if r.Method == "POST" { context["name"] = r.FormValue("name") } templ.Execute(w, context) } func main() { myHandler := http.HandlerFunc(myFunc) fmt.Println("Listening on http://127.0.0.1:8000/") http.ListenAndServe(":8000", nosurf.New(myHandler)) } ``` -------------------------------- ### Complete nosurf Integration Example Source: https://context7.com/justinas/nosurf/llms.txt This Go program demonstrates a full integration of nosurf for CSRF protection. It includes setting up routes for form submissions, AJAX requests, and a health check endpoint. Configure CSRF settings like failure handlers and base cookies. ```go package main import ( "encoding/json" "html/template" "log" "net/http" "github.com/justinas/nosurf" ) var templates = template.Must(template.New("").Parse( ` {{define "layout"}} nosurf Demo

CSRF Protection Demo

{{end}} ` )) func main() { mux := http.NewServeMux() // Page with form mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { templates.ExecuteTemplate(w, "layout", map[string]interface{}{ "Token": nosurf.Token(r), }) }) // Form handler mux.HandleFunc("/form", func(w http.ResponseWriter, r *http.Request) { if r.Method == "POST" { message := r.FormValue("message") log.Printf("Received message: %s", message) http.Redirect(w, r, "/", http.StatusSeeOther) return } http.Redirect(w, r, "/", http.StatusSeeOther) }) // JSON API handler mux.HandleFunc("/api/data", func(w http.ResponseWriter, r *http.Request) { var req map[string]string json.NewDecoder(r.Body).Decode(&req) w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]interface{}{ "status": "success", "message": req["message"], }) }) // Health check (exempt from CSRF) mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("OK")) }) // Configure CSRF handler csrfHandler := nosurf.New(mux) // Custom failure handler with logging csrfHandler.SetFailureHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { log.Printf("CSRF failure: %v, path: %s", nosurf.Reason(r), r.URL.Path) http.Error(w, "CSRF token validation failed", http.StatusForbidden) })) // Secure cookie configuration csrfHandler.SetBaseCookie(http.Cookie{ Path: "/", HttpOnly: true, Secure: false, // Set to true in production with HTTPS MaxAge: 86400, }) // Exempt health check endpoint csrfHandler.ExemptPath("/health") log.Println("Server running on http://localhost:8080") http.ListenAndServe(":8080", csrfHandler) } ``` -------------------------------- ### Manual CSRF Token Verification Source: https://github.com/justinas/nosurf/blob/master/README.md When endpoints are excluded from automatic CSRF checks, you must manually verify tokens. This example shows how to unmarshal JSON data containing a token and verify it against the token provided by nosurf using VerifyToken. Ensure the handler is exempted using methods like ExemptFunc, ExemptGlob, or ExemptPath. ```go func HandleJson(w http.ResponseWriter, r *http.Request) { d := struct{ X,Y int Tkn string }{} json.Unmarshal(ioutil.ReadAll(r.Body), &d) if !nosurf.VerifyToken(nosurf.Token(r), d.Tkn) { http.Errorf(w, "CSRF token incorrect", http.StatusBadRequest) return } // do smth cool } ``` -------------------------------- ### Set Custom CSRF Failure Handler Source: https://context7.com/justinas/nosurf/llms.txt Sets a custom handler to be called when CSRF validation fails, overriding the default 400 Bad Request response. Use `nosurf.Reason(r)` within the custom handler to get the specific failure reason. ```go package main import ( "fmt" "net/http" "github.com/justinas/nosurf" ) func customFailureHandler(w http.ResponseWriter, r *http.Request) { // Get the reason for the CSRF failure reason := nosurf.Reason(r) w.WriteHeader(http.StatusForbidden) fmt.Fprintf(w, `

CSRF Validation Failed

Error: %s

Please go back and try again.

Return to home `, reason) } func main() { handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Success!")) }) csrfHandler := nosurf.New(handler) csrfHandler.SetFailureHandler(http.HandlerFunc(customFailureHandler)) http.ListenAndServe(":8080", csrfHandler) } ``` -------------------------------- ### Configure TLS detection with SetIsTLSFunc Source: https://context7.com/justinas/nosurf/llms.txt Use this to define how the application determines if a request is secure, particularly when operating behind a reverse proxy. ```go package main import ( "net/http" "slices" "strings" "github.com/justinas/nosurf" ) func main() { handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Protected endpoint")) }) csrfHandler := nosurf.New(handler) // Option 1: Direct TLS (no reverse proxy) csrfHandler.SetIsTLSFunc(func(r *http.Request) bool { return r.TLS != nil }) // Option 2: Behind a trusted reverse proxy trustedProxies := []string{"10.0.0.1", "10.0.0.2", "127.0.0.1"} csrfHandler.SetIsTLSFunc(func(r *http.Request) bool { // Get client IP (before the port) ip, _, _ := strings.Cut(r.RemoteAddr, ":") // Only trust X-Forwarded-Proto from known proxies if slices.Contains(trustedProxies, ip) { proto := r.Header.Get("X-Forwarded-Proto") return proto == "https" } // Direct connection - check TLS return r.TLS != nil }) http.ListenAndServe(":8080", csrfHandler) } ``` -------------------------------- ### Configure origin validation with SetIsAllowedOriginFunc Source: https://context7.com/justinas/nosurf/llms.txt Use StaticOrigins for fixed domain lists or a custom function for dynamic validation of cross-origin requests. ```go package main import ( "net/http" "net/url" "strings" "github.com/justinas/nosurf" ) func main() { handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Cross-origin request accepted")) }) csrfHandler := nosurf.New(handler) // Option 1: Static list of allowed origins allowedOrigins, err := nosurf.StaticOrigins( "https://app.example.com", "https://admin.example.com", "https://api.example.com", ) if err != nil { panic(err) } csrfHandler.SetIsAllowedOriginFunc(allowedOrigins) // Option 2: Dynamic origin validation csrfHandler.SetIsAllowedOriginFunc(func(origin *url.URL) bool { // Allow all subdomains of example.com if strings.HasSuffix(origin.Host, ".example.com") { return true } // Allow specific partner domains partnerDomains := []string{"partner1.com", "partner2.com"} for _, domain := range partnerDomains { if origin.Host == domain || strings.HasSuffix(origin.Host, "."+domain) { return true } } return false }) http.ListenAndServe(":8080", csrfHandler) } ``` -------------------------------- ### Create CSRF Handler and Serve HTTP Source: https://context7.com/justinas/nosurf/llms.txt Wraps an http.Handler with CSRF protection. Automatically generates and validates tokens, setting a cookie with a 1-year max-age by default. This is the primary way to integrate nosurf into your Go web application. ```go package main import ( "fmt" "html/template" "net/http" "github.com/justinas/nosurf" ) var tmpl = template.Must(template.New("form").Parse( ` {{ if .Name }}

Hello, {{ .Name }}!

{{ end }}
` )) func formHandler(w http.ResponseWriter, r *http.Request) { data := map[string]string{ "Token": nosurf.Token(r), } if r.Method == "POST" { data["Name"] = r.FormValue("name") } tmpl.Execute(w, data) } func main() { handler := http.HandlerFunc(formHandler) csrfHandler := nosurf.New(handler) fmt.Println("Server running on http://localhost:8080") http.ListenAndServe(":8080", csrfHandler) } ``` -------------------------------- ### nosurf.New Source: https://context7.com/justinas/nosurf/llms.txt Creates a new CSRFHandler that wraps an existing http.Handler to automatically generate and validate CSRF tokens. ```APIDOC ## nosurf.New ### Description Wraps an existing http.Handler with CSRF protection. It automatically generates a secure cookie and validates tokens on non-safe HTTP methods (POST, PUT, DELETE, PATCH). ### Parameters - **handler** (http.Handler) - Required - The handler to be wrapped with CSRF protection. ``` -------------------------------- ### Handle CSRF Failure with Reason Source: https://context7.com/justinas/nosurf/llms.txt Logs CSRF failures and returns specific HTTP errors based on the reason. Use this within a failure handler to diagnose validation issues. ```go package main import ( "log" "net/http" "github.com/justinas/nosurf" ) func loggingFailureHandler(w http.ResponseWriter, r *http.Request) { reason := nosurf.Reason(r) // Log the failure with details log.Printf("CSRF failure: %v, Path: %s, Method: %s, RemoteAddr: %s", reason, r.URL.Path, r.Method, r.RemoteAddr) // Return appropriate response based on error type switch reason { case nosurf.ErrBadToken: http.Error(w, "Invalid or missing CSRF token", http.StatusForbidden) case nosurf.ErrBadReferer, nosurf.ErrBadOrigin: http.Error(w, "Request origin not allowed", http.StatusForbidden) case nosurf.ErrNoReferer: http.Error(w, "Missing referer header", http.StatusForbidden) default: http.Error(w, "CSRF validation failed", http.StatusBadRequest) } } func main() { csrfHandler := nosurf.New(http.DefaultServeMux) csrfHandler.SetFailureHandler(http.HandlerFunc(loggingFailureHandler)) http.ListenAndServe(":8080", csrfHandler) } ``` -------------------------------- ### nosurf.VerifyToken Source: https://context7.com/justinas/nosurf/llms.txt Manually verifies that a provided token matches the expected CSRF token. ```APIDOC ## nosurf.VerifyToken ### Description Manually verifies that a sent token matches the real token. Useful for non-standard transmission methods like JSON request bodies. ### Parameters - **realToken** (string) - Required - The actual token retrieved via nosurf.Token(r). - **sentToken** (string) - Required - The token provided by the client in the request. ``` -------------------------------- ### Configure Base CSRF Cookie Source: https://context7.com/justinas/nosurf/llms.txt Customizes the CSRF token cookie attributes like Domain, Path, HttpOnly, Secure, and SameSite. Recommended for production environments. ```go package main import ( "net/http" "github.com/justinas/nosurf" ) func main() { handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Protected endpoint")) }) csrfHandler := nosurf.New(handler) // Configure secure cookie settings for production csrfHandler.SetBaseCookie(http.Cookie{ Name: "csrf_token", Path: "/", Domain: "example.com", MaxAge: 86400 * 30, // 30 days HttpOnly: true, Secure: true, SameSite: http.SameSiteStrictMode, }) http.ListenAndServe(":8080", csrfHandler) } ``` -------------------------------- ### Custom CSRF Exemption Logic with ExemptFunc Source: https://context7.com/justinas/nosurf/llms.txt Implement ExemptFunc to define custom logic for exempting requests from CSRF validation. This allows for complex rules based on request headers, IP addresses, or other attributes. ```go package main import ( "net/http" "strings" "github.com/justinas/nosurf" ) func main() { mux := http.NewServeMux() mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Protected endpoint")) }) csrfHandler := nosurf.New(mux) // Exempt requests based on custom logic csrfHandler.ExemptFunc(func(r *http.Request) bool { // Exempt requests with valid API key header if apiKey := r.Header.Get("X-API-Key"); apiKey != "" { return validateAPIKey(apiKey) } // Exempt requests from internal network if strings.HasPrefix(r.RemoteAddr, "10.0.") { return true } // Exempt specific content types (like server-to-server JSON APIs) contentType := r.Header.Get("Content-Type") if strings.Contains(contentType, "application/json") && r.Header.Get("X-Internal-Service") != "" { return true } return false }) http.ListenAndServe(":8080", csrfHandler) } func validateAPIKey(key string) bool { // Implement your API key validation logic validKeys := map[string]bool{ "secret-api-key-123": true, } return validKeys[key] } ``` -------------------------------- ### Exempt Paths Using Glob Patterns Source: https://context7.com/justinas/nosurf/llms.txt Exempts URL paths matching glob patterns from CSRF validation. Supports wildcards like '*' and '?'. Useful for grouping related API endpoints. ```go package main import ( "net/http" "github.com/justinas/nosurf" ) func main() { mux := http.NewServeMux() // Various API endpoints mux.HandleFunc("/api/v1/users", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Users API")) }) mux.HandleFunc("/api/v2/products", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Products API")) }) mux.HandleFunc("/static/images/logo.png", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Static content")) }) csrfHandler := nosurf.New(mux) // Exempt all API endpoints using glob pattern csrfHandler.ExemptGlob("/api/*") // Exempt multiple patterns csrfHandler.ExemptGlobs( "/static/*", "/public/*", "/webhooks/*", ) http.ListenAndServe(":8080", csrfHandler) } ``` -------------------------------- ### ExemptRegexp and ExemptRegexps Source: https://context7.com/justinas/nosurf/llms.txt Exempts URL paths matching regular expressions from CSRF validation. Accepts either a string pattern or a compiled `*regexp.Regexp`. ```APIDOC ## ExemptRegexp and ExemptRegexps ### Description Exempts URL paths matching regular expressions from CSRF validation. Accepts either a string pattern or a compiled `*regexp.Regexp`. ### Method `ExemptRegexp(pattern string | *regexp.Regexp)` `ExemptRegexps(patterns ...string | ...*regexp.Regexp)` ### Endpoint N/A (This is a method on the `CSRFHandler`) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```go // Exempt using string pattern csrfHandler.ExemptRegexp(`^/api/v\d+/.*$`) // Or use a pre-compiled regexp for better performance webhookPattern := regexp.MustCompile(`^/webhooks/[a-z]+/callback$`) csrfHandler.ExemptRegexp(webhookPattern) // Exempt multiple patterns at once csrfHandler.ExemptRegexps( `^/internal/.*$`, `^/rpc/.*$`, regexp.MustCompile(`^/events/\d+/notify$`), ) ``` ### Response None (These methods modify the handler's configuration) ### Error Handling None explicitly defined for these methods. ``` -------------------------------- ### RegenerateToken Source: https://context7.com/justinas/nosurf/llms.txt Generates a new CSRF token, sets it on the response, and returns it. Useful for token rotation after sensitive operations like login or password changes. ```APIDOC ## RegenerateToken ### Description Generates a new CSRF token, sets it on the response, and returns it. Useful for token rotation after sensitive operations like login or password changes. ### Method `RegenerateToken(w http.ResponseWriter, r *http.Request) string` ### Endpoint N/A (This is a method on the `CSRFHandler`) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```go // Regenerate token after successful login to prevent session fixation newToken := csrfHandler.RegenerateToken(w, r) // The new token can be used in the response w.Write([]byte("Login successful. New CSRF token: " + newToken)) ``` ### Response #### Success Response - **newToken** (string) - The newly generated CSRF token. #### Response Example ``` Login successful. New CSRF token: aBcDeFgHiJkLmNoPqRsTuVwXyZ0123456789 ``` ### Error Handling None explicitly defined for this method. ``` -------------------------------- ### nosurf.Token Source: https://context7.com/justinas/nosurf/llms.txt Retrieves the current CSRF token for the request, which should be included in forms or headers. ```APIDOC ## nosurf.Token ### Description Retrieves the CSRF token for the current request. The token is masked using one-time pad encryption to prevent BREACH attacks. ### Parameters - **r** (*http.Request) - Required - The current HTTP request. ``` -------------------------------- ### nosurf.SetFailureHandler Source: https://context7.com/justinas/nosurf/llms.txt Configures a custom handler to execute when CSRF validation fails. ```APIDOC ## nosurf.SetFailureHandler ### Description Sets a custom handler to be called when CSRF validation fails. The default behavior is to return an HTTP 400 Bad Request. ### Parameters - **handler** (http.Handler) - Required - The custom handler to execute on failure. ``` -------------------------------- ### Retrieve CSRF Token for AJAX Requests Source: https://context7.com/justinas/nosurf/llms.txt Retrieves the CSRF token for the current request, which should be included in AJAX requests as a header. The token is masked using one-time pad encryption to prevent BREACH attacks. This snippet demonstrates serving the token via a JSON API endpoint. ```go package main import ( "encoding/json" "net/http" "github.com/justinas/nosurf" ) func apiHandler(w http.ResponseWriter, r *http.Request) { // Return the CSRF token for use in subsequent AJAX requests response := map[string]string{ "csrfToken": nosurf.Token(r), } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(response) } // Client-side JavaScript usage: // fetch('/api/data', { // method: 'POST', // headers: { // 'X-CSRF-Token': csrfToken, // Token from /api/token response // 'Content-Type': 'application/json' // }, // body: JSON.stringify({data: 'value'}) // }) func main() { mux := http.NewServeMux() mux.HandleFunc("/api/token", apiHandler) http.ListenAndServe(":8080", nosurf.New(mux)) } ``` -------------------------------- ### Manually Verify CSRF Token from JSON Body Source: https://context7.com/justinas/nosurf/llms.txt Manually verifies a CSRF token sent in a JSON request body. This is useful when tokens are transmitted in non-standard ways. Both masked and unmasked tokens are supported. The JSON endpoint is also exempted from automatic verification. ```go package main import ( "encoding/json" "io" "net/http" "github.com/justinas/nosurf" ) type JSONRequest struct { Data string `json:"data"` Token string `json:"csrf_token"` } func jsonHandler(w http.ResponseWriter, r *http.Request) { body, _ := io.ReadAll(r.Body) var req JSONRequest json.Unmarshal(body, &req) // Manually verify the token from JSON body if !nosurf.VerifyToken(nosurf.Token(r), req.Token) { http.Error(w, "Invalid CSRF token", http.StatusBadRequest) return } // Token is valid, process the request w.Write([]byte("Request processed successfully")) } func main() { mux := http.NewServeMux() mux.HandleFunc("/api/json", jsonHandler) csrfHandler := nosurf.New(mux) // Exempt the JSON endpoint from automatic verification csrfHandler.ExemptPath("/api/json") http.ListenAndServe(":8080", csrfHandler) } ``` -------------------------------- ### ExemptFunc Source: https://context7.com/justinas/nosurf/llms.txt Sets a custom function to determine whether a request should be exempt from CSRF validation. Provides maximum flexibility for complex exemption logic based on request attributes. ```APIDOC ## ExemptFunc ### Description Sets a custom function to determine whether a request should be exempt from CSRF validation. Provides maximum flexibility for complex exemption logic based on request attributes. ### Method `ExemptFunc(fn func(*http.Request) bool)` ### Endpoint N/A (This is a method on the `CSRFHandler`) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```go csrfHandler.ExemptFunc(func(r *http.Request) bool { // Exempt requests with valid API key header if apiKey := r.Header.Get("X-API-Key"); apiKey != "" { return validateAPIKey(apiKey) } // Exempt requests from internal network if strings.HasPrefix(r.RemoteAddr, "10.0.") { return true } // Exempt specific content types (like server-to-server JSON APIs) contentType := r.Header.Get("Content-Type") if strings.Contains(contentType, "application/json") && r.Header.Get("X-Internal-Service") != "" { return true } return false }) ``` ### Response None (This method modifies the handler's configuration) ### Error Handling None explicitly defined for this method. ``` -------------------------------- ### Exempt URL Paths from CSRF Validation Source: https://context7.com/justinas/nosurf/llms.txt Use ExemptRegexp to exclude requests matching string patterns or compiled regular expressions from CSRF validation. This is useful for API endpoints or specific routes that do not require CSRF protection. ```go package main import ( "net/http" "regexp" "github.com/justinas/nosurf" ) func main() { mux := http.NewServeMux() mux.HandleFunc("/api/v1/resource", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("API v1")) }) mux.HandleFunc("/api/v2/resource", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("API v2")) }) csrfHandler := nosurf.New(mux) // Exempt using string pattern csrfHandler.ExemptRegexp(`^/api/v\d+/.*$`) // Or use a pre-compiled regexp for better performance webhookPattern := regexp.MustCompile(`^/webhooks/[a-z]+/callback$`) csrfHandler.ExemptRegexp(webhookPattern) // Exempt multiple patterns at once csrfHandler.ExemptRegexps( `^/internal/.*$`, `^/rpc/.*$`, regexp.MustCompile(`^/events/\d+/notify$`), ) http.ListenAndServe(":8080", csrfHandler) } ``` -------------------------------- ### Regenerate CSRF Token After Sensitive Operations Source: https://context7.com/justinas/nosurf/llms.txt Call RegenerateToken after successful authentication or other sensitive operations to issue a new CSRF token and prevent session fixation attacks. The new token is returned and should be used in subsequent requests. ```go package main import ( "net/http" "github.com/justinas/nosurf" ) func loginHandler(csrfHandler *nosurf.CSRFHandler) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if r.Method == "POST" { // Validate credentials... username := r.FormValue("username") password := r.FormValue("password") if authenticateUser(username, password) { // Regenerate token after successful login to prevent session fixation newToken := csrfHandler.RegenerateToken(w, r) // Set session cookie, redirect, etc. http.SetCookie(w, &http.Cookie{ Name: "session", Value: createSession(username), }) // The new token can be used in the response w.Write([]byte("Login successful. New CSRF token: " + newToken)) return } http.Error(w, "Invalid credentials", http.StatusUnauthorized) return } } func authenticateUser(username, password string) bool { return true } func createSession(username string) string { return "session-id" } func main() { csrfHandler := nosurf.New(http.DefaultServeMux) http.HandleFunc("/login", loginHandler(csrfHandler)) http.ListenAndServe(":8080", csrfHandler) } ``` -------------------------------- ### Exempt Specific Paths from CSRF Source: https://context7.com/justinas/nosurf/llms.txt Exempts individual URL paths from CSRF validation. Useful for public endpoints like health checks or webhooks. ```go package main import ( "net/http" "github.com/justinas/nosurf" ) func main() { mux := http.NewServeMux() // Public health check endpoint mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("OK")) }) // Webhook from external service mux.HandleFunc("/webhooks/stripe", func(w http.ResponseWriter, r *http.Request) { // Verify using Stripe signature instead of CSRF token w.Write([]byte("Webhook received")) }) // Another webhook endpoint mux.HandleFunc("/webhooks/github", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("GitHub webhook received")) }) csrfHandler := nosurf.New(mux) // Exempt single path csrfHandler.ExemptPath("/health") // Exempt multiple paths at once csrfHandler.ExemptPaths("/webhooks/stripe", "/webhooks/github") http.ListenAndServe(":8080", csrfHandler) } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.