Facebook oauth login with custom parameters using Sorcery gem - ruby-on-rails

I'm trying to pass a custom parameter to Facebook oauth url to get it back in the callback. I know it's possible but I'm using Sorcery gem and I need to set the parameter dynamically, I mean I can't define it in sorcery.rb initialization file, like it is now:
Rails.application.config.sorcery.configure do |config|
config.facebook.callback_url = ENV['FACEBOOK_CALLBACK_URL']
...
end
I need to define in my controller, how can I do it with this gem?

I haven't found this documented but it worked, so just put in your controller:
::Sorcery::Controller::Config.facebook.callback_url = ENV['FACEBOOK_CALLBACK_URL'] + "param1=foo"
and param1 will be send back to you after authentication :)

Use the state parameter outlined in oAuth Dialog.
A unique string used to maintain application state between the request
and callback.
Facebook will redirect back to the site with:
YOUR_REDIRECT_URI#
access_token=USER_ACCESS_TOKEN
&expires_in=NUMBER_OF_SECONDS_UNTIL_TOKEN_EXPIRES
&state=YOUR_STATE_VALUE

Related

How do you add auth to the routes provided by eve_swagger?

I'm using eve_swagger (https://github.com/pyeve/eve-swagger) in a project and it works great for generating swagger docs. I have a use case where I need to have the default /api-docs endpoint that is created as a route in the library require authentication.
When I create my eve app, I set the auth param to my auth class, but /api-docs endpoint is created with a blueprint and I'm not sure how I can add auth to this endpoint. Any ideas?
My eve* deps:
eve = "~0.7"
eve_sqlalchemy = "~0.7"
eve_swagger = "^0.0.11"
Thanks!
I found a way, not sure if this is the best/right way though.
I take the eve_swagger blueprint that's provided, and add a before_request with an authorization function. Something "like" this:
import eve_swagger
from flask import current_app as app
def authorize_swagger:
# my auth logic
eve_swagger.swagger.before_request(authorize_swagger)
app.register_blueprint(eve_swagger.swagger)
The result of doing this is now when I call the default /api-docs route, my authorization function is called and processed before the request. This way if my function decides the request is not authorized, it can stop the request.

Is it possible to create a functionality about user registration with Pudit or Devise on Rails?

I already used Pudit and Devise for registration and authorization via the web interface.
But I want to support via REST interface too. Is it possible to use Pudit or Devise for doing that. For example, sending this JSON for creating a new user
{
"email":"user#mail.com",
"password":"password",
"confirm_password":"password"
}
Yes It is possible. I have used Devise gem to create user registration with RESTful api. RESTful api like - http://APPLICATION_URL/api/v1/users/sign_up.json
and You can post json parameter as follows
{"user": {"email":"user#mail.com","password":"password",
"confirm_password":"password"} }
Thanks,
Kapil Chothe

dynamic callback with omniauth

I use omniauth for Facebook Authentification in my app. All works great. Now I try to implement a callback to a dynamic page which is the ID of an article.
The URL follows the pattern myapp.com/ads/:id/
On this page I use the auth gateway to /auth/facebook
The callback should come back exactly to this page (e.g. /ads/4711/).
I tried to accomplish this in routes:
match "/auth/facebook/callback" => "/ads/:id/"
which is obv not valid.
Also tried to work out this solution OmniAuth dynamic callback url to authenticate particular objects instead of current_user with no success.
Any help is appreciated.
Found the solution via Devise + Omniauth - How to pass extra parameters along?
I can easily pass the ID as a param to the auth page and get it back via request.env['omniauth.params']

Passing parameters through OmniAuth

