Skip to content

Commit d162037

Browse files
authored
[docs] Improve JS header/form instructions (#103)
1 parent 40703b8 commit d162037

File tree

1 file changed

+45
-4
lines changed

1 file changed

+45
-4
lines changed

README.md

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,15 @@ body.
117117
### JavaScript Applications
118118

119119
This approach is useful if you're using a front-end JavaScript framework like
120-
React, Ember or Angular, or are providing a JSON API.
120+
React, Ember or Angular, and are providing a JSON API. Specifically, we need
121+
to provide a way for our front-end fetch/AJAX calls to pass the token on each
122+
fetch (AJAX/XMLHttpRequest) request. We achieve this by:
123+
124+
- Parsing the token from the `<input>` field generated by the
125+
`csrf.TemplateField(r)` helper, or passing it back in a response header.
126+
- Sending this token back on every request
127+
- Ensuring our cookie is attached to the request so that the form/header
128+
value can be compared to the cookie value.
121129

122130
We'll also look at applying selective CSRF protection using
123131
[gorilla/mux's](https://www.gorillatoolkit.org/pkg/mux) sub-routers,
@@ -133,12 +141,13 @@ import (
133141

134142
func main() {
135143
r := mux.NewRouter()
144+
csrfMiddleware := csrf.Protect([]byte("32-byte-long-auth-key"))
136145

137146
api := r.PathPrefix("/api").Subrouter()
147+
api.Use(csrfMiddleware)
138148
api.HandleFunc("/user/{id}", GetUser).Methods("GET")
139149

140-
http.ListenAndServe(":8000",
141-
csrf.Protect([]byte("32-byte-long-auth-key"))(r))
150+
http.ListenAndServe(":8000", r)
142151
}
143152

144153
func GetUser(w http.ResponseWriter, r *http.Request) {
@@ -159,11 +168,39 @@ func GetUser(w http.ResponseWriter, r *http.Request) {
159168
}
160169
```
161170

171+
In our JavaScript application, we should read the token from the response
172+
headers and pass it in a request header for all requests. Here's what that
173+
looks like when using [Axios](https://github.com/axios/axios), a popular
174+
JavaScript HTTP client library:
175+
176+
```js
177+
// You can alternatively parse the response header for the X-CSRF-Token, and
178+
// store that instead, if you followed the steps above to write the token to a
179+
// response header.
180+
let csrfToken = document.getElementsByName("gorilla.csrf.Token")[0].value
181+
182+
// via https://github.com/axios/axios#creating-an-instance
183+
const instance = axios.create({
184+
baseURL: "https://example.com/api/",
185+
timeout: 1000,
186+
headers: { "X-CSRF-Token": csrfToken }
187+
})
188+
189+
// Now, any HTTP request you make will include the csrfToken from the page,
190+
// provided you update the csrfToken variable for each render.
191+
try {
192+
let resp = await instance.post(endpoint, formData)
193+
// Do something with resp
194+
} catch (err) {
195+
// Handle the exception
196+
}
197+
```
198+
162199
### Google App Engine
163200

164201
If you're using [Google App
165202
Engine](https://cloud.google.com/appengine/docs/go/how-requests-are-handled#Go_Requests_and_HTTP),
166-
which doesn't allow you to hook into the default `http.ServeMux` directly,
203+
(first-generation) which doesn't allow you to hook into the default `http.ServeMux` directly,
167204
you can still use gorilla/csrf (and gorilla/mux):
168205

169206
```go
@@ -180,6 +217,10 @@ func init() {
180217
}
181218
```
182219

220+
Note: You can ignore this if you're using the
221+
[second-generation](https://cloud.google.com/appengine/docs/go/) Go runtime
222+
on App Engine (Go 1.11 and above).
223+
183224
### Setting Options
184225

185226
What about providing your own error handler and changing the HTTP header the

0 commit comments

Comments
 (0)