I have 3 different devise models. Two using email & password for login and works great. But For the third one I need to use mobile & OTP based login instead of email & password. So the devise session controller only receives mobile & the otp as params.
I have changed from email to mobile by using authentication_keys
class Customer < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable, authentication_keys: [:mobile]
def email_required?
false
end
end
I am using devise-jwt for jwt response & overriding sessions_controller like this
class Api::Customers::V1::Auth::SessionsController < Devise::SessionsController
def create
super { #token = current_token }
end
private
def current_token
request.env['warden-jwt_auth.token']
end
end
But now am getting password blank validation error. How can I disable password validation & change to do an otp verification instead?
PS: I have seen several resources on two factor auth . But they all work with password validation.
Related
I hope you are good. I try to implement google authentication to my rails API. I get error
ActiveRecord::RecordInvalid (Validation failed: Email is invalid)
My user.rb:
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable,
:confirmable, :trackable,
:omniauthable, omniauth_providers: [:google_oauth2]
def self.create_user_for_google(data)
where(uid: data['email']).first_or_initialize.tap do |user|
user.provider = 'google_oauth2'
user.uid = data['email']
user.email = data['email']
user.password = Devise.friendly_token[0, 20]
user.password_confirmation = user.password
user.save!
end
end
end
and my users_controller.rb looks:
class UsersController < ApplicationController
def google_oauth2
url = "https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=#{params['id_token']}"
response = HTTParty.get(url, format: :plain)
user = User.create_user_for_google(response.parsed_response)
render json: user
end
end
My guess is there's no email in response.parsed_response
You're not supposed to make the request from your backend the way you do:
HTTParty.get "https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=#{params['id_token']}"
You're supposed to redirect user's browser to user_google_oauth2_omniauth_authorize_url (I think this URL helper comes from devise in routes.rb (look for devise_for:)
Then your user's browser shows the Google log in page (or, if user was already logged in, next step) then (still google) asks for their consent to share data, and only after receiving this consent google would redirect your user back to your app to an address that is called a callback (it looks like omniauth_callbacks: "users/omniauth_callbacks")
And only in the controller/action that handles this callback, you'll see an email and a token you can save with your user and use it to signing in with google's oAuth protocol.
Don't worry, oAuth is confusing when you do it for the first time.
One of the clearest step-by-step example how to implement omni auth I could find is here: https://www.digitalocean.com/community/tutorials/how-to-configure-devise-and-omniauth-for-your-rails-application
When I create a new record and send password reset email. The link of that gives me this error
reset password token is invalid devise rails
My model is
class Advertiser < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
after_create { |admin| admin.send_reset_password_instructions }
def password_required?
new_record? ? false : super
end
end
Basically I create new advertiser from activeadmin without giving password. Only in this scenario that issue came.Otherwise it works fine.
Link genereate is like that
http://localhost:3000/admin/password/edit?reset_password_token=fDxVmCNjKNDiUseWGLe6
BUt it gives error like that
Reset password token is invalid
See this solution.
Rails 4 + Devise: Password Reset is always giving a "Token is invalid" error on the production server, but works fine locally.
Check and see if your token in the DB is the same as the one in the email. Devise is using hashes for tokens and you might be getting the hashed version.
I am trying to configure token generation with devise in a grape api rails app. Since I have the current version of devise, token generation has been disabled. I am having several issues. First, is that when I submit a username and password to the sessions controller, it gives me an error that "ensure_authentication_token":
undefined method `ensure_authentication_token!' for #<User:0x007f880cca9090>
This is so strange because as you can see below, I have it defined in my user model and when I manually create Users in rails console, it works properly.
Is that a scope issue or why is that occurring?
User Model:
class User < ActiveRecord::Base
before_save :ensure_authentication_token
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
def ensure_authentication_token
if authentication_token.blank?
self.authentication_token = generate_authentication_token
end
end
private
def generate_authentication_token
loop do
token = Devise.friendly_token
break token unless User.where(authentication_token: token).first
end
end
end
Sessions Grape API Controller:
module API
module V1
class Sessions < Grape::API
include API::V1::Defaults
resource :sessions do
params do
requires :email, type: String, desc: "Email"
requires :password, type: String, desc: "Password"
end
post do
email = params[:email]
password = params[:password]
if email.nil? or password.nil?
error!({error_code: 404, error_message: "Invalid Email or Password."},401)
return
end
user = User.where(email: email.downcase).first
if user.nil?
error!({error_code: 404, error_message: "Invalid Email or Password."},401)
return
end
if !user.valid_password?(password)
error!({error_code: 404, error_message: "Invalid Email or Password."},401)
return
else
user.ensure_authentication_token!
user.save
{status: 'ok', token: user.authentication_token}.to_json
end
end
end
end
end
end
The second problem is that when I follow this blog, it says that I need to add the following authentication check in my defaults.rb in the base api controller. When I add the "before do" section, I get access denied error even if I enter in the right credentials and it doesn't even go on to the rest of the sessions controller that I mentioned above.
before do
error!("401 Unauthorized, 401") unless authenticated
end
helpers do
def warden
env['warden']
end
def authenticated
return true if warden.authenticated?
params[:access_token] && #user = User.find_by_authentication_token(params[:access_token])
end
def current_user
warden.user || #user
end
end
Thanks for any help you can give!
EDIT: Phillip was absolutely correct that one of these issues was due to the bang versus non banged version of ensure_authentication_token. Removing the ! from the controller fixed that issue. The other problem was indeed from adding the "before do" loop I had.
This is so close to working, I can give and receive tokens in my api but when it connects to ember, it complains about a lack of a csrf token even though I have "protect_from_forgery with: :null_session" set in my application.rb
In your User model, you define a method called ensure_authentication_token.
In your Session controller, you call a method called ensure_authentication_token!.
These are not the same method: Why are exclamation marks used in Ruby methods?
This is preventing you from generating an authentication token, which probably explains the "401 Unauthorized, 401" error.
I want to configure devise to send a confirmation email when the user has changed their password as a security measure. I'd prefer to re-use my devise mailers if possible. Any ideas how to do this?
Untested, but I'd try to do this within your User model with a simple after_update callback:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable, :recoverable # whatever
after_update :send_password_changed_notification
# attr_accessible, validations, ...
private
def send_password_changed_notification
# Send email with the mailer of your choice,
# e. g. your existing custom Devise mailer:
YourDeviseMailer.password_changed_notification(self).deliver if password_changed?
end
end
I would configure the update user action, you can read on how to do that in their documentation. Check how devise handles confirmations of new registered users in registration action and re-use that code in your new reset password action.
Recently I added the confirmable module to my User class. I already have a quite nice mailing system (Sidekiq, Sendgrid...) in my app, so I created my own "confirm account" mail. The problem now is to disable Devise from sending its default email. Is there any way to completely disable the Devise mailing system?
Added:
I want to maintain the confirmable module, as I am using its attributes and routes.
I can't use skip_confirmation! because I want the users to confirm their account.
I just want to disable Devise mails.
Use the source, Luke:
# lib/devise/models/confirmable.rb
# A callback method used to deliver confirmation
# instructions on creation. This can be overriden
# in models to map to a nice sign up e-mail.
def send_on_create_confirmation_instructions
send_devise_notification(:confirmation_instructions)
end
So override this method in your model to do nothing.
Try overriding the following devise method in your model:
def confirmation_required?
!confirmed?
end
or use skip_confirmation!:
user = User.new(params)
user.skip_confirmation!
user.save!
Use skip_confirmation! method before saving any object.
def create
#user = User.new(params[:user])
#user.skip_confirmation!
#user.save!
end
I think just removing
:confirmable
from the user model should do it
or have you tried disabling
config/environments/development.rb
config.action_mailer.default_url_options = { :host => 'localhost:3000' }
I recommend you
User.skip_reconfirmation!
That is skip confirm mail and update email not to use "confirm!"
remove (:confirmable) from devise model
ex:- here my devise model is User
here I used like this.
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,:omniauthable
end