I’m working on a small Hanami 2 app where I want to the users to be able to create there account with various social logins. I’m using omniauth for the integration. For this I have configured Hanami to use sessions. I’ve configured omniauth the way it should work but whenever I am trying to login with the developer strategy I’m getting a OmniAuth::AuthenticityError
.
It appears to me that this happens because Omniauth is expecting a different csrf token than the one I am putting inside my form. I retrieve the csrf value like this:
request.session["csrf"]
(I also tried to access the “_csrf_token” key but this doesn’t help either.
What am I missing? How can I make omniauth pass the csrf test?
Hi, take a look at this thread: Peter Solnica: "@BobbyMcWho hey there, may I have an omniauth que…" - Ruby.social
Folks, I ran into this problem myself and found a workaround.
Two next steps:
- Share the short term solution (once back home)
- Design a solution in the framework (if possible)
Right, so we all stumbled upon the same issue. Like @kukicola wrote, there’s a workaround but my understanding is that what it actually does, is disabling CSRF altogether because setting an empty action as the validation handler just calls it, and it always returns a truthy value soooo, that’s not what we want. I don’t know enough about omniauth itself to propose any solution yet though.
@solnic It’s not disabling it. Hanami Actions have CSRF validations enabled by default: https://github.com/hanami/controller/blob/main/lib/hanami/action/csrf_protection.rb#L95
So it’ll still validate the token but using Hanami implementation (instead of the one from RackProtection). If I modify the token before sending request I can see Hanami::Action::InvalidCSRFTokenError
.
Here’s my working solution:
# config/app.rb
require "omniauth"
require "rack/csrf"
OmniAuth::AuthenticityTokenProtection.default_options(key: "csrf.token", authenticity_param: "_csrf")
module MyApp
class App < Hanami::App
config.actions.sessions = :cookie, {
key: "_my_app.session",
secret: settings.session_secret,
expire_after: 60 * 60 * 24 * 365 # 1 year
}
# ...
end
end
# app/actions/sessions/new.rb
# frozen_string_literal: true
module Hashtag
module Actions
module Sessions
class New < Hashtag::Action
def handle(req, res)
# TODO: shouldn't `request` be exposed by default?
res[:request] = req
end
end
end
end
end
# app/views/sessions/new.rb
# frozen_string_literal: true
require "rack/csrf"
module Hashtag
module Views
module Sessions
class New < Hashtag::View
# TODO: shouldn't `request` be exposed by default?
expose :request
expose :csrf_tag do |request|
Rack::Csrf.tag(request.env)
end
end
end
end
end
# app/templates/sessions/new.html.slim
form action="/auth/developer" method="post"
== csrf_tag
button type="submit" Login with Developer
Thanks, that worked for me too!
As a sidenode: I tried the solution I found in the mastodon thread before the one @jodosha mentioned. This didn’t work + it was more stuff to do anyways…