I have a Rails 4.1 Application running with Devise for authentication.
For access via mobile apps i would like to implement token auth with the recommended devise_token_auth gem. I do not use Omniauth
The functionality of the existing app should not be altered.
What i did:
Installed devise_token_auth via gemfile.
Used the generator: rails g devise_token_auth:install User auth
Changed the migration to add the required fields.
Migration failed due missing of Omniauth. So i also installed it.
Changed routes.rb
devise_for :users, :skip => [:sessions, :registrations, :omniauth_callbacks]
as :user do
get 'register' => 'users/registrations#new', :as => :new_user_registration
post 'register' => 'users/registrations#create', :as => :user_registration
get 'sign_in' => 'devise/sessions#new', :as => :new_user_session
post 'sign_in' => 'devise/sessions#create', :as => :user_session
delete '/' => 'users/sessions#destroy', :as => :destroy_user_session
end
added:
namespace :api do
scope :v1 do
mount_devise_token_auth_for 'User', at: 'auth', skip: [:omniauth_callbacks]
end
end
In User Model i have:
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:confirmable, :timeoutable, :lockable
include DeviseTokenAuth::Concerns::User
Now when i try to sign_up a new user it gives me the validation error:
Uid can't be blank
Does someone had the same problem and resolved it?
What i find strange is that it needs to have Omniauth installed.
Update:
I overwrite the Devise registration controller create action:
build_resource(sign_up_params)
resource.uid = resource.email
resource.provider = ''
Now when i sign_in i get:
{"errors":["Authorized users only."]}
in Browser.
Adding the following to app/models/user.rb:
before_validation do
self.uid = email if uid.blank?
end
did it for me. Also make sure the provider is set to "email" for "provider".
Well I'm currently struggling with the same thing. Trying to add devise_token_auth to Devise, and it is not working so far for me.
As far as this goes, are you talking about "sign_up" for Devise, or devise_token_auth? If it is for Devise, I supposed setting uid=email before creating the record would solve this.
This error is raised by devise_token_auth, not by devise. So essentially, devise_token_auth is trying to authenticate your normal devise routes the same way it would normally authenticate an api request. Your normal devise routes are authenticating via session, not via token, so you'll get this error:
{"errors":["Authorized users only."]}
There are a couple of things that could be happening here. First, make sure that you're only looking for token validation on the actions of your API controllers. So make sure that this line is included in your BaseAPIController, and not in your ApplicationController.
include DeviseTokenAuth::Concerns::SetUserByToken
The other possibility is that you have some namespacing issues in your routes.rb. Make sure that you have something like this. You need to have devise_for first, and the token_auth properly namespaced or it will cause validations issues on your other routes.
Rails.application.routes.draw do
devise_for :admins
namespace :api do
scope :v1 do
mount_devise_token_auth_for 'user', at: 'auth'
end
end
end
Good luck!
Related
i've seen a bunch of posts on how to rename already-declared routes in devise. I want to expand devise to have my own route check for and idle session. I am implementing a simple js check every 1 minute that I want to hit 'check_active' in the devise sessions controller. I tried this but no luck:
devise_scope :sessions do
get 'check_active'
end
Is there way to expand devise with a custom route (not rename an already-existing one) ?
UPDATE - almost there, i did this
# already had this in routes
devise_for :users, :controllers =>
{ registrations: 'registrations',
confirmations: 'confirmations',
sessions: 'sessions',
passwords: 'passwords',
omniauth_callbacks: "omniauth_callbacks"}
# added this
devise_scope :sessions do
get '/check_active' => 'sessions#check_active'
end
I have a js firing, i have it get '/check_active' as rake routes shows this:
check_active GET /check_active(.:format)
But when it fires, the controller 404s with
AbstractController::ActionNotFound (Could not find devise mapping for path "/check_active".
This may happen for two reasons:
1) You forgot to wrap your route inside the scope block. For example:
devise_scope :user do
get "/some/route" => "some_devise_controller"
end
2) You are testing a Devise controller bypassing the router.
If so, you can explicitly tell Devise which mapping to use:
#request.env["devise.mapping"] = Devise.mappings[:user]
):
If you are overwriting Devise's default controllers, it is not any different from any other controller to add your own route.
After you create your devise controllers to overwrite, do the following:
Under sessions_controller declare a method
# app/controllers/devise/sessions_controller.rb
def check_active
# do what you want to do
end
And in your router:
# config/routes.rb
devise_scope :sessions do
get 'check_active', to: "devise/sessions#check_active"
end
I was trying the same thing and realized that the scope should be for user and not sessions, also ensure that it has to be singular.
devise_scope :user do
get '/check_active' => 'sessions#check_active'
end
Edit: Adding link to help docs for better understanding
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
I'm overriding the default Devise signin method as such:
def after_sign_in_path_for(resource)
stored_location_for(resource) || jobs_path
end
So that when an authenticated users signs in, they are taken to my jobs page. Which is fine,
but the problem I'm having is that I'd like to be able to utilize the Devise password (new/edit) pages, typically found at /users/password/new and /users/password/edit but when I attempt to go to those locations (http://localhost:3000/users/password/new), I get immediately redirected back to jobs page. What do I need to do to correct this. Below is part of my routes.rb if that helps:
devise_for :users, :skip => [:sessions] do
# devise/sessions
get 'signin' => 'devise/sessions#new', :as => :new_user_session
post 'signin' => 'devise/sessions#create', :as => :user_session
get 'signout' => 'devise/sessions#destroy', :as => :destroy_user_session
end
resources :users
Thanks in advance for your time and assistance.
The devise wiki says that users can edit their password using the registerable module:
https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-edit-their-password
Have you tried just using devises methods for letting users change their password?
Also, here is a related question:
Rendering the Devise edit Password Form
I am working with OmniAuth to use Facebook Connect in my Devise based rails app. One of the routes it creates is:
user_omniauth_callback /users/auth/:action/callback(.:format) {:action=>/facebook/, :controller=>"devise/omniauth_callbacks"}
I'd like to modify this route to a custom URL. Where would be the right place to do that?
the problem is by default, the route it creates is http://foo/users/auth/:action/callback.format. I want to have something more custom like http://foo/prefix_path/users/auth/:action/callback.format. I tried making my routes file look like the following:
scope "/mypath" do
devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks" }
end
but it still generates the wrong route:
user_omniauth_callback /users/auth/:action/callback(.:format) {:action=>/facebook/, :controller=>"users/omniauth_callbacks"}
I'm not exactly sure what you are asking, I assume you want to have your own custom code for the callback.
You can extend the devise controller such as:
class MyOmniauthCallbacksController < Devise::OmniauthCallbacksController
def facebook
#Custom Code here
end
end
Then you can register this new controller in your routes.rb
devise_for :users, :controllers => {:omniauth_callbacks => "my_omniauth_callbacks"}
EDIT:
devise can also take a 'path' option in the devise_for so changing the route:
devise_for :users, :controllers => {:omniauth_callbacks => "my_omniauth_callbacks"}, :path => "path_prefix/users"
If you are unsatisfied with omniauthable in devise itself, then you may consider implementing omniauth as separate gem and then just tie it with device.
To modify routes, you may use :match as well and map those routes to omniauth_callbacks url. Didn't get why you want to
I'd like to modify this route to a custom URL.
Decribe what you want to make different that what is available.
I am using Devise for authenticating a Rails application. I am now able to successfully route /users/sign_in and /users/sign_out to /sign_in and /sign_out via this code in routes.rb:
devise_for :user, :as => ''
How do I map /registration/sign_up to /sign_up?
So that sign_in, sign_out, and sign_up all have the same pattern.
Note that I am using Devise only for users. No admins.
You need to add the following block to your routes.rb file:
devise_scope :user do
get "/sign_up" => "devise/registrations#new"
end
It's explained in: http://github.com/plataformatec/devise/wiki/How-To:-Change-the-default-sign_in-and-sign_out-routes