Devise does not show correct error via login - ruby-on-rails

I'm using devise and devise-token-auth for auth in the backend and 'redux-auth` on the client side.
I'm trying to get devise to send a proper error message to show to a client in case the account is temporarily locked
this is my user.rb file
# devise method to check if user is banned
def active_for_authentication?
super && !self.banned?
end
# message to send in case of ban. doesnt work yet
def inactive_message
self.banned? ? :locked : super
end
def banned?
return self.role == 'banned'
end
my devise.en.yml file
en:
devise:
confirmations:
confirmed: "Your email address has been successfully confirmed."
failure:
locked: "Your account is locked."
errors:
messages:
locked: "Your account has been banned"
I seem to be getting a standard error response from devise when trying to login either with redux-auth or CURL (i cant seem to find the given message anywhere in devise.en.yml file)
curl http://localhost:3000/auth/sign_in -d "email=foo#foo.com&password=123"
the response
{"success":false,"errors":["A confirmation email was sent to your account at 'foo#foo.com'."]}
Where can i customize the message?

The message is in the devise_token_auth yaml file: https://github.com/lynndylanhurley/devise_token_auth/blob/123cfb730ebaf4e2acc124edd39e68816cb0b8cf/config/locales/en.yml
so you need to override it by adding the following to one of your local yaml files:
en:
devise_token_auth:
sessions:
not_confirmed: "Custom message"

Related

Displaying failure messages using Devise gem in Rails

Hello I have a problem with displaying Devise failure messages. No matter what I do, I always get the "invalid" message even though the account is locked. My goal is to display the "locked" message for 10 minutes after 5 failed attempts.
The gem is configured properly because accounts are being locked correctly. The only problem I have is with the messages.
This is my code from the devise.rb file, which is related to the lockable module:
config.paranoid = false
config.lock_strategy = :failed_attempts
config.unlock_keys = [:time]
config.unlock_strategy = :time
config.maximum_attempts = 5
config.unlock_in = 10.minutes
config.last_attempt_warning = true
I found other topics on stackoverflow (e.g. Some devise messages are not shown, Devise: lockable - last_attempt_warning not displaying), where people say it's because of the paranoid mode, that's why I disabled it, but it still doesn't solve my issue. Devise does not seem to display any other message than "invalid" no matter what I put in the Devise config file (last_attempt_warning isn't showing up as well).
This is part of devise.en.yml related to failures:
en:
devise:
failure:
already_authenticated: "You are already logged in."
deactivated: "Your account is no longer active. Please contact your administrator for access."
inactive: "Your account is not activated yet."
invalid: "Sorry, the email or password you entered is incorrect."
last_attempt: "You have one more attempt before your account will be locked."
locked: "Your account has been locked. Try to log in again in 5 minutes."
not_found_in_database: "Sorry, the email or password you entered is incorrect."
timeout: "Your session expired. Please log in again to continue."
unauthenticated: "You need to log in or sign up before continuing."
unconfirmed: "You have to confirm your account before continuing."
I tried to workaround it by creating a method in Sessions Controller:
before_action :check_failed_attempts, only: :create
def check_failed_attempts
flash.clear
email = params["educator"]["email"]
return unless email
user = Person.find_by(email: email)
return unless user
if user.access_locked?
flash[:alert] = I18n.t "devise.failure.locked"
end
end
but devise seems to override the flash[:alert] and displays the invalid message anyway.
I spent a few hours trying to fix it and run out of ideas already, so I appreciate any help.
You are not halting the request cycle in your before_action, so the request is proceeding to call the create action which is overriding the flash[:alert]. From the documentation:
If a "before" filter renders or redirects, the action will not run. If
there are additional filters scheduled to run after that filter, they
are also cancelled.
def check_failed_attempts
flash.clear
email = params["educator"]["email"]
return unless email
user = Person.find_by(email: email)
return unless user
if user.access_locked?
flash[:alert] = I18n.t "devise.failure.locked"
redirect_to new_educator_session_path
end
end

Devise Token Auth confirmation email link expired

I am currently developing a website and i have a problem with te confirmation link with devise token auth.
Everything is working right, after someones registers they get an email with a confirmation link. This link is confirming and working properly BUT when this link expires (i set it up in the configuration with config.confirm_within = 1.day ) or someone clicks this link again they get a "Routing error". So i suppose there should be a way of redirecting to the homepage when that link expires and maybe showing a message saying that they have to ask for the email confirmation again..
i have this confirmation routes:
new_api_user_confirmation GET /api/auth/confirmation/new(.:format) devise_token_auth/confirmations#new
api_user_confirmation GET /api/auth/confirmation(.:format) devise_token_auth/confirmations#show
POST /api/auth/confirmation(.:format) devise_token_auth/confirmations#create
I use the last route POST for resending the email and it is working, but the other to routes are not working and that makes sense because i am using API. But there should be a redirect url for when you get an error
Any thoughts? thank you in advance
you can override the DeviseTokenAuth::ConfirmationsController#show and redirect to root_path
DeviseTokenAuth ConfirmationsController#show
class ConfirmationsController < DeviseTokenAuth::ConfirmationsController
def show
...
else
# raise ActionController::RoutingError, 'Not Found'
redirect_to :root_path
end
...
in routes
mount_devise_token_auth_for 'User', at: 'auth', controllers: {
# confirmations: 'devise_token_auth/confirmations',
confirmations: 'confirmations',
devise-token-auth docs

Customize the validation when user sign in in devise

I have a website that uses Devise for authentication.
While sign in if email and password both are empty it is giving me error
Invalid email or password.
but I want to show different error messages for users for different cases:
For instance,
if email field is empty and the password is present then show
Email can't be blank.
else if password field is empty and email is present than show
Password can't be blank.
else password and email are unauthenticated than show
invalid email or password
which currently working.
I don't want to remove :validatable from my model.
I tired validates :email, :presence => true, :email => true
from here
but when I sign up it shows 2 errors of
Email can't be blank.
one error of Devise and the other for the model.
please tell me how to do this validation only for user sign-in.
Try this in your devise session controller's create action.
def create
user = User.find_by(email: params[:user][:email])
if user
if user.valid_password?(params[:user][:password])
sign_in_and_redirect user
else
flash[:error] = "Please enter the valid password."
end
end
end
Please prefer this
Link
If the user is signing in, you can edit all the error messages in devise.en.yml under config/locales.

Devise Mailer, using custom email template for existing module

I'm using ruby on rails, with devise.
I have a senario wherin an Administrator would be able to add new user to the web application giving his email id and under this senario i'd be creating a new user. and would like to issue an Auth-Token to the user email. so when he clicks the link in his email, he'd be prompted to issue his/her new password.
My forgot password implementation.
def create
resource = User.send_reset_password_instructions(params[:user])
if successfully_sent?(resource)
render json: {status: :true},status: 200
else
render json: {status: :false, error: user.errors.full_messages.join(",") } , status: 200
end
end
Now my question is how do i use the same logic as that of forgot password, but use different Email-template for the user-added by the administrator screen. ?
Thanks a lot.
Why are you redirecting a user to forgot your password page when you can simply redirect him/her to settings page from where a user can change his/her password?
Create a mailer action with its template and simply call that mailer action inside the method where your admin is creating users. e.g:
if your mailer action is:
def forgot_pass(email)
mail(to: email, subject: 'Change your pass')
end
and your method where your admin is creating users is:
def create_user
# your logic
YourMailerClass.forgot_pass(xyz#abc.com).deliver
end
For more details on mailer refer to here

Rails - authenticate_or_request_with_http_basic custom "access denied" message

I'm struggling myself trying to change that default message once you insert invalid credentials as username:password on rails using authenticate_or_request_with_http_basic.
For example if I make a curl request on a method that need this authentication, once I insert the wrong username and password it returns HTTP Basic: Access denied.
So, in this case I would like to be able to customize this message with a specific XML formatted string, (just like twitter API does). Is that possible?
Thanks in advance
If you want to customize the message in the login prompt, just pass the message to the method call.
authenticate_or_request_with_http_basic "My custom message" do |user_name, password|
user_name == USER_NAME && password == PASSWORD
end
If you want to customize the final error message, according to Rails 2.3.4 source code you can do this only for the HTTP Digest authentication.
def authentication_request(controller, realm, message = nil)
message ||= "HTTP Digest: Access denied.\n"
authentication_header(controller, realm)
controller.__send__ :render, :text => message, :status => :unauthorized
end
The Basic Authentication has the error message hard-coded into the method.
def authentication_request(controller, realm)
controller.headers["WWW-Authenticate"] = %(Basic realm="#{realm.gsub(/"/, "")}")
controller.__send__ :render, :text => "HTTP Basic: Access denied.\n", :status => :unauthorized
end

Resources