3

I'm trying to use my existing auth system to protect the /sidekiq route. I'm using JWT with Rails-api. I'm able to read the JWT token to check if the user has an admin role but it only works on the initial request. Subsequent requests in the Sidekiq panel retrieve CSS and JS but they fail because the token is not passed along to them.

I have the following route in my routes.rb:

mount Sidekiq::Web => '/sidekiq', constraints: AdminConstraint.new

Then lib/admin_constraint.rb:

class AdminConstraint
  def matches?(request)
    token = request.params['token']
    unless token
      puts 'AdminConstraint: No token in params found'
      return false;
    end

    user = Knock::AuthToken.new(token: token).entity_for(User)
    unless user
      puts "AdminConstraint: No user found for token #{token}"
    end

    if user.admin?
      puts "AdminConstraint: User with user_id #{user.id} is an admin, access granted"
      true
    else
      puts "AdminConstraint: User with user_id #{user.id} is NOT an admin, rejecting"
      false
    end
  end
end

I'm accessing the route in my browser like so: https://example.com/sidekiq?token=<token>

Is there some way I can persist the token for subsequent requests? I can't seem to use Rails session in this lib file.

Maros
  • 1,825
  • 4
  • 25
  • 56

1 Answers1

1

Is there some way I can persist the token for subsequent requests?

This can't/shouldn't be done within a constraint in your routes.

You'll need to provide another endpoint, which sets something in the session to show that the session has been authenticated, which you'd then check within your routing constraint.

This could be done in a controller, or a rack middleware perhaps.

Daniel Westendorf
  • 3,375
  • 18
  • 23
  • How would I interact with that endpoint? A PUT/POST request? Ideally, as a user I want to just be able to go to /sidekiq on the client side and see the dashboard if I'm an authenticated admin user. The trouble is Sidekiq owns the controllers/views etc and wants to serve html. In other words, it doesn't seem to be designed to work with a single page app + rails API – Maros Dec 12 '17 at 19:29
  • Ideally, you'd PUT/POST your token to that endpoint, and either redirect to /sidekiq from there or handle that appropriately clientside after a successful response. A GET would also work with your token as param, but likely be less rails-y. – Daniel Westendorf Dec 12 '17 at 20:54
  • Gotcha. I think I'll add some hidden action to the window like `window.authToSidekiq()` which will POST to the endpoint, save the token in session then a 302 redirect will take me to /sidekiq. – Maros Dec 12 '17 at 23:36
  • I tried this idea but it seems like the initial problem is still there. Even if I set the token into session in my custom controller, the routing constraint still doesn't have access to session to read the token. – Maros Dec 13 '17 at 02:36
  • You should be able to access the session within your constraint. Something like this: https://www.mobomo.com/2011/02/use-lambdas-for-rails3-route-constraints/ – Daniel Westendorf Dec 13 '17 at 03:08
  • `request.session` seems to be empty in the constraint after setting `session[:token] = token` in my auth controller. Is it possible that these two sessions are different things? – Maros Dec 13 '17 at 03:16
  • There are a lot of possibilities as to what could be going wrong there. It should work, however, if your sessions are set up correctly. – Daniel Westendorf Dec 13 '17 at 03:30
  • Hmm, `request.cookies` does have a `rack.session` cookie but it seems to be a long encrypted value. – Maros Dec 13 '17 at 03:41
  • I got it working. I had to re-add the sessions layer since I'm using rails-api. Like this: https://stackoverflow.com/a/37140228/659910. Can you add that detail to your answer and I'll accept it? – Maros Dec 13 '17 at 03:46