Comments (29)
Because Ueberauth doesn't provide a good interface for querying the Facebook API and getting an Ueberauth.Auth struct back, I had to copy paste a lot of code out of Ueberauth in order to request information from Facebook/etc with the token I received from the mobile app.
It sounds to me that we just need to provide a public API (Protocol or callback behaviour) for fetching user data from a token so that you can get the user data back in a unified way outside of the OAuth2 Authorization Code flow.
Ueberauth was designed around OAuth2 Authorization Code flow. The user is redirected from their browser to the authorization server and then back to the redirect_uri
(callback) with a code grant that is then used in exchange for an access token.
The access token can then be used to get the user's data and other things on behalf of the user.
If you are wanting to provide a token for your native mobile apps, you will most likely need to implement an endpoint like POST /token
where your mobile app can post the token it received from the OAuth2 provider so your app can exchange that for your own auth token (like a JWT generated from Guardian).
POST /token
{"provider": "facebook", "access_token": "<facebook-access-token>"}
Does this make sense?
from ueberauth.
@hassox the problem is not doing it, the problem is why
? Why would I do that for the good of the community. Specially that we are talking about backend code, which we don't care on increase the code base as long as is for the good of the package, no just for sake of adding it.
Look, those people that @Rakoth (amazing job and I am glad that somebody implemented), but now I have to make decision about using ueberauth
from the official repo or use them because I really need that.
I hope you understand that I am trying to actually avoid to add complexity on hex
packages when we really don't need to do it. I want to see ueberauth
to be extended from the next needs, and being realistic, in 2017 is more valuable to have the token based workflow
than the other one. With SPAs
everywhere and mobile apps.
Sorry I repeated again, it's about if I can do it or not outside of euberauth
, it's about extending ueberauth
for the good of the community.
from ueberauth.
@danielberkompas Thanks for your reply. I'm still exploring things, and I'm reconsidering my approach after your last comment. Thanks 👍 .
Possibly a better alternative is:
- Get FB accessToken on the client;
- Send this token to the server, on the server do a request to (in my case) Facebook's graph API, https://graph.facebook.com/v2.7/{facebook-user-id}?access_token=MY_TOKEN, and request the needed user's information.
- If token is valid, and thus results are returned, the user is authenticated. If needed store the user's info in the database and exchange the Guardian token.
Thoughts?
from ueberauth.
Hi guys, you could use providers forks with token flow implemented:
https://github.com/KosyanMedia/ueberauth_facebook
https://github.com/KosyanMedia/ueberauth_twitter
https://github.com/KosyanMedia/ueberauth_google
https://github.com/KosyanMedia/ueberauth_vk
https://github.com/KosyanMedia/ueberauth_ok
from ueberauth.
@danielberkompas after watching what you did I notice a common pattern in the other packages and I am starting to understand a little bit better ueberauth
in a nutshell.
Things to Notice
- From most of the
strategies
implemented extracting the datais attached
to theconn
for some reason https://github.com/ueberauth/ueberauth_github/blob/master/lib/ueberauth/strategy/github.ex#L161 - We need to construct the
Ueberauth.Auth
in both cases, for example: https://gist.github.com/danielberkompas/9822197a8cec66ff011d24ab32e687cf#file-auth-ex-L73 In eachstrategy
Thoughts
- Create a
protocol
meaning,hand shaking
between thestrategies
andueberauth
, instead of depending ofconn
inside thewe pass the user info down
so you can constructUeberauth.Auth
.
That allow us to use the samestrategy
even if we are usingtoken
basedstrategy
. - Create a
token strategy
which is a little different and normally it will be callmanually
with therequired access token
but it will reuse thestrategy configuration + extracting data code
I am just thinking right now it how to do it, I am pretty sure if we open the protocol
of the strategies
we can actually scale
this package to the next required feature.
from ueberauth.
Hi! Thanks for your effort on this great library!
Facing the same issue with sdk returning access token. My first thought was to support extra case in handle_callback!
when token
parameter is present.
I agree though, that provider API could be more clear and reusable, so we don't have to copy-paste private methods from providers in non-trivial cases.
from ueberauth.
@mbenatti Here's a gist of what I ended up doing: https://gist.github.com/danielberkompas/9822197a8cec66ff011d24ab32e687cf
from ueberauth.
Hello everyone!
Thank the contributors for a great job!
Ueberauth solves the same problems that omniauth from ruby comunity solves. So the problem (if it is a problem) explained here must be the problem in ruby community too.
There is no general implementation for this case in omniauth, but there is a gem (no longer supported) https://github.com/SoapSeller/omniauth-facebook-access-token which is implementing Oauth API token authentication for Facebook.
I am not sure than defining extra provider is a good idea but why the idea of defining extra ueberauth layer for common case for native iOS and Android application is so bad? Or may be there is a security issues we should know about? Thank you!
from ueberauth.
@yordis I think I'm agreeing with you. I'm suggesting that we should build this into the libraries to accept a "token" parameter as part of the callback so you get the standard Auth struct. Is that not what you had in mind?
from ueberauth.
Can you please explain a little more about what you're wanting to do?
from ueberauth.
I mean when you piping trough api instead of browser
from ueberauth.
If you're piping through an api pipeline rather than browser it sounds like you're into Guardian territory. There's nothing specifically in ueberauth that relies on the session. I'm sorry to go back again, but can you outline what you're trying to do?
from ueberauth.
I have a similar issue. I want a mobile app to be able to post an OAuth token to my API authentication endpoint. I then want to be able to run that token through Ueberauth and get back an Ueberauth.Auth
struct, which I can then use to authenticate the user the same way I do for regular web requests.
Right now, it isn't clear if there's a way to use Ueberauth without using the plugs, or whether you should use the plugs for this. Does that make sense?
from ueberauth.
I also struggle(d) with this. But it's mostly based on a misunderstanding of what the goal of this library is. That being said, if if say something misinformed here please comment :)
IMO this sums up the goal of the library nicely:
Ueberauth provides only the initial authentication challenge, (initial OAuth flow, collecting the information from a login form, etc). It does not authenticate each request, that's up to your application
So the goal is only acquiring the user's information. For example when working with a mobile application (as in my case) there is a big chance you don't need this library. Instead you can use a clientside oAuth library to acquire the user' relevant information, store this information if needed, and continue with something like guardian to authenticate future requests.
from ueberauth.
@swennemans I'm not sure that really works. If your client app doesn't post an OAuth token to your API to authenticate, how does it authenticate? Do you require your users to type in a password even after they've logged in via OAuth on the client app?
from ueberauth.
@danielberkompas I was wondering the same thing. Currently I'm using react-native-fbsdk. And I'm experimenting with the following flow:
- Login / Signup with Facebook button;
- This will transit user to Facebook login/screen;
- If an user fills in valid login information, it will return a token;
- This token is only useful to querying the user information using Facebook's graph API;
- This queried information I can store/query in my Phoenix' database. Here I can create or query the user based on the user' email (returned from Facebook's graph API;
- Based on the valid token returned from the Facebook login, I assume the user is authenticated;
- Then, in order to communicate with the JSON API, I return a Guardian token.
- If an user is logged-out and wants to login again, the same process applies.
I'm not saying that this is the way to go. But from reading ueberauth's readme, it seems that it's only meant as information retrieval tool. Maybe @hassox can chime in :)
Thoughts?
from ueberauth.
Do you query Facebook for user information on the mobile app or on the server?
If on the mobile app, what do you then send to the server to prove the user is authenticated, in exchange for the Guardian token?
If on the server, how does the server get the Facebook token if you don't send it to the server and don't use Ueberauth to fetch information?
from ueberauth.
The flow you suggest there is exactly what I'm doing.
Because Ueberauth doesn't provide a good interface for querying the Facebook API and getting an Ueberauth.Auth struct back, I had to copy paste a lot of code out of Ueberauth in order to request information from Facebook/etc with the token I received from the mobile app.
from ueberauth.
I am also looking for this kind of scenario (The mobile app gets the token, then send if to the server for validation and get a JWT token back), there is still nothing about this in Ueberauth ? What would be the best approach ?
from ueberauth.
@danielberkompas
Hi
I'm trying to do the same thing, can you share your solution with me?
from ueberauth.
For Facebook strategy,
I finished the module that would work when you pass a token
.
Things to notice
The things to notice is the overlapping in how to extract the data BUT
the differences is that I pass the raw user data
instead of extract it from the Plug.Conn
.
auth method
which leave in https://github.com/ueberauth/ueberauth/blob/master/lib/ueberauth/strategy.ex#L276 have a different shape, because it doesn't require a Plug.Conn
but it does require to pass %OAuth2.AccessToken{} = token
because credentials
need that hash type.
It's been call here https://github.com/ueberauth/ueberauth/blob/master/lib/ueberauth/strategy.ex#L311
defmodule Ueberauth.Strategy.Facebook do
alias Ueberauth.Auth.{Info, Credentials, Extra}
def handle_callback!(token) when is_binary(token) do
{_module, config} = Application.get_env(:ueberauth, Ueberauth)[:providers][:facebook]
token = OAuth2.AccessToken.new(token)
client = Ueberauth.Strategy.Facebook.OAuth.client([token: token])
case OAuth2.Client.get(client, "/me?fields=#{config[:profile_fields]}") do
{:ok, %OAuth2.Response{status_code: status_code, body: user}} when status_code in 200..299 ->
{:ok, auth(user, token)}
{:ok, %OAuth2.Response{status_code: 401, body: body}} ->
{:error, body["error"]["message"]}
{:error, %OAuth2.Error{reason: reason}} ->
{:error, reason}
_other ->
{:error, :internal_server_error}
end
end
defp auth(user, %OAuth2.AccessToken{} = token) do
%Ueberauth.Auth{
provider: :facebook,
strategy: Ueberauth.Strategy.Facebook,
uid: uid(user),
info: info(user),
extra: extra(user, token),
credentials: credentials(token)
}
end
def uid(%{"id" => id} = _user), do: id
def info(user) do
%Info{
description: user["bio"],
email: user["email"],
first_name: user["first_name"],
image: fetch_image(user["id"]),
last_name: user["last_name"],
name: user["name"],
urls: %{
facebook: user["link"],
website: user["website"]
}
}
end
def extra(user, token) do
%Extra{
raw_info: %{
token: token,
user: user
}
}
end
def credentials(%OAuth2.AccessToken{} = token) do
scopes = token.other_params["scope"] || ""
scopes = String.split(scopes, ",")
%Credentials{
expires: !!token.expires_at,
expires_at: token.expires_at,
scopes: scopes,
token: token.access_token
}
end
defp fetch_image(uid) do
"http://graph.facebook.com/#{uid}/picture?type=square"
end
end
from ueberauth.
Dealing a little bit deeper with the code, I think the best approach from ueberauth
is to create two types of strategies
. The only thing that overlap is data fetching
but everything else is pretty much completely different.
I will stop here because I need some advice from the contributors in what should I do (specially thinking in backward comparability)
from ueberauth.
@Rakoth I tried #50 but the idea was shutdown 😢
from ueberauth.
Hello everyone again!
I think that @scrogson approach make sense! We don't need to affect default web flow, we only need another flow for server based exchange of token into user info (ueberauth auth format). The main problem is a correct implementation of API and configuration rules format which look good with default rules and general API. I think that strategies will be prepared very fast in case of presented general template. Thank you, and sorry for strange proposation of extra layer.
from ueberauth.
I came across this whilst trying to figure out a way to authenticate a single page app with my phoenix api. I'm trying the use the google strategy along with the Google sign-in for websites.
Essentially the first leg of authentication is handled entirely client-side; the user clicks the 'login with google' button and a popup from google appears prompting them to sign-in/allow access. Upon successful authentication on the google popup a callback on my spa is fired which receives a googleUser
object from which I can obtain a token to send to my server. I'm sending in the form /auth/callback?code={token}
which is the same as what's hit in the standard Ueberauth server flow but I'm getting an error like this:
(ArgumentError) raise/1 expects an alias, string or exception as the first argument, got: %OAuth2.Response{body: %{"error" => "invalid_grant", "error_description" => "Code was already redeemed."}
I feel like I'm quite close but ueberauth seems to struggle with the token provided? Perhaps I'm going wrong client side. Any ideas?
from ueberauth.
@harrygr if your are handling the OAuth2 workflow in the client side, then you will need what I am pushing for.
This is not currently supported. You will have to do something similar to what I did to be able to do token based workflow
from ueberauth.
I think I agree with @scrogson here. The strategies have this stuff already there just isn't a way that you can post it.
If we were to add a "token" parameter to the oauth strategies which assumes you've done client side oauth and have an access token, it should use that to populate the auth struct. Would that solve the issue that you folks are having?
from ueberauth.
@hassox and after I deal with it. I don't see the point of literally duplicate 80%
of the code just because we don't want to add some layer of abstraction, which is the only reason why I pushed for this.
But you are right, everything can be done without even use anything from ueberauth
but the effort is already implemented on this package 😢 just look how much code overlap to each other
from ueberauth.
Moved to #89
from ueberauth.
Related Issues (20)
- OAuth2 needs new maintainers HOT 4
- State nonce cookie should properly be signed HOT 2
- How can run Ueberauth plug directly? HOT 3
- Custom `callback_port` and `callback_scheme` not used HOT 1
- Callback URL not mounted right when router has nested paths
- Can't set strategy options at runtime HOT 2
- Line Login v2.1 update request which I've done HOT 4
- Gracefully handle unknown providers HOT 10
- callback_port config compiled into plug at compile time HOT 10
- App.Auth.AuthController.request/2 is undefined or private HOT 1
- minor: mix package versions are out of date
- New hex.pm release? HOT 1
- Incorrect callback_url when using Bandit.PhoenixAdapter
- put_session successful, but get_session failed HOT 1
- function MyAppWeb.OAuthController.request/2 is undefined or private HOT 1
- Support for nonces HOT 1
- FR: Support multiple usages of the same strategy in config HOT 13
- Incomplete docs to configure pipeline and check that user is authenticated HOT 3
- Latest release breaks existing paths HOT 6
- Latest version is retired HOT 7
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from ueberauth.