Aravind Raju
Aravind Raju

Reputation: 61

How to authenticate users using devise in rails middleware?

config/application.rb

config.middleware.insert_before(Rack::Runtime, Rack::ReverseProxy) do
  reverse_proxy_options preserve_host: false
  reverse_proxy '/external/app', 'https://runalong.com:64167/app'
end

I'm using rack-reverse-proxy to forward requests to another server(not rails server) which is running in a different host when a specific url is requested. Now i want to verify whether the user is signed_in using devise and then only serve forward the requests to the proxy server otherwise send the user back to the sign-in page.

Upvotes: 3

Views: 2576

Answers (1)

Pavel Bulanov
Pavel Bulanov

Reputation: 953

Update. On the general consideration, assuming that the target server is publicly available, you should think of authentication strategy, as checking it only on your interim server isn't secure.

Basically, answer to your question will be - Devise does not add any own middleware to Rails application, so you can't use Devise in middleware. You can potentially use Warden middleware.

Devise sits on top of Warden. Devise injects Warden::Manager middleware at the end of middleware stack (it can also inject omniauth middlewares) :

# Initialize Warden and copy its configurations.
config.app_middleware.use Warden::Manager do |config|
  Devise.warden_config = config
end

Other than that, Devise works on Rails application level, i.e. add helpers such as sign_in and similar to controllers. But it doesn't work on middleware level itself.

Warden by itself is "lazy", which is described here

Warden is designed to be lazy. That is, if you don’t use it, it doesn’t do anything, but when you do use it, it will spring into action and provide an underlying mechanism to allow authentication in any Rack-based application.

So unless Devise will somehow manipulate with Warden, Warden doesn't do much. What Warden does, is embedding itself into env variable accessable by other middleware (and Rails application as well). Devise use this instance.

env['warden'] = Proxy.new(env, self)

Warden also listens to special warden exceptions which other middlewares (or in the end rails application) can throw:

 result = catch(:warden) do
   @app.call(env)
 end

In order to use Warden in middleware, you would need to embed in middleware earlier (before your target middleware). Then you would be able to use Warden (and not Devise helpers!).

Per comments in warden source, it should be embedded after (no earlier then) session-building middleware, e.g. ActionDispatch::Session::CookieStore:

The middleware for Rack Authentication The middleware requires that there is a session upstream The middleware injects an authentication object into the rack environment hash

Warden accessor for session:

def session
  env["rack.session"] || {}
end

Upvotes: 6

Related Questions