I need to pass some parameters to callback action. Judging from the source code, OmniAuth should add query string to callback URL but strangely it does not. When I open
/auth/facebook?from=partner
...and get redirected to Facebook, return_url is just
/auth/facebook/callback
...without any parameters.
After struggling with all the above answers, I figured out what to do regarding Facebook, which by default does not display the params in request.env["omniauth.auth"].
So -- If you are using a query string for the callback, similar to something like this:
"/auth/facebook?website_id=#{#website.id}"
The only way to get that website_id param is by using request.env["omniauth.params"]. NOTE: MAKE SURE YOU USE omniauth.params and not omniauth.auth -- this one tripped me up for a while.
Then, to test this out, you can inspect it within your controller action (notice the RAISE line...):
def create
raise request.env["omniauth.params"].to_yaml
# the rest of your create action code...
end
You should see your parameter there. Great. Now, go back to your controller and remove that RAISE line. Then, you can access the param as follows in your controller action:
params = request.env["omniauth.params"]
website_id = params["website_id"]
NOTE: in params["website_id"] you need to use quotes and NOT a symbol.
I guess the cookie thing works but why do all that when you can use the state variable as documented here: https://github.com/mkdynamic/omniauth-facebook
This is how I used it:
when creating the url you can just add state in the Query String and it will be available in the callback url as well.
user_omniauth_authorize_path(:facebook, :display => 'page', :state=>'123') %>
now the callback url will be
http://localhost:3000/users/auth/facebook/callback?state=123&code=ReallyLongCode#_=_
Now in the callback handler you can process the state
You can use the :params options, as in
omniauth_authorize_path(:user, :facebook, var: 'value', var2: 'value2' )
and later in the callback you can access request.env['omniauth.params'] to get the hash! :)
(copied from this answer)
What you want to do is dynamically set your callback to include the partner name in the url (not the url parameters), on a per authentication transaction basis, depending on which partner was involved. This means setting the callback url dynamically, for each authentication request. See this blog post to get started. The callback url automatically drops the url parameters, as you've noticed, so doing this with parameters won't work.
So, if instead of trying to pass the partner name/id in as a parameter (which is dropped), you structured your routes so that the partner_id and OmniAuth provider were part of the callback url, then you'd have something like:
/auth/:omniauth_provider/callback/:partner_id
...where a valid callback would be something like
/auth/facebook/callback/123456
...then you would know that a given callback came in from facebook, with partner id 123456
OmniAuth already has a built-in way to know where the user was, it's called "origin" as documented here:
https://github.com/intridea/omniauth/wiki/Saving-User-Location
You know, I think I might be trying to solve this the hard way.
Cookies might be the answer. I think you can solve this by having your login action store a cookie, and then redirecting to the proper /auth/:provider path for authentication, and when the callback is triggered (in SessionsController#create), you just read the cookie back to know where to redirect them to.
So, right now, your "login with facebook" link (or whatever you have you in your app) probably goes to /auth/facebook. Instead if you created a custom action like
POST /partner_auth
...and called it with the url...
POST example.com/partner_auth?from=partner&provider=facebook
Then you might have a controller like:
class PartnerAuth < ApplicationController
def create
cookies[:from] = params[:from] # creates a cookie storing the "from" value
redirect_to "auth/#{params[:provider]"
end
end
Then in the SessionsController#create action, you would have...
def create
...
destination = cookies[:from]
cookies[:from].delete
redirect_to destination # or whatever the appropriate thing is for your
# app to do with the "from" information
end
I tried to build a demo app to accomplish what I'd outlined in the other answer, but you're right - it was too complicated to try to dynamically inject a custom callback into the OmniAuth code. There is a configuration option to override the default callback, but it doesn't appear to be easy to set it dynamically.
So, it dawned on me that cookies would be way simpler, user-specific, and since you theoretically only need to store this from information for a very short time (between when the user tries to authenticate, and when the callback is triggered), it's no big deal to create a cookie, and then delete it when the callback gets hit.
Use the 'state' Variable. Facebook allows the user to set a STATE variable.
Here is how I did it, I appended the AUTH URL with ?state=providername
http://localhost/users/auth/facebook?state=providername
This param is returned to me at Callback as params['providername']
I devised the solution from the original Omniauth Path Method
user_omniauth_authorize_path(:facebook, :display => 'page', :state=>'123') %>

Devise + Omniauth - How to pass extra parameters along?

I have the ability in the app to load /users/auth/facebook to connect to facebook. I want to be able to know where the request came from. Whether it was from a user who is registering with facebook, or a existing user who simply wants to connect with facebook. Based on the type, the responses are very different.
How can I pass a param along to omniauth when authenticating. I tried doing:
/users/auth/facebook?connect_action=signup_connect_to_facebook
But that connect_action param didn't make it when it hit AuthenticationsController#Create
Ideas? Thansk
You have to use the :params options, as in
omniauth_authorize_path(:user, :facebook, var: 'value', var2: 'value2' )
and later in the callback you can access request.env['omniauth.params'] to get the hash! :)
If the request is made from different pages in your application, you can examine the request.env['omniauth.origin']. Omniauth saves this variable automatically.
Here is a more detailed explanation
As far as passing custom parameters, I have tried to do this unsuccessfully. The workaround is to store it in the session before going to the provider as explained here.
Hope this helps you.
For facebook use the 'state' parameter and pass what you want, but don't forget the encode.
/users/auth/facebook?state=parameter
You could send the parameter as a url form encoded json and then in the callback parse it.

Resources