Problem Outline
We have a Rails app that uses Google OAuth for login/authentication. We're trying to update omniauth to ~> 2 because that fixes security advisory CVE-2015-9284. We've followed the instructions for the upgrade on the omniauth github pages but now having trouble with CSRF token authentication errors. We aren't using a 'Login' button to redirect users to the auth endpoint and instead we redirect to this endpoint in the controller as soon as an unauthenticated user lands on our app. Here are the logs showing the login process and the error (with some values redacted):
heroku[router]: at=info method=GET path="/" host=example/request_id=123fwd="34.240.54.231" dyno=web.1 connect=0ms service=8ms status=200 bytes=1418 protocol=https
app[web.1]: D, DEBUG -- omniauth: (google_oauth2) Request phase initiated.
app[web.1]: W, WARN -- omniauth: Attack prevented by OmniAuth::AuthenticityTokenProtection
app[web.1]: E, ERROR -- omniauth: (google_oauth2) Authentication failure! authenticity_error: OmniAuth::AuthenticityError, Forbidden
heroku[router]: at=info method=POST path="/auth/google_oauth2" host=example.com request_id=123 fwd="1.2.3.4" dyno=web.1 connect=0ms service=6ms status=302 bytes=704 protocol=https
heroku[router]: at=info method=GET path="/auth/failure?message=authenticity_error&strategy=google_oauth2" host=example.com request_id=123 fwd="1.2.3.4" dyno=web.1 connect=0ms service=6ms status=404 bytes=896 protocol=https
For completeness, we don't define a /auth/failure route in our app so this GET by the google oauth code goes to a 404. But my understanding is that not defining a route here won't impact the CSRF problem we're seeing
Further Explanation
I think these are the relevant libraries and versions we're using:
rails (6.1.6.1)
repost (0.4.1)
oauth2 (2.0.9)
omniauth (2.1.1)
omniauth-google-oauth2 (1.1.1)
omniauth-oauth2 (1.8.0)
omniauth-rails_csrf_protection (1.0.1)
This is our authenticate function. We don't have a 'log in' button and instead use the repost gem library to redirect to POST /auth/google_oauth2 and pass an authenticity token. The redirect_post function in the code below is from the repost library.
# Authenticate against Google OAuth
def authenticate
return if session[:email] || request.path =~ /google_oauth2/ || Rails.env.test?
return if Rails.env.development?
puts "Session authenticity_token: #{session[:_csrf_token]}"
puts "form_authenticity_token: #{form_authenticity_token}"
redirect_post('/auth/google_oauth2', params: { authenticity_token: form_authenticity_token })
end
As can be seen in the snippet above, I've printed out the values for both session[:_csrf_token] and form_authenticity_token to compare. The output of that is:
app[web.1]: Session authenticity_token: hmSkGXBPM1lvsIApuu6rzEgwFnKco8dg+XyqK6uglU8=
app[web.1]: form_authenticity_token: 3EqoUKrNNRvY4zPIZ0fTjiIoFLvAofaSDmDzDy14hozh8DoXzyFXJATrWL0SLH/YDC3LQNKerPx6iKxJ3lYwSA==
They are different values and appear to be different lengths, leading me to believe there's something not connected right in the middleware. But I'm very new to Rails and my debugging power is reaching maximum :).