"invalid_scope" when trying to get oauth2 access token - google-photos

I'm following the docs at https://developers.google.com/photos/library/guides/authentication-authorization, and believe the below code is quite close to correct ...
import requests
# from https://developers.google.com/identity/protocols/OAuth2ForDevices#step-1-request-device-and-user-codes
def get_token(client_id="661666866149-42r2bldb8karc5bv5vltj0suis2fm4up.apps.googleusercontent.com"):
response = requests.post(
'https://accounts.google.com/o/oauth2/device/code',
data={
'client_id': client_id,
'scope': 'https://www.googleapis.com/auth/photoslibrary https://www.googleapis.com/auth/photoslibrary.readonly.appcreateddata https://www.googleapis.com/auth/photoslibrary.sharing'
})
print(response.text)
return response
The above keeps failing with
{
"error": "invalid_scope"
}
<Response [400]>
However, if I change the scope value to just email, that works. I got the value above from google's docs, so I don't know what else to put there.

It looks like you are following the guide for OAuth 2.0 for TV and Limited-Input Device Applications to authorize OAuth user scopes on a TV or similar device.
As outlined on that page, this flow only supports a limited set of scopes. Unfortunately this does not currently include the Google Photos Library API scopes.
There's a feature request open on the issue tracker to add support for this OAuth flow here: https://issuetracker.google.com/113342106 (You can "star" the issue to be notified of any updates.)
(If your flow involves a mobile device and a server component, you might be able to accomplish something similar with Google sign-in by exchanging user credentials between your server and Google Services. You could prompt users to authorize the scope in your app and after exchanging tokens with your server, make API calls that way. You'd have to handle the link between the TV/limited-input device and your app yourself.)

Related

How OAuth authorization works via API

It is clear how to get a token from Google(or any other OAuth provider). But I do not understand where shoud I do it - server part or client part.
For example: I have a backend on Flask with unified API for Android, iOS and web(js/react) apps.
Where do I need to get a token? On the client (Android for example) part and send it to server or in my Flask app after request from client? Where should I get data from provider? How at all works interaction between client and server while using OAuth?
Would be pleased for some explanations or links on some guides
Your UIs will manage redirecting the user to authenticate - after which the UI is given an access token to call the API with.
The OAuth provider is the entry point for authentication and issues an access token afterwards.
The API uses the access token to identify the user and authorize access to resources.
A good way to understand OAuth is the HTTP messages - my blog post highlights these, and they are largely the same for SPAs and mobile.
There are also some code samples on my blog which you can run, in case useful.

Facebook Api Check Access Token Without Hardcoding App Secret

I'm building a manual login flow for my App which is integrating some facebook functionality.
I need to check when the current access_token of the user will expire.
The API documentary says I should do this call:
GET graph.facebook.com/debug_token?
input_token={token-to-inspect} &access_token={app-token-or-admin-token}
So I did this in C#:
Uri inspectAccessTokenUri = new Uri("http://graph.facebook.com/debug_token?input_token="+access_token+"&"); //IDK which value should have the last parameter
HttpWebRequest checkToken = (HttpWebRequest)WebRequest.Create(inspectAccessTokenUri);
var response = await checkToken.GetResponseAsync();
Stream stream = response.GetResponseStream();
StreamReader reader = new StreamReader(stream);
string data = reader.ReadToEnd();
Debug.WriteLine(data);
The last parameter should be the app-token:
BUT: Of course I looked up how to get the app-token and facebook says:
Note that because this request uses your app secret, it must never be
made in client-side code or in an app binary that could be decompiled.
It is important that your app secret is never shared with anyone.
Therefore, this API call should only be made using server-side code.
(Facebook Graph API Documentation 1.1.16)
So my question: Can I check the token without the app-token or hardcoding the app-secret?
App secret is usually used by the server-side app, we don't use it in our UWP app, it could be decompiled.
Read the official doc about FB Graph Debug-Token, this can only be used when you debug your app, for example if you want to check the metadata about a given access token, after you publish your app, your code will not relay on it.
In an UWP app, we use WebAuthenticationBroker class to connect to OAuth providers such as Facebook, Flickr, Google, and Twitter. Maintenance is need during using OAuth connections. For example, expires information is included in the access token, when we use OAuth protocol for authentication and authorization, we need to refresh the access token after it expired.
Due to these conditions, you may reconsider what you can do in an UWP app and which API you should choose.
If the app-token is expired you will get a facebook response error. And you can catch this exception to deal with the situation you want. In this way you don't need to make a request with your app secret.
You can also use fb-uwp sdk that contains AccessTokenData for authenticated users

Generate an OAuth2 token in a view

Let's say I have an AngularJS application that consumes the REST API of a Django application.
The Django application has got a built-in OAuth2 provider that can be called to retrieve an access token and use the protected endpoints of the API. This provider is using django-oauth-toolkit.
Let's assume there is a registered client with "password" grant type, so that the end users only need to provide their credentials in the front-end in order to get an access token from the back-end.
At some point we want to add some support for social networks login and we decide to use python-social-auth (PSA) to that end. Here is the workflow I want to achieve:
The user logs in on Facebook from the front-end (via the Facebook SDK) and we get an access token back from the OAuth2 provider of Facebook.
We send the Facebook token to an endpoint of our REST API. This endpoint uses the Facebook token and django-social-auth to authenticate the user in our Django application (basically matching a Facebook account to a standard account within the app).
If the authentication succeeds, the API endpoint requests an access token from the OAuth2 provider for this newly authenticated user.
The Django access token is sent back to the front-end and can be used to access the REST API in exactly the same way that a regular user (i.e. logged in with his credentials) would do.
Now my problem is: how do I achieve step 3? I first thought I would register a separate OAuth2 client with Client Credentials Grant but then the generated token is not user-specific so it does not make sense. Another option is to use the TokenAuthentication from DRF but that would add too much complexity to my project. I already have an OAuth server and I don't want to set up a second token provider to circumvent my problem, unless this is the only solution.
I think my understanding of PSA and django-oauth-toolkit is not deep enough to find the best way of reaching my goal, but there must be a way. Help!
I managed to get something working using urllib2. I can't speak towards whether or not this is good practice, but I can successfully generate an OAuth2 token within a view.
Normally when I'd generate an access token with cURL, it'd look like this:
curl -X POST -d "grant_type=password&username=<user_name>&password=<password>" -u"<client_id>:<client_secret>" http://localhost:8000/o/token/
So we're tasked with making urllib2 accomplish this. After playing around for some bit, it is fairly straightforward.
import urllib, urlib2, base64, json
# Housekeeping
token_url = 'http://localhost:8000/auth/token/'
data = urllib.urlencode({'grant_type':'password', 'username':<username>, 'password':<password>})
authentication = base64.b64encode('%s:%s' % (<client_id>, <client_secret>))
# Down to Business
request = urllib2.Request(token_url, data)
request.add_header("Authorization", "Basic %s" % authentication)
access_credentials = urllib2.urlopen(request)
json_credentials = json.load(access_credentials)
I reiterate, I do not know if this is in bad practice and I have not looked into whether or not this causes any issues with Django. AFAIK this will do this trick (as it did for me).

Django-allauth, JWT, Oauth

I have an AngularJS Single Page Application that uses a Django backend API based on the Django Rest Framework. The API is protected via django-rest-framework-jwt. I would like to use django-allauth for account management and authentication on the server side.
I am just missing one single piece in the flow: How does my Oauth-Token from the client get transferred into a JWT-token? Basically, I would like to do as described here http://blog.wizer.fr/2013/11/angularjs-facebook-with-a-django-rest-api/ based on python-social-auth.
So my question is, how do I implement the ObtainAuthToken class from the link with django-allauth?
There are usually two login flows with social login: client-side ("Javascript SDK") and server-side. If your server needs to be authorised, it's usually a lot easier to go through the server-side flow. And that's also what all-auth does I think (and you didn't mention you use a frontend library like the blogpost you mentioned does).
Now the challenge is to provide the token from the server to the frontend. You would probably load the token in the HTML of the initialisation of the SPA, and then from Angular save the token client side (cookie, localStorage, etc.) so the session isn't lost on a refresh.
If you don't want the user to leave your app, you can open your /accounts/login/ or /accounts/signup/ url in a new window. In that new window they authorise your app, and your server receives the token upon return. There, you will have to generate a JWT token manually, and render that into the template so that javascript can access it. With js in that popup window, you can then communicate with your app that opened the popup and pass it the token – see this SO answer for an example – so it can save it.
Django-allauth provides signals that let you hook into the social login process. In your case, I would recommend subscribing to the allauth.socialaccount.signals.pre_social_login signal. The code will look something like this:
from allauth.socialaccount.signals import pre_social_login
#receiver(pre_social_login)
def create_jwt_token(sender, request, sociallogin, **kwargs):
# dig into the sociallogin object to find the new access token.
We used hello.js for O-Auth at the company I worked at.
You provide a shim on the Python end and get the refresh token and whatever other data needed once the user connects their social account.
We redirect them via Django to the page they attempted to access from their OAuth provider's page.
Each user still has their own email account which is needed for the JWT, but you could assume that whatever email is in the scope of their social account is their email then use django's functionality to create new users: User.objects.create(email=emailStringFromOauthData) etc.

dropbox api usage in django apps, how?

Could someone show some example about using dropbox api with django?
Dropbox api is installed, readme is done, tests are done, how to go further?
Yes, you need to understand, how oauth works.
Consider the use-case, when you are trying to store uploaded files directly on user's dropbox account.
First of all, you have to register a developer account on dropbox site.
In your django views, a typical workflow is this:
ask dropbox for a request token, (it
notifies them that you will use
their api soon)
dba = auth.Authenticator(app_settings.CONFIG)
request_token = dba.obtain_request_token()
it's in the api's documentation how to
set up the config file
than you build an authentication url:
authorize_url = dba.build_authorize_url(request_token, callback='http://...'
the user sign in at dropbox.com, than
redirected back to your site
you should store now the request
token, but it's only useful to get the
access token!
you use the request token to get an
access token, it's now unique to the
user.
access_token = dba.obtain_access_token(request_token, 'verifier')
leave the verifier blank, it's preserved do future usage!
store the access token, you need it in any further operation(per session)
here you are! you should instantiate a client, it's defined
in the python-specific dropbox
package
drpbx_client = client.DropboxClient('server','content_server','port',dba,access_token)
the client is a helper object for file operations:
drpbx_client.put_file('dropbox', '/porn/', request.FILES['file'])
You must use the Dropbox REST api:
http://www.dropbox.com/developers/docs#api-specification
It uses oauth for authentication. Detailed guide and walkthrough can be found here:
http://hueniverse.com/oauth/