Namespaced Authentication Routes

Hello everyone,

The devise_for method appeared in a DocsDoctor email the other day and it made me curious about authentication and name-spacing. What sort of scenarios would warrant you to namespace your authentication routes?

  • Is it actually possible to have two or more separate authentication routes inside of one app?
  • In what situations does it actually make sense to do so?
  • What are the basic advantages and disadvantages?

On the surface it simply seems like duplication to me, or maybe it’s only useful for highly customized auth strategies?

Thank you for your time,
Chad

“Includes devise_for method for routes. This method is responsible to generate all needed routes for devise, based on what modules you have defined in your model.”
|
Routes integration
|
devise_for is meant to play nicely with other routes methods. For example, by calling devise_for inside a namespace, it automatically nests your devise controllers:
|
namespace :publisher do
devise_for :account
end
|
The snippet above will use publisher/sessions controller instead of devise/sessions controller. You can revert this change or configure it directly by passing the :module option described below to devise_for.
|
Also note that when you use a namespace it will affect all the helpers and methods for controllers and views. For example, using the above setup you’ll end with following methods: current_publisher_account, authenticate_publisher_account!, publisher_account_signed_in, etc.

http://www.rubydoc.info/github/plataformatec/devise/master/ActionDispatch/Routing/Mapper%3Adevise_for

I recently did this very thing; I have an application I wrote, which is really just an API for our mobile app @ work. But, when designed, I designed it as “One App To Rule Them All”, meaning everything needed is within one application… So, consider the following routes:

Rails.application.routes.draw do
  constraints subdomain: 'admin' do
    namespace :admin, path; '/' do
    end
  end

  constraints subdoman: 'api' do
    namespace :api, path: '/' do
    end
  end

  constraints subdomain: 'partners' do
    namespace :partners, path: '/' do
    end
  end

  // front-end website routes
end

Now, I could have done all this with a single authentication route and could have merged admin and partners together, but opted against it because reasons. Since each ‘area’ has different requirements and needs to be logged in, it made sense to separate them, so what how did i do it?

Rails.application.routes.draw do
  devise_for :users
  constraints subdomain: 'admin' do
    namespace :admin, path; '/' do
      devise_for :users
    end
  end

  constraints subdoman: 'api' do
    namespace :api, path: '/' do
      # actual implementation is slightly different than this
      # I set the specific controllers, as while these inherit from devise
      # They do everything the same, except for save the login session.
      namespace :v1 do
        devise_for :users, :controllers => { :registrations => 'registrations', :sessions => 'sessions', :passwords => 'passwords' }
      end
    end
  end

  constraints subdomain: 'partners' do
    namespace :partners, path: '/' do
      devise_for :users
    end
  end

  # front end website routes
end

The end result gave me a mechanism to authenticate differently for each use-case. One downside, is for the namespaced route, lets say admin for simplicity, instead of being current_user becomes 'admin_current_user`, but aside from that, all functionality is there.

Hey Justin, thanks a bunch for your reply!

I’m still not sure that I understand the benefit of namespacing your auth routes.

Is it just useful for cases when you will have very different and custom authentication strategies?

Are there many differences between the authentication strategies in your various namespaces?

Does this strategy allow you to more easily balance your authentication request loads through multiple channels so that they are easier to control and less likely to lead to a bottle neck?

Thanks,
Chad

It doesn’t necessarily help the potential bottle neck issues that might arise, though it doesn’t really add to it either.

For me the most notable benefit is that it gives me fine grained controls, that otherwise wouldn’t be as easy to do, for dictating what it means to be authenticated in each portion of the site. So, i’m logged in as a partner, that doesn’t mean i’m also logged into the admin, the api or the front-end.

For my authentication strategies they go as follows:
API: - normal authentication via the login route, then every other route not associated with devise is a custom api token authenticator.

ADMIN: A user must be user.admin? and from there, be part of specific teams in order to view anything.

PARTNERS: A user that is associated with a specific partner company, that has been given access to the partner panel via user.partner? and associates it with a specific company

Then the front-end is really just anyone can sign in to use that.

Thanks again Justin, that’s helpful for some further clarity.

It sounds like you’ve got a pretty clean and well-designed app in regards to separation of concerns.

If you know of any examples in public repos or would be willing to share a few files via a private gist then it would be greatly appreciated. In your case, I think that the Partners model and authorization/sessions management files would be most interesting.

If not, that’s ok too.

I’ll put something together for you; May take me a little bit, but i’ll get it for you within the next day or so. But i’ll build a small replica application that contains the authentication parts to our private one and put it up public for you.