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
).
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