I am using NoSurf for CSRF in my Golang code. This is from Trevor Sawler's Golang course, section 8.2. If anything, I decide to go with Bootstrap 5 instead the tutorial's Bootstrap 4. My code can be found here. To activate the web server, I use go run ./cmd/web/*.go
. So inside cmd\web\routes.go
, the following are available for the localhost:8080/search-availability
page:
mux.Get("/search-availability", handlers.Repo.Availability)
mux.Post("/search-availability", handlers.Repo.AvailabilityPost)
Inside pkg\handlers\handlers.go
, I have:
func (m *Repository) Availability(w http.ResponseWriter, r *http.Request) {
log.Println("Availability")
render.RenderTemplate(w, r, "search-availability.page.tmpl", &models.TemplateData{})
}
func (m *Repository) AvailabilityPost(w http.ResponseWriter, r *http.Request) {
log.Println("Before Write")
w.Write([]byte("Posted to search-availability"))
log.Println("After Write")
}
Inside pkg\render\render.go
, I have:
func AddDefaultData(td *models.TemplateData, r *http.Request) *models.TemplateData {
td.CsrfToken = nosurf.Token(r)
return td
}
Inside pkg\models\templatedata.go
, I have:
type TemplateData struct {
StringMap map[string]string
IntMap map[string]int
FloatMap map[string]float64
Data map[string]interface{}
CsrfToken string
Flash string
Error string
}
Inside templates\search-availability.page.tmpl
, I have on line 13:
<input type="text" name="csrf_token" value="{{.CsrfToken}}">
After choosing the start and end date from the localhost:8080/search-availability
page, clicking on the Search Availability
button always gets me a 400 Bad Request
as seen below.
From the terminal, I can see that the code never enters AvailabilityPost
:
2023/03/12 19:06:48 Hit the page
2023/03/12 19:06:48 Availability
2023/03/12 19:06:51 Hit the page
However if I disable nosurf
inside cmd\web\routes.go
like this:
func routes(app *config.AppConfig) http.Handler {
mux := chi.NewRouter()
mux.Use(middleware.Recoverer)
mux.Use(WriteToConsole)
// mux.Use(NoSurf)
mux.Use(SessionLoad)
...
mux.Get("/search-availability", handlers.Repo.Availability)
mux.Post("/search-availability", handlers.Repo.AvailabilityPost)
...
fileServer := http.FileServer(http.Dir("./static/"))
mux.Handle("/static/*", http.StripPrefix("/static", fileServer))
return mux
}
The browser shows a successful post:
Posted to search-availability
The terminal also confirms:
2023/03/12 19:19:46 Hit the page
2023/03/12 19:19:46 Availability
2023/03/12 19:19:48 Hit the page
2023/03/12 19:19:48 Before Write
2023/03/12 19:19:48 After Write
Could someone point out what I have done wrong? I am not getting a successful post as seen in the tutorial. The material is a bit dated, but I can't see how it be an issue.
You didn't send the CSRF token input on form submit. To fix this, you can either add the form attribute to your CSRF input element and set it to the ID of your form (date-picker), or move the CSRF input element inside the form element.