I am trying to enable server side offline access to Google APIs where the user authenticates from an iOS app. This is to allow a server to have continual access to Google APIs outside of the iOS app.
Google documents the approach below:
https://developers.google.com/identity/sign-in/ios/offline-access
I've followed their documentation exactly with a barebones project. However, whenever I try to exchange the one-time authorization code for access and refresh tokens, I receive a 'redirect_uri_mismatch' error during the exchange.
I've searched forums and a number of folks recommended to configure the Google API project OAuth 2.0 client ID (from Google developer console) with no redirect URIs. However this causes the error 'Missing property "redirect_uris" in a client type of "web"'
I've also tried other OAuth 2.0 client ID types (e.g., Other) but with no luck.
Has anyone been able to get this flow to work? Any help would be greatly appreciated!
I've bumped into this also. Google's example is wrong or at least incomplete. You have to set a redirect uri on the developer console and pass it to the oauth client like so:
credentials = client.credentials_from_clientsecrets_and_code(
CLIENT_SECRET_FILE,
['https://www.googleapis.com/auth/drive.appdata', 'profile', 'email'],
auth_code, None, "your redirect uri")
Full documentation here http://oauth2client.readthedocs.io/en/latest/source/oauth2client.client.html
Set redirect_uri to urn:ietf:wg:oauth:2.0:oob in your code, it is used for installed app. As mentioned by #oravecz over here. This worked for me.
Related
There are several options while setting up a service account. And it is confusing. I'm a beginner as well.
How may i Set-up the service account so that the script will successfully keep posting on blogger as posts.
Or could someone please assist me in setting up the Oauth client. There are two kinds of uri and I'm not sure how to find or create or obtain them. Or if there any way to setup successful authentication with Google so that posts can be created infinitely without any error.
This script will be run in python termux.
Any help is very appreciated.
Yes, i tried setting up this oauth client Id and it didn't work. There are errors. Perhaps because i don't have uris.
I also tried setting up the service account, where after execution of script, it says in termux something like, we are sorry but... Global.... No access... Something like that ...
Im not sure why but when trying to use the following code I get ('Access blocked: This app’s request is invalid' and 'redirect_uri_mismatch') when the browser window opens:
gc = gspread.oauth(
credentials_filename='auth/oauth_creds.json'
)
I have already enabled the needed apis and download the creds for the OAuth client IDs, not sure why I am hitting this error, this is my first time using gspread, in the past I used the normal libs that gspread seems to wrap, but it has been a while.
Redirect uri miss match is one of the most common Oauth2 errors. The redirect uri you have entered in google cloud console for your app must exactly match the one that your application is sending from.
There should be an error details link you can click on it will tell you the exactly redirect uri you should enter into google developer console.
Google OAuth2: How the fix redirect_uri_mismatch error. Part 2 server sided web applications.
I created a Flask-Webservice with Python that runs independently inside a docker container. I then uploaded the docker image to an Azure Container Registry. From there I can create a WebService (for Containers) with some few clicks in the Azure Portal, that runs this container. So far so good. It behaves just as I want it to.
But of course I don't want anyone to access the service. So I need some kind if authentication. Luckily (or so I thought) there is a built-in authentication-mechanism (I think it is based on OAuth ... I am not that well versed in security issues). Its documentation is a bit sparse on what actually happens and also concentrates on solutions in C#.
I first created a project with Google as described here and then configured the WebApp-Authentication with the Client-Id and Secret. I of course gave Google a java script source and callback-url, too.
When I now log off my Google account and try a GET-Request to my Webservice in the Browser (the GET should just return a "hello world"-String), I am greeted with a Login Screen ... just as I expected.
When I now login to Google again, I am redirected to the callback-url in the browser with some kind of information in the parameters.
a token perhaps? It looks something like this:
https://myapp.azurewebsites.net/.auth/login/google/callback?state=redirxxx&code=xxx&authuser=xxx&session_state=xxx&prompt=xxx).
Here something goes wrong, because an error appears.
An error occurred.
Sorry, the page you are looking for is currently unavailable.
Please try again later.
If you are the system administrator of this resource then you should check the error log for details.
Faithfully yours, nginx.
As far as I now, nginx is a server software that hosts my code. I can imagine that it also should handle the authentication process. It obviously lets all requests through to my code when authentication is turned off, but blocks un-authenticated accesses otherwise and redirects to the google login. Google then checks if your account is authorized for the application and redirects you to the callback with the access token along with it. This then returns a cookie which should grant my browser access to the app. (I am just reproducing the documentation here).
So my question is: What goes wrong. Does my Browser not accept the cookie. Did I something wrong when configuring Google+ or the Authentication in the WebApp. Do I have to use a certain development stack to use the authentication. Is it not supported for any of the technologies I use (Python, Flask...).
EDIT
#miknik:
In Microsofts documentation of the authentication/authorization it says
The authentication and authorization module runs in the same sandbox
as your application code. When it's enabled, every incoming HTTP
request passes through it before being handled by your application
code.
...
The module runs separately from your application code and is
configured using app settings. No SDKs, specific languages, or changes
to your application code are required.
So while you are probably right that the information in the callback-redirect is the authorization grant/code and that after that this code should now be used to get an access token from Google, I don't quite understand how this would work in my situation.
As far as I can see it Microsofts WebApp for Container-Resource on Azure should take care of getting the token automatically and return it as part of the response to the callback-request. The documentation states 4 steps:
Sign user in: Redirects client to /.auth/login/.
Post-authentication: Provider redirects client to /.auth/login//callback.
Establish authenticated session: App Service adds authenticated cookie to response.
Serve authenticated content: Client includes authentication cookie in subsequent requests (automatically handled by browser).
It seems to me that step 2 fails and that that would be exactly what you wrote: that the authorization grant is to be used by the server to get the access token but isn't.
But I also don't have any control over that. Perhaps someone could clear things up by correcting me on some other things:
First I can't quite figure out which parts of my problem represent which role in the OAuth-scheme.
I think I am the Owner, and by adding users to the list in the Google+-Project I authorize them to use my service.
Google is obviously the authorization server
my WebService (or better yet my WebApp for Containers) is the resource server
and finally an application or postman that does the requests is the Client
In the descriptions of OAuth I read the problematic step boils down to: the resource server gets the access token from the authorization server and passes it along to the client. And Azures WebApps Resource is prompted (and enabled) to do so by being called with the callback-url. Am I right somewhere in this?
Alas, I agree that I don't quite understand the whole protocol. But I find most descriptions on the net less than helpful because they are not specific to Azure. If anyone knows a good explanation, general or Azure-specific, please make a comment.
I found a way to make it work and I try to explain what went wrong as good as I can. Please correct me if I go wrong or use the wrong words.
As I suspected the problem wasn't so much that I didn't understand OAuth (or at least how Azure manages it) but the inner workings of the Azure WebApp Service (plus some bad programming on my part). Azure runs an own Server and is not using the built-in server of flask. The actual problem was that my flask-program didn't implement a WSGI-Interface. As I could gather this is another standard for python scripts to interact with any server. So while rudimentary calls from the server (I think Azure uses nginx) were possible, more elaborate calls, like the redirect to the callback url went to dev/null.
I build a new app following this tutorial and then secured it by following the authentication/authorization-tutorial and everything worked fine. The code in the tutorial implements WSGI and is probably more conform to what Azure expects. My docker solution was too simple.
My conclusion: read up on this WSGI-standard that flask always warned me about and I didn't listen and implement it in any code that goes beyond fiddeling around in development.
I've created a project in Google Cloud Console, and I'm pretty sure my AppEngine project is associated with it (clicking on the AppEngine link in the project shows an overview of my AppEngine project).
I've uploaded my project to run on appspot.com.
I've properly copied and pasted the console project's OAuth2 client secret and id to be used by the Python library.
I've properly setup the consent screen.
I've added the callback urls.
I've made sure that the appropriate API's are turned "ON" and green (Google Drive).
But I'm still getting Error: invalid_client when trying to authenticate.
What did I miss?
EDIT: Here's the url where it goes wrong
https://accounts.google.com/o/oauth2/auth?state=https%3A%2F%2Fmy-app-id.appspot.com%2Fspreadsheet%2Fview%2F0Ao7HHtqOGzZ7dDNneTg0b1R0bnVJNzRvWk9DVVhIVXc%3A9wi8bS1R7fejjVuDd9IdPjoxMzg0NjgyNDU5&redirect_uri=https%3A%2F%2Fmy-app-id.appspot.com%2Foauth2callback&response_type=code&client_id=abcxyz123.apps.googleusercontent.com&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive.readonly&access_type=offline
and the following text (with an image of a broken robot):
Request Details
cookie_policy_enforce=false
response_type=code
scope=https://www.googleapis.com/auth/drive.readonly
redirect_uri=https://my-app-id.appspot.com/oauth2callback
access_type=offline
state=https://my-app-id.appspot.com/spreadsheet/view/0Ao7HHtqOGzZ7dDNneTg0b1R0bnVJNzRvWk9DVVhIVXc:9wi8bS1R7fejjVuDd9IdPjoxMzg0NjgyNDU5
client_id=abcxyz123.apps.googleusercontent.com
Have you enabled the Drive API? The link to do this is more obvious if you use the old form of the API Console (see the faint grey link at the bottom of the new API Console page).
Otherwise, if you did what you said you did, you haven't missed anything.
For any Oauth problems such as this, it is immensely helpful to paste the http request and response into your question. This page tells you how to do that https://developers.google.com/api-client-library/python/guide/logging
A really good debugging technique is to put your code to one side and use the Oauth2 Playground (with your own application credentials configured). You can compare the http traffic from the Oauth playground with the traffic from your app, and play spot-the-difference.
I'm using the Google AppEngine 1.3.4 SDK which offers to allow your application to act as a OAuth service provider (http://code.google.com/appengine/docs/python/oauth/). Setting up a standard application on my localhost and using the following:
Request URL /_ah/OAuthGetRequestToken
Authorize URL /_ah/OAuthAuthorizeToken
Access Token URL /_ah/OAuthGetAccessToken
The client application just gets sent to a page requesting to grant OAuth access even though no user is logged in. Clicking 'Grant access' results in a message saying 'OAuth access granted' with no tokens or anything exchange. Can't see how this could work when it's not even prompting for a login.
As this functionality is quite new I can't find much out there. I've created a OAuth provider before in Rails and know that you need a Consumer Key and Secret, something that seems to be lacking in GAE?
Any ideas on how to get OAuth working in a sample GAE project are most welcome.
I would hazard a guess that the SDK implementation simply grants access regardless. It's also possible you still have a dev_appserver login cookie. Either way, try it in production - it'll almost certainly request login in that case.