Constant state value in OAuth 2.0 URLGO-S1001
OAuth 2.0 clients must implement CSRF protection for the redirection URI, typically accomplished by including a value that binds the request to the UA's (user-agent) authenticated state. It is recommended to use the "state" request parameter to deliver the value to the authorization server. Go's OAuth 2.0 library allows you to specify a "state" value which is then included in the auth code URL. That state is then provided back by the remote authentication server in the redirect callback, from where it must be validated. If not validated, it makes the client susceptible to a CSRF attack. So it is essential to use a unique, non-guessable "state" value that is also bound to the user's authenticated state with each authentication request and then validated in the redirect callback.
Bad practice
func do(w http.ResponseWriter) {
const state = "state_value" // harcoded & highly predictable
conf := &oauth2.Config{
ClientID: os.Getenv("CLIENT_ID"),
ClientSecret: os.Getenv("CLIENT_SECRET"),
Endpoint: oauth2.Endpoint{
AuthURL: "https://*/oauth2/auth",
TokenURL: "https://*/oauth2/token",
},
}
url := conf.AuthCodeURL(state)
// ...
}
Recommended
func encodeStateOAuthCookie(w http.ResponseWriter) string {
b := make([]byte, 256)
return base64.URLEncoding.EncodeToString(b)
}
func do(w http.ResponseWriter) {
conf := &oauth2.Config{
ClientID: os.Getenv("CLIENT_ID"),
ClientSecret: os.Getenv("CLIENT_SECRET"),
Endpoint: oauth2.Endpoint{
AuthURL: "https://*/oauth2/auth",
TokenURL: "https://*/oauth2/token",
},
}
state := encodeStateOAuthCookie(w) // harder to guess
url := conf.AuthCodeURL(state)
// ...
}