I'm building an app using Devise.
The problem I have is about the password reset process.
If the user forgets their password, enter the registered email address and send a password reset notice to that address.
So far it works as expected.
problem
The password reset token received in the email does not match the password reset token generated by the application.
So, when I try to reset the password from the email I received, I get the error "Token is invalid".
=========================
Show my code.
Gemfile
gem 'devise'
gem 'omniauth'
gem 'omniauth-google-oauth2'
gem 'omniauth-facebook'
gem 'devise-i18n'
routes.rb
devise_for :users, controllers: {
registrations: 'users/registrations',
sessions: 'users/sessions',
confirmations: 'users/confirmations',
omniauth_callbacks: 'users/omniauth_callbacks'
}
model/user.rb
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable, :confirmable,
:omniauthable, omniauth_providers: %i[google_oauth2]
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.email = auth.info.email
user.password = Devise.friendly_token[0,20]
user.skip_confirmation!
end
end
def update_without_current_password(params, *options)
params.delete(:current_password)
if params[:password].blank? && params[:password_confirmation].blank?
params.delete(:password)
params.delete(:password_confirmation)
end
result = update_attributes(params, *options)
clean_up_passwords
result
end
views/users/mailer/reset_password_instructions.html.erb
<%= link_to 'パスワードの変更を行う', edit_password_url(#resource,reset_password_token: #token) %>
=========================================
I searched many times, but I couldn't find much new information because it was only old information.
Why don't the tokens match?
How can I email the generated tokens?
Please help someone.
※I'm not good at English. There may be mistakes.
You have to create a new table for reset tokens.
schema can be like
password_reset_tokens
---------------------
id pk
reset_token unique string
user_id integer
is_active boolean
created_at datetime
updated_at datetime
whenever a user is going to request for a change password. Create an entry in this password_reset_tokens with a random reset_token string and assign a user_id to it.
send this token in the email with a link and when user is going to click on it the reset token. Open the form with new password fields and when password is updated through that link then mark is_active as false.
Additional step:
You can also write a cron to expire the reset_tokens after x hours. whenever a new reset_passsword_token is generated then you can schedule a cron to expire it after x hours.
Related
I am using RoR 5.2, devise and omniauth-trello gem.
I can't sign in with Trello.
I need to create ability to sign in without existing user with returned provider and uid: it should create user if it doesn't exist.
I have already added in config/routes.rb:
devise_for :users, controllers: { omniauth_callbacks: 'omniauth_callbacks' }
config/initializers/devise.rb:
config.omniauth :trello, "#{Rails.application.credentials.trello[:key]}", "#{Rails.application.credentials.trello[:secret]}"
config/initializers/omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
provider :trello, Rails.application.credentials.trello[:key], Rails.application.credentials.trello[:secret],
app_name: "Trello-Rooney", scope: 'read,write,account', expiration: 'never'
end
app/controllers/omniauth_callbacks_controller.rb
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
def trello
#user = User.from_omniauth(request.env['omniauth.auth'])
if #user.persisted?
sign_in_and_redirect #user, event: :authentication
set_flash_message(:notice, :success, kind: 'Trello') if is_navigational_format?
end
end
end
app/models/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, :omniauthable, omniauth_providers: %i[trello]
def self.from_omniauth(auth)
user = User.where(provider: auth.provider, uid: auth.uid.to_s).first
return user if user
email = auth.info[:email]
while email.nil?
generated_email = "#{SecureRandom.base58(10)}#roonyx.trello"
if User.where(email: generated_email).blank?
email = generated_email
end
end
user = User.where(email: email).first
if user
user.update(provider: auth.provider, uid: auth.uid)
else
password = Devise.friendly_token[0, 12]
user = User.create!(email: email, password: password, password_confirmation: password, provider: auth.provider, uid: auth.uid)
end
user
end
end
But when I am trying to sign in with Trello, I see this in console. Looks like it doesn't cause my callback. Can anyone help? Thank you in advance.
E, [2019-05-13T14:10:29.647241 #19958] ERROR -- omniauth: (trello) Authentication failure! service_unavailable: Net::HTTPFatalError, 500 "Internal Server Error"
[2019-05-13 14:10:29] (pida=19958) INFO -- : Processing by OmniauthCallbacksController#failure as HTML
[2019-05-13 14:10:29] (pida=19958) INFO -- : Parameters: {"oauth_token"=>"47215df2b25b4fc089953da32acf0730", "oauth_verifier"=>"8a0b310f2afe98d0aebbd2073efc5b54"}
[2019-05-13 14:10:29] (pida=19958) INFO -- : Redirected to http://localhost:3000/users/sign_in
[2019-05-13 14:10:29] (pida=19958) INFO -- : Completed 302 Found in 1ms (ActiveRecord: 0.0ms)
The error is right there in your log:
Authentication failure! service_unavailable: Net::HTTPFatalError, 500 "Internal Server Error"
Your callback isn't being hit because you've inserted the OmniAuth::Builder middleware. You could try removing that and inspecting the params that are sent along with the callback.
Once you're removed the middleware you can drop a byebug or a binding.pry at the top of your callback action. Once you're in the debugger check the value of request.env['omniauth.auth']. That should give you some insight as to what the problem is. Hard to say more without knowing more about the environment.
I used the Devise gem to set up a User model for my app. I'm trying to work in Facebook authentication using Omniauth. I can retrieve the Name and Email data, but I'm having trouble getting any other public_profile data. In this example I'm trying to get Gender, but none of the other data works either. When I visit this path: user_omniauth_authorize_path(:facebook), the "facebook" action in "controllers/registrations_controller.rb" is called. But for the user that is created, user.gender, and all other data other than name and email, comes back nil.
config/initializers/devise.rb
config.omniauth :facebook, "<ID>", "<SECRET>", scope: 'email', display: 'popup', info_fields: 'email,name,gender'
app/models/devise.rb
devise :omniauthable, :omniauth_providers => [:facebook]
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.gender = auth.extra.raw_info.gender.to_s
end
end
app/controllers/registrations_controller.rb
def facebook
#user = User.from_omniauth(request.env["omniauth.auth"])
if #user.persisted?
sign_in_and_redirect #user, :event => :authentication
set_flash_message(:notice, :success, :kind => "Facebook") if is_navigational_format?
else
session["devise.facebook_data"] = request.env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
gemfile
gem 'devise'
gem 'omniauth-facebook'
What's strange is I can't even get the class type of the data. Name and Email return "String" if I call class.to_s on them, but all the other data returns "NilClass".
What am I doing wrong?
UPDATE:
Okay I literally have no idea what could have possibly changed, but this same exact code now suddenly works....so problem solved I guess?
Try This way
def self.from_omniauth(access_token)
data = access_token.info
email = data.info.email
first_name = data.first_name
last_name = data.last_name
end
You can gender attribute using auth.info.gender
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.gender = auth.info.gender
end
You sure the user has these data as public info?
I would try to debug the permissions in Facebook's open graph explorer
https://developers.facebook.com/tools/explorer/
That will help you understand wether it is permissions, lacking data issue or a problem with the integration.
I'm trying to do OmniAuth in rails 4 for spotify. I almost have it but for some reason, the redirect URI isn't working. I am using Devise with omniauth These are my files:
User.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:omniauthable, :omniauth_providers => [:spotify]
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.provider = auth.provider
user.uid = auth.uid
user.email = auth.info.email
user.password = Devise.friendly_token[0,20]
end
end
end
My Callbacks controller to handle callbacks
class CallbacksController < Devise::OmniauthCallbacksController
def spotify
#user = User.from_omniauth(request.env["omniauth.auth"])
sign_in_and_redirect #user
end
end
My Devise.rb snippet:
config.omniauth :spotify, client_id, client_secret,scope: 'playlist-read-private user-read-private user-read-email'
My Routes.rb
Rails.application.routes.draw do
devise_for :users, :controllers => { :omniauth_callbacks => 'callbacks' }
get '/users/auth/callback', to: 'callbacks#spotify'
end
And lastly, the link leading up to the login:
<%= link_to 'Sign in with Spotify', user_omniauth_authorize_path(:spotify) %>
But for some reason, whenever I try to log into spotify, it says invalid redirect URI
OK, I figured out a solution to my particular problem:
When it was giving me the error of "invalid redirect URI", I looked at the URI it was trying to go to and I simply used that.
Then I got a second error which gave me a SSL Cert error so I used "gem certified" to fix that. THEN, it gave me a third problem of unauthorized access (the callback returned a failed request). What was happening was that I was trying to use OmniAuth twice. I had two files:
A) OmniAuth.rb
and B) Devise.rb
Both of these files were making API calls and it was messing it up. So to anyone having this problem- don't use both omniauth and devise. Honestly, after the first initial hiccup, I found devise to be way more useful than making your own User model and applying omniauth to that. Devise is more comprehensive!
I've been using Devise + OmniAuth Twitter to authenticate the user to my portal. I am currently facing two issues.
When the user is accessing /users/sign_up, the form is publicly visible. Instead, I want to redirect him to the Twitter authentication page.
When the user is accessing /users/sign_up, the email form is visible. I'm using this form to get the email address of the users after he signs up successfully from Twitter.
Can someone please help me solve this issue from people accessing the forms directly?
Adding Code Snippets:
#config/routes.rb
devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks" }
devise_scope :user do
get "skcript1625" => "devise/sessions#new", as: :login
get "logout", to: "devise/sessions#destroy", as: :logout
end
# app/models/user.rb
devise :database_authenticatable, :registerable, :rememberable, :trackable, :validatable
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.email = auth.info.email
user.password = Devise.friendly_token[0,20]
user.name = auth.info.name # assuming the user model has a name
user.profileimg = auth.info.profileimg # assuming the user model has an image
end
end
You have to redirect the user with the following link
<%= link_to "Sign in with Twitter", user_omniauth_authorize_path(:twitter) %>
Make sure you told your model (usually 'user') that it is 'omniauthable'
devise :omniauthable, :omniauth_providers => [:twitter]
When the user authorized twitter to share your info with the app, all the user's information is available in a hash request.env["omniauth.auth"].
See the documentation for more detail about this hash.
Edit: Everything is well explained here
I have my Rails app setup with Devise, but it's still in the development stages. I also have a Thor task that creates the default Admin user.
Problem is Devise won't let that admin user login to the site until the account is confirmed. Is there any way I can disable the confirmable module for the creation of specific users, such as Admin?
My Thor task:
class Setup < Thor
desc "create_admin [EMAIL] [PASSWORD]", "Creates the administrative user."
def create_admin(email = "admin#bogus.com", password = "testpassword123")
require File.expand_path('config/environment.rb') # load Rails environment
admin = User.create(:email => email, :password => password, :password_confirmation => password)
admin.assign_role :admin
puts "Admin user (#{ email }) created."
end
end
Once your user is created you can call the devise provided confirm! method on it rather than updating the database directly. Eg.:
admin = User.create(:email => email, :password => password, :password_confirmation => password)
admin.assign_role :admin
admin.confirm!
This should work
admin = User.create(:email => email, :password => password, :password_confirmation => password)
So your confirmed_at is set, which is the field devise refers to when checking user confirmation.
EDIT
Forgive me if this seems like a hack but this seems to work for me. After executing the above line,
admin.update_attributes(:confirmed_at => Time.now)
just coment :confirmable in User or Admin model
devise :database_authenticatable, :recoverable, :rememberable, :trackable, #:confirmable...
In config/inicializers/devise.rb
you can set here how many time user have to confirm his account