I'm using Janrain to handle user sessions in my Ruby on Rails app. It appears to be working, however, I don't know how to tell if a user is logged in or not or access the current user's information. After the user signs in, is there a session variable created?
Assuming you are referring to Janrain Social Login(Engage), once the user authenticates through a Social Provider the widget gets a Janrain OAuth token that is valid for 60 minutes. You can use that token to retrieve the user's profile data through this API end point: (https://{your-engage-domain.com}/api/v2/auth_info).
Janrain Social Login does not maintain any log in state related session data. It simply facilitates authentication and normalizes the retrieval of user profile data from multiple authentication providers. Once a successful authentication event happens it is up to your server to validate the authentication token and then establish any form of authorization session related work.
Most Social Providers return access tokens that are valid for 30-60 days.
try 'current_user' variable, it works in most of the rails authentication libs, e.g.:
#in the erb file:
<% current_user = session[:user_id] %>
# or in the rb file:
class MusicController < ApplicationController
before_filter :authenticate_user! # just like devise
def index
# same methods and api as devise.
return if signed_in? and current_user.email
end
end
# put this method in application_controller.rb
def current_user
#current_user ||= User.find_by_id(session[:user_id])
end
more details refer to this example: https://github.com/hatem/janrain-engage-demo
Related
I have rails app with:
Admin table with Devise authentication
User table with email and name without authentication (but session to remember them)
User can browse anywhere but now on certain pages I would like to enhance it and add authentication - allow user to create password and only with password it will be accessible but I am quite lost what is the best way to do it with the current setting?
I allow users to add their details like name and email and I am creating a cookie to remember them without any authentication or password:
UsersController
def create
user = User.find_or_create_by(email: params[:user][:email])
cookies.permanent.signed[:user_id] = user.id
session[:user_id] = user.id # for users/edit temporary
render json: user
end
Let's say I have this following method in User:
before_filter :authenticate_user!, only: :your_order
def your_order
end
If User will visit this page and didn't set up password before, how can I prompt him to create one and how can I require for him to login after with Devise? I am thinking of more solutions but none of them are perfect.
As per the specifications given the below mentioned criteria might help you.
def your_order #before_filter
if user.password.present?
# authenticate using valid_password? method of devise
else
#redirect user to say set_password
end
end
def set_password
#set the user password in this method and after successful completion redirect to login page where before filter your_order will be called
end
Trying to login with another account, i found that on login not asks again for a gmail account.
My action/method is this
class Users::SessionsController < Devise::SessionsController
def destroy
super
cookies.delete :_myapp_session
end
end
It comes here as delete method in routes.rb
When i delete all cookies from browser, i can login watching the gmail page.
If i login with another account stills loading the data from the other account.
I use Devise with omniauth and Mongoid instead ActiveRecord
Problem was that user not created before as properly fields needed on
model like uid and provider
I'm working on google authentication for a rails app. Currently using the omniauth-google-oauth2 gem to implement Google auth. I've managed to have users sign in using google. However, I'd also like users to be able to sign up using google. My problem is that I've matched the google callback URL to a particular controller action (sessions#create).
Is it possible to choose between 2 redirect URIs based on whether users are signing in or signing up? Currently, my only idea is to create new google client credentials to be used for sign up, I hope there is a better way.
You don't need to have 2 redirect uris, you just need to do some more work when receiving the callback. For instance:
class SessionsController < ApplicationController
...
def create
email = auth_hash['info']['email'] # assuming your omniauth hash is auth_hash and you're requiring the email scope
#user = User.find_by(email: email) if !email.blank? # assuming your user model is User
if #user
login_user(#user) # use your login method
elsif !email.blank?
#user = User.new(name: auth_hash['info']['name'], email: email)
unless #user.save!(validate: false) # validate false because I'm enforcing passwords on devise - hence I need to allow passwordless register here)
# deal with error on saving
end
else
# deal with no found user and no email
end
end
protected
def auth_hash
request.env['omniauth.auth']
end
end
I've written all steps but the creation process can be shortened to:
#user = User.create_with(name: auth_hash['info']['name']).find_or_initialize_by(email: email)
#user.save! if #user.new_record?
if #user
login_user(#user)
else
# deal with no user
end
Nonetheless, you can't be sure the user is going to give you scope access to the email, so personally I think the first version, even if a bit lengthier is more robust. Then on the shorter version there's also the problem of, if #user is false, why is so? And will require you to add more logic to figure out why is that, whereas in the first one it's much easier to apply the correct response to each situation.
There is a Rails hotel list app with Devise/CanCan set up
class HotelsController < ApplicationController
before_filter :authenticate_user!, except: [:show]
load_and_authorize_resource
1) What is the most elegant way to let owners edit their hotel info without registering them as users?
2) What if we create a unique token for every hotel and email something like the following link to the corresponding owner:
http://myapp.io/hotels/10010/edit?token=AAAABBBBCCCCDDD
..how to configure Devise/CanCan so they authenticate the user and allow them edit the corresponding record in the Hotels table?
Thank you in advance!
Regards,
Serge.
A quick and dirty solution would be to override the authenticate_user! method and add a check for the token:
# application_controller.rb
def authenticate_user!
if (token = params[:token] || session[:token])
#current_user = User.find_by_token token
session[:token] = token if #current_user
else
super
end
end
First you'd have to add the token column to the user table and you'd still need to create a user for them. Generate a token and email them the link with their token. When they first arrive at the site with the token in the URL, the above method will check if there's a matching record in the db and set it as the current_user and save the token to the session so that subsequent requests will still work. Don't forget to clear that session later (logout or expires).
The reason you still need to create a user record is that you don't want to start overriding your cancan logic and you need a place to store the token anyway.
There's also some gems that will add token authentication:
https://github.com/gonzalo-bulnes/simple_token_authentication
And a simple Rails built in solution:
http://api.rubyonrails.org/classes/ActionController/HttpAuthentication/Token.html
I have previously used a session variable, i.e session[:user_id] to keep track of the current user, but I'm now trying to make my app work with EmberJS necessitating a Grape API backend instead of controllers and such. I was wondering, what is the best way to keep track of user credentials across pages: Session, Cookie, or Thread? I'm leaning toward Thread at the moment, but I was wondering what the pros and cons of each are?
Authentication in API's is a little different. The user should be authorized on every request by passing some type of token rather than once per session.
Typically, you'll have a route that accepts username/password that will return an auth token and then the token will be passed as part of BasicAuth or in headers on every request. In Grape, there are a few ways to do this. You can add an Authentication helper:
module ApiHelpers
module Authentication
def authenticate!
error!('401 Unauthorized', 401) unless current_user
end
def current_user
if token_from_headers
#current_user ||= User.find_by api_key: token_from_headers[1]
end
end
def authenticate!
error!('401 Unauthorized', 401) unless current_user
end
def token_from_headers
/Token token="(.+)"/.match(headers['Authorization'])
end
end
end
Include that in the main api file:
class API < Grape::API
helpers ApiHelpers::Authentication
end
Then, for every request that needs authentication:
resource :items do
get do
authenticate!
present current_user.items, with: Entities::Item
end
end
You can also add a custom middleware for authentication or authenticate using basic auth. More info on that in Grape's README: https://github.com/intridea/grape#authentication
I'm assuming your endpoint is using SSL?