Search code examples
ruby-on-railsdevisedevise-token-auth

Devise reset password email points to the wrong controller


I included devise_token_auth to login from a webapp hosted elsewhere. But I'd like also to be able to sign in directly into my rails app.

My routes.rb looks like this:

#...
devise_for :users

namespace :api, defaults: {format: :json} do
  mount_devise_token_auth_for 'User', at: 'auth'
  #...

To reset the password the webapp sends a POST to /api/auth/password. With the configuration above, the link in the email to reset the password uses the wrong controller (the one on users/password). The redirect_url doesn't get applied and the user sees the login form of the rails app, not the webapp:

http://localhost:3000/users/password/edit?redirect_url=http://localhost:8080/reset_password&reset_password_token=...

If I comment the line devise_for :users the email link is correct, using api/auth/password/edit:

http://localhost:3000/api/auth/password/edit?redirect_url=http://localhost:8080/reset_password&reset_password_token=...

But of course, by commenting devise_for :users I can't login using just the rails app (on http://localhost:3000/users/sign_in).


Solution

  • Devise, on its mailer template to reset the password (reset_password_instructions.html.erb) calls onto the model to get the url:

    <p><%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token) %></p>
    

    Although the controller that initially handled the client intent to reset the password was DeviseTokenAuth::PasswordsController, the function edit_password_url on User resolves to a path to be handled by Devise::PasswordsController (users/password/edit vs api/auth/password/edit).

    The solution in this case was to use a different model:

    routes.rb

    #...
    devise_for :users
    
    namespace :api, defaults: {format: :json} do
      mount_devise_token_auth_for 'Api::User', at: 'auth'
      #...
    

    api/user.rb

    class Api::User < ActiveRecord::Base
       devise :database_authenticatable, :recoverable,
         :rememberable, :trackable, :validatable
       include DeviseTokenAuth::Concerns::User
       #...
    end