a lot of documentation that I had read about how to build Marketplace's apps is telling me to use OpenID+Oauth 1.0 with 2-Legged.
But reading all other information about Authentication on Google's docs is telling me OAuth 1.0 is deprecaded and should NOT be used.
So what is correct? Should I use OAuth 1.0 on Marketplace or not ?
PS: to clarify, I'm going to use Google Documents List API version 3.0 API, because on Drive SDK is impossible to know user's email, based on a File's permission set. On the File's permission set there's only the name, but I need the user's email.
Thanks,
Expanding on jonathanberi's comment,
As on this answer Google has deprecated the Oauth1 and OpenId. Google recommend using OAuth2 for all marketplace apps, especially after the new experience announcement
Here is some sample code
def get(self, *args, **kwargs):
code = self.get_argument('code', None)
error = self.get_argument('error',None)
redirect_uri = "{protocol}://{host}{path}".format( protocol = self.request.protocol,
host = self.request.host,
path = self.request.path)
flow = OAuth2WebServerFlow(
client_id = config['CLIENT_ID'],
client_secret= config['CLIENT_SECRET'],
scope = 'https://www.googleapis.com/auth/userinfo.email',
redirect_uri = redirect_uri,
access_type = 'online'
)
if code is None:
auth_uri = flow.step1_get_authorize_url()
self.redirect(auth_uri)
elif error:
self.redirect("http://error.com")
else:
credentials = flow.step2_exchange(code)
http = httplib2.Http()
http = credentials.authorize(http)
service = build('oauth2', 'v2', http=http)
user = service.userinfo().get().execute()
The alternative of using OpenID is to give the user the possibility of logging in to your app using different kinds of accounts like facebook, google, etc.
https://developers.google.com/accounts/docs/OpenID?hl=en
If you want to give that possibility you should use OpenID, but if you just want to give permission to the user only for gmail accounts, you should only use the OAuth authorization.
OAuth 1.0 is officialy deprecated since April, 2012 https://developers.google.com/accounts/docs/OAuth
Related
I am writing a Azure Service that will occasionally write to my facebook page as a status. Since the service does not have a UI component, a majority of the examples on the Facebook and Facebook .NET SDK pages are not helpful.
I created an application on facebook and then fired up the F# REPL in Visual Studio. I generated the token like so:
#r "../packages/Facebook.7.0.6/lib/net45/Facebook.dll"
#r "../packages/Newtonsoft.Json.7.0.1/lib/net45/Newtonsoft.Json.dll"
open Facebook
open Newtonsoft.Json
type Credentials = {client_id:string; client_secret:string; grant_type:string;scope:string}
let credentials = {client_id="859968674039398";
client_secret="XXXXXXXXXX";
grant_type="client_credentials";
scope="manage_pages,publish_stream,read_stream,publish_checkins,offline_access"}
let client = FacebookClient()
let tokenJson = client.Get("oauth/access_token",credentials)
type Token = {access_token:string}
let token = JsonConvert.DeserializeObject<Token>(tokenJson.ToString())
A token comes back as expected. However, when I go to use the token, I am getting errors:
let client' = FacebookClient(token.access_token)
let me = client'.Get("me")
returns
An active access token must be used to query information about the
current user.
and
let pageId = "/me"
type FacecbookPost = {title:string; message:string}
let post = {title="Test Title"; message = "Test Message"}
let postResponse = client'.Post(pageId + "/feed", post)
returns
The user hasn't authorized the application to perform this action
When I read the docs, they talk about getting the application to be approved by Facebook -> but that makes no sense in my use case b/c there is no application as defined with a human end user -> or even any other user invoking the code.
When I generate the token on Facebook Graph Api explorer with the correct permissions, I can use the token to make those GETS and POSTS. Should I just generate the token and stick it in my .config file? How long does a token last?
Thanks in advance
I think you haven't fully understood how Facebook API works.
You always need an App to perform an action (in your case the APP is 859968674039398)
In order to post on behalf a user, you will need that user to grant permissions to your App.
Your App has to be public and if you require more permissions than the basic ones, you need to go through the review process.
The access token you get from the Graph API Explorer (which is an App BTW) is only for you.
Please read the docs CBro provided.
I hope it helps.
I am playing with Google's OAuth 2.0 Playground using my own personal Google account, but I cannot seem to recover my Gmail address using the playground.
The scope I am using is:
email profile https://www.googleapis.com/auth/plus.login
But when I call the API:
https://www.googleapis.com/oauth2/v2/userinfo
I get various information about the user such as family name, first name, gender, picture, etc. but it does not return the user's email.
How do I retrieve the user's email address? Do I have the wrong scope or am I calling the wrong API? I feel like this should be very simple but I have literally been trying to figure this out for hours and I cannot find an API and scope combination that consistently provides the user's email address.
Update: December 2018
On December 20th, Google announced that the Google+ API would be turned down in March 2019, with intermittent failure starting at the end of January 2019. As part of the the plus.people.get endpoint is deprecated and scheduled to be terminated.
The userinfo endpoint is de-deprecated (see clarification) and should provide the info assuming
You request the https://developers.google.com/identity/sign-in/web/devconsole-project scope and
You request the email field.
Clarification: 24 Jan 2019
Google documented that the userinfo (v2) endpoint was deprecated, but later changed it to "deprecated, but kept available for backwards compatibility".
Current documentation discusses getting profile and email information through the currently supported openid method. This includes using the "userinfo" endpoint specified in their discovery document, as required by OpenID Connect.
At the moment, that URL is https://openidconnect.googleapis.com/v1/userinfo, but this has changed in the past and the discovery document at https://accounts.google.com/.well-known/openid-configuration is the authoritative source for the URL to use.
So, to be clear:
The old userinfo URL is maintained for backwards compatibility
The new userinfo URL is available at the discovery document
Regardless, the plus version of anything (described below) is deprecated and scheduled to be removed.
Original Answer
There are a lot of issues here in what you're doing and how you're trying to do it.
For starters, the https://www.googleapis.com/oauth2/v2/userinfo endpoint is deprecated, and scheduled to be removed in September 2014. It has begun working inconsistently - so don't use it.
As #abraham noted, you'll use the people.get endpoint at https://www.googleapis.com/plus/v1/people/me. This should give you the emails field containing an array of addresses. In your case, there will likely be only one that has a type of "account".
As of 2017: use the email scope. See Authorizing API requests.
This email scope is equivalent to and replaces the
https://www.googleapis.com/auth/userinfo.email scope.
For signing in with Google using OAuth 2.0, there's no need to make a separate request to get user's email.
When Google calls the callback URL, it provides a code in the query string that you could use to exchange for access token and ID token. The ID token is a JWT that contains identity information about the user, which includes the email address.
See more information here: https://developers.google.com/identity/protocols/oauth2/openid-connect
You'll want to add the https://www.googleapis.com/auth/userinfo.email scope or replace https://www.googleapis.com/oauth2/v2/userinfo with it. If you're using the HTML example they provide, you can list multiple scopes separated by a space.
<span
class="g-signin"
data-callback="signInCallback"
data-clientid="{{ plus_id }}"
data-cookiepolicy="single_host_origin"
data-requestvisibleactions="http://schemas.google.com/AddActivity"
data-scope="https://www.googleapis.com/auth/plus.login
https://www.googleapis.com/auth/userinfo.email">
</span>
To retrieve the email address, you need to include the scope: "https://www.googleapis.com/auth/userinfo.email" as mentioned in this document. If this scope is included while you generate the refresh token, you should be able to get the email address of the authenticating user by making the following request:
you can call this with your own access token then will give the response
https://www.googleapis.com/oauth2/v3/userinfo?access_token="YOUR_ACCESS_TOKEN"
response will look like this
{
"sub": "1057abc98136861333615xz",
"name": "My Name",
"given_name": "My",
"family_name": "Name",
"picture": "https://lh3.googleusercontent.com/a-/AOh14qiJarwP9rRw7IzxO40anYi4pTTAU_xseuRPFeeYFg",
"email": "MyName#gmail.com",
"email_verified": true,
"locale": "en"
}
or simply you can just write a function
import requests
def get_user_email(access_token):
r = requests.get(
'https://www.googleapis.com/oauth2/v3/userinfo',
params={'access_token': access_token})
return r.json()
I came here looking why my server did not get email in response to /oauth2/v2/userinfo api call. It was only once that I saw this & it has been working well in past.
The answer gave good lead. While fixing this, there were several other resources that helped. Still I am not sure whether expecting always email in the response is ok. so - put error handling in code in case emails are not returned.
Google api documentation about migrating to google+ signin.
https://www.googleapis.com/auth/userinfo.email scope
People resource documentation
Add google+ api to the project using google developer console. The complimentary (quota) of calls is quite high (20m for google+ signin api per day).
Add error handling & logging in server code in case api returns no emails. In my case, I was looking only type='account' email.
This is actually a bit of a challenge as Google does not provide an email by default. You must specifically request it from Google Plus.
const scope = [
'https://www.googleapis.com/auth/plus.me', // request access here
'https://www.googleapis.com/auth/userinfo.email',
];
auth.generateAuthUrl({
access_type: 'offline',
prompt: 'consent',
scope: scope,
});
const plus = google.plus({ version: 'v1', auth });
const me = await plus.people.get({ userId: 'me' });
const userEmail = me.data.emails[0].value;
There is a full version in this blog post I wrote: https://medium.com/#jackscott/how-to-use-google-auth-api-with-node-js-888304f7e3a0
by using google nodejs sdk:
const {google} = require('googleapis');
const oauth2Client = new google.auth.OAuth2(
googleClientIdPublic,
googleClientSecret,
googleRedirectUriPublic
);
//scope you need: https://www.googleapis.com/auth/userinfo.email
oauth2Client.setCredentials(tokens);
const googleAuth = google.oauth2({
version: "v2",
auth: oauth2Client,
});
const googleUserInfo = await googleAuth.userinfo.get();
const email = googleUserInfo.data.email;
more info
I have been following Prisoner's answer right above, and it helped me... until I received the email from Google Developers about how Google+ API will be shutdown on March 7, 2019.
I scrounged around and found this solution to get the email using an id_token that is returned when you authorize an app with the email scope on your developer console.
From Google Sign-in for Websites:
To validate an ID token in PHP, use the Google API Client Library for
PHP. Install the library (for example, using Composer):
composer require google/apiclient
Then, call the verifyIdToken() function. For example:
require_once 'vendor/autoload.php';
// Get $id_token via HTTPS POST.
$client = new Google_Client(['client_id' => $CLIENT_ID]); // Specify the CLIENT_ID of the app that accesses the backend
$payload = $client->verifyIdToken($id_token);
if ($payload) {
$userid = $payload['sub'];
// If request specified a G Suite domain:
//$domain = $payload['hd'];
} else {
// Invalid ID token
}
This will return an array that contains the user information, that also contains the email of the user who logged in. Hope this helps anyone else.
Please see my answer here to the identical issue:
how to get email after using google OAuth2 in C#?
In your scopes variable. Use the value "email" not the
full https address. Scope keywords in the web link are separated by spaces. I solve your issue with scopes written as: profile email openid.
https://developers.google.com/gmail/api/v1/reference/users/getProfile
For gmails api, add this to nodejs code:
function getUsersEmail (auth) {
const gmail = google.gmail({version: 'v1', auth})
gmail.users.getProfile({
userId: 'me'
}, (err, {data}) => {
if (err) return console.log('The API returned an error: ' + err)
console.log(data.emailAddress)
})
}
Gmails api: https://developers.google.com/gmail/api/guides/
Change the authorizationRequest with given scope: scope=openid%20email%20profile and use userinfoapi. This link worked for me
I suggest the following minimal code, which include '*/userinfo.email' and '#google-cloud/local-auth' package:
const path = require('path');
const { google } = require('googleapis');
const { authenticate } = require('#google-cloud/local-auth');
const scope = [
'https://www.googleapis.com/auth/userinfo.email'
];
async function runSample() {
const auth = await authenticate({
keyfilePath: path.join(__dirname, 'oauth2.keys.json'),
scopes: scope
});
google.options({ auth });
const dat = await google.oauth2('v2').userinfo.get()
console.log(dat.data.email);
}
if (module === require.main) {
runSample().catch(console.error);
}
module.exports = runSample;
I am new to Facebook apps, I have an app already up and running on GAE (using python). I want to integrate it with Facebook so I can access some of the users' data to help me personalize the app (data like the liked pages, interests, where they are from etc..). And also to share the app's outputs to be seen by friends.
I thought I would go for the Facebook app option on https://developers.facebook.com/
I don't know where to start from, there are some tutorials (most of them are very old, some use scripts that are deprecated so it is a bit worrying), and there's FBML.. and I was thinking that maybe I can get the same data by only using Facebook's log in then use FQL to access these data.
And I don't know if I will get stuck with that new https restriction (Facebook says that it is required as of October 2011 to have an SSL certificate).
So bottom line.. where do I start?
Here we go:
From this link do download: https://github.com/jgorset/facepy/tree/master/facepy:
from downloads, you will have:
signed_request.py to parse signed_request that will be posted by facebook in your
canvas url: https://apps.facebook.com/myapp in POST method
and graph_api.py to make operation to graphapi https://developers.facebook.com/docs/reference/api/
note: you will be including access_token from cookies written by facebook js sdk.
for fb js sdk see this answer: https://stackoverflow.com/a/8625873/492258 of javascript part
in your index page:
fb_app_secret='abcd...'
fb_app_id = 123345
def index(request):
if request.POST:
signed_request_param = request.POST.get('signed_request)
if signed_request_param:
#signed_request.py
signed_request_dic = signed_request.parse_signed_request(signed_request_param, fb_app_secret)
if signed_request_dic:
if signed_request_dic.has_key('user_id'):
fb_uid = signed_request_dic['user_id']
#you got your man that is previously authorized your fb app : mypp
for successive calls, you'll be using cookies that I mentioned above:
def my_page(request):
my_dict = None
my_dict = signed_request.get_user_from_cookie(request.COOOKIES, fb_app_id, fb_app_secret)
if my_dict:
if my_dict.has_key('uid'):
fb_uid = my_dict['uid']
fb_uid = int(fb_uid)
#you got your registered user again.
For registration, the easiest way doing from fb js sdk, already I mentioned
#finally for SSL, in your app.ymal:
- url: .*
script: django_bootstrap.py
secure: optional
Don't forget to set P3P for internet explorer, iframre cookie issue:
def my_page(request):
....
response = render_to_response('mypage.html', view_params )
response["P3P"] = 'CP="IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT"'
return response
You need to authenticate your server app (GAE) against Facebook: you need to implement server-side authentication flow.
See LeanEngine (open-source) for an example implementation: server auth classes.
Once you are past authentication and you get user FB auth token, you can use FB Graph API to get all kinds of data.
Buy a SSL cert for your web server, so you can be compliant with the new rules.
Create/Setup your app to get your app id and secret.
Study up on the Javascript SDK, it's the easiest to implement in my humble opinion.
Study up on the Graph API and learn about the objects and their properties as well as their connections.
You can play around with the JS SDK here: https://developers.facebook.com/tools/console/ and the Graph here: https://developers.facebook.com/tools/explorer
Introduce code slowly to your page on your webserver. First get authentication working, then move on to getting basic user information.
This post { AppSecret with Windows Phone 7 }
indicates that the WP7 sample doesn't use the AppSecret to login from windows phone, but the current sample in the 5.3.2 download does use the secret.
However, FacebookOAuthClient.cs throws exceptions if it isn't provided. Also, http://blog.prabir.me/post/Facebook-CSharp-SDK-Writing-your-first-Facebook-Application.aspx
shows a sample without using the AppSecret.
Reading Facebooks developer docs it appears that the secret is intended for backend (webserver) auth to facebook, not client apps, and that it is poor practice, maybe insecure, and probably fattening to include your secret in your client application.
Do I misunderstand the guidance, or is there some way to authenticate with the facebook-c#-sdk without using the secret?
Thanks!
In WP 7.0 there was a problem with Fragment in Url (all after # was truncated). Facebook return auth token in Url Fragment, so without it it was impossible to authentificate like desktop/mobile app. The solution was to switch to Web mode, where you can receive auth token if you know AppSecret, so it was the only solution for that (but with security gaps).
In WP 7.1 Fragment Url bug was closed and now you can use normal authentification mode (without AppSecret on client).
If you could access anything of mine WITHOUT first having me authorize the app (solely using the app ID without an access token or a app secret), then that would be a HUGE security hole. Not only to my profile, but to any app out there since the app id is public.
The short answer is, you are required to have a user (or other type of) access token or an app secret to get information.
I figured out the problem was not with the SDK, but the Windows Phone 7 sample included. That sample uses the server-side flow. The changes necessary to the example were:
changing:
loginParameters["response_type"] = "code";
to:
loginParameters["response_type"] = "token";
and removing the entire labda function in webBrowser1_Navigated:
...
// The url is the result of OAuth 2.0 authentication.
if (oauthResult.IsSuccess)
{
var oauthClient = new FacebookOAuthClient { AppId = AppId, AppSecret = AppSecret };
// we got the code here
var code = oauthResult.Code;
oauthClient.ExchangeCodeForAccessTokenCompleted +=
(o, args) =>
{
...
and replaced it with this:
if (_fLoginMode && oauthResult.IsSuccess && !string.IsNullOrEmpty(oauthResult.AccessToken))
{
Dispatcher.BeginInvoke(() => NavigationService.Navigate(new Uri("/FacebookInfoPage.xaml?access_token=" + oauthResult.AccessToken, UriKind.Relative)));
}
And, of course removing the AppSecret constant
I will build an iOS application whose functionality will be based on access permissions provided by a Django REST application.
Django manages the permissions for the activities in the iOS app. User A can do Work A if he/she is permitted. Permissions will be queried via ASIHTTPRequest to a REST API served by Django Tastypie.
There is no registration. Users will just be able to login via Twitter. XAuth will be used to present a login screen for users.
There are 2 types of users. For example purposes, there will be Type 1 and Type 2. Type 1 will be ordinary user who can only browse data in the iOS app.
Type 2 user can submit/edit data.
That's it theoretically. However...I don't know where to start!!
The biggest roadblock:
How can I hook Twitter XAuth with Django's user backend via Tastypie?
If I know this then I can query the necessary permissions.
Thanks in advance!
I've done something similar with django + tastypie and facebook login for iOS.
Authentication
Log the user in using whatever means you will, get the access_token.
Create a GET request tastypie endpoint to which you will pass the accesstoken as a query string.
On the server side validate etc... and then create your own internal "tastypie" token and return that in the response to the get request e.g:
class GetToken(ModelResource):
"""
Authenticates the user via facebook and returns an APIToken for them.
"""
class Meta(object):
queryset = ApiKey.objects.all()
resource_name = 'authenticate'
fields = ['user', 'key']
allowed_methods = ['get']
authorization = Authorization()
authentication = FacebookAuthentication()
def prepend_urls(self):
"""We override this to change default behavior
for the API when using GET to actually "create" a resource,
in this case a new session/token."""
return [
url(r"^(?P<resource_name>%s)%s$" % (self._meta.resource_name, trailing_slash()),
self.wrap_view('_create_token'), name="api_get_token"),
]
def _create_token(self, request, **kwargs):
"""Validate using FacebookAuthentication, and create Api Token if authenticated"""
self.method_check(request, allowed=['get'])
# This checks that the user is authenticated on facebook and also creates the user
# if they have not been created.
self.is_authenticated(request)
self.throttle_check(request)
bundle = self.build_bundle(obj=None, request=request)
bundle = self.obj_create(bundle, request, **kwargs)
bundle = self.full_dehydrate(bundle)
self.log_throttled_access(request)
return self.create_response(request, bundle.data)
def obj_create(self, bundle, request=None, **kwargs):
"""Create a new token for the session"""
bundle.obj, created = ApiKey.objects.get_or_create(user=request.user)
return bundle
Pass the returned API key on all subsequent calls, can either be as a query string param again or I set it on the Authorisation header for every call.
Make sure ALL the other resources you want to have authentication on have ApiKeyAuthentication() set in the Meta.
class ThingResource(ModelResource):
class Meta:
queryset = Thing.objects.all()
resource_name = 'thing'
authentication = ApiKeyAuthentication()
Authorisation
So now you know on the server side that the user is who they say they are, what is this user allowed to do? Thats what the authorisation meta is all about.
You probably want Django Authorisation in which case you can just use the normal permissioning schemes for users, or you could roll your own. It's pretty simple.
amrox has a nice example on how to hook a custom fork of django-oauth-plus that supports xAuth into tastypie. I imagine it can be tweaked to suit your purposes.