Reputation: 235
I want to create an application that will have read only access to multiple users calendar events. However, I constantly fail to pass through authentication step. Browser opens new consent screen with Error 400: redirect_uri_mismatch. Here is what i did:
For this I set up my project in google console. I did following:
{"web":
{
"client_id":"123234-jjjjj.apps.googleusercontent.com",
"project_id":"ppppp-1234",
"auth_uri":"https://accounts.google.com/o/oauth2/auth",
"token_uri":"https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs",
"client_secret":"zzzzzzzzzzzzzzzzzz",
"redirect_uris":["http://localhost:8080"],
"javascript_origins":["http://localhost"]
}
}
I use following code to call google API:
import pickle
import os
from google_auth_oauthlib.flow import Flow, InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.http import MediaFileUpload
from google.auth.transport.requests import Request
def Create_Service(client_secret_file, api_name, api_version, *scopes):
CLIENT_SECRET_FILE = client_secret_file
API_SERVICE_NAME = api_name
API_VERSION = api_version
SCOPES = [scope for scope in scopes[0]]
cred = None
pickle_file = f'token_{API_SERVICE_NAME}_{API_VERSION}.pickle'
if os.path.exists(pickle_file):
with open(pickle_file, 'rb') as token:
cred = pickle.load(token)
if not cred or not cred.valid:
if cred and cred.expired and cred.refresh_token:
cred.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(CLIENT_SECRET_FILE, SCOPES)
cred = flow.run_local_server()
with open(pickle_file, 'wb') as token:
pickle.dump(cred, token)
try:
service = build(API_SERVICE_NAME, API_VERSION, credentials=cred)
print(API_SERVICE_NAME, 'service created successfully')
return service
except Exception as e:
print(e)
return None
CLIENT_SECRET_FILE = 'token.json'
API_NAME = 'calendar'
API_VERSION = 'v3'
SCOPES = ['https://www.googleapis.com/auth/calendar.events.readonly']
service = Create_Service(CLIENT_SECRET_FILE, API_NAME, API_VERSION, SCOPES)
colors = service.colors().get().execute()
print(colors)
When I run it, browser opens a consent screen with
Error 400: redirect_uri_mismatch. Then I follow http://localhost:8080/ and I see message "The authentication flow has completed. You may close this window."
And in the console I see following errors:
File "main.py", line 48, in <module>
service = Create_Service(CLIENT_SECRET_FILE, API_NAME, API_VERSION, SCOPES)
File "main.py", line 29, in Create_Service
cred = flow.run_local_server()
File "/home/ev/Projects/TIM/web/.venv/lib/python3.8/site-packages/google_auth_oauthlib/flow.py", line 480, in run_local_server
self.fetch_token(authorization_response=authorization_response)
File "/home/ev/Projects/TIM/web/.venv/lib/python3.8/site-packages/google_auth_oauthlib/flow.py", line 288, in fetch_token
return self.oauth2session.fetch_token(self.client_config["token_uri"], **kwargs)
File "/home/ev/Projects/TIM/web/.venv/lib/python3.8/site-packages/requests_oauthlib/oauth2_session.py", line 239, in fetch_token
self._client.parse_request_uri_response(
File "/home/ev/Projects/TIM/web/.venv/lib/python3.8/site-packages/oauthlib/oauth2/rfc6749/clients/web_application.py", line 203, in parse_request_uri_response
response = parse_authorization_code_response(uri, state=state)
File "/home/ev/Projects/TIM/web/.venv/lib/python3.8/site-packages/oauthlib/oauth2/rfc6749/parameters.py", line 268, in parse_authorization_code_response
raise MismatchingStateError()
oauthlib.oauth2.rfc6749.errors.MismatchingStateError: (mismatching_state) CSRF Warning! State not equal in request and response.
So, the question how to authenticate to google API via OAuth 2.0 in a correct way?
Upvotes: 1
Views: 6641
Reputation: 116868
redirect_uri_mismatch
The redirect uri is used by Web applications to denote the location that your application is prepared to accept the authorization response from googles authorization server. It is basically a URL on the web server prepared to respond to authorization. Redirect uris are only used in with web applications.
In your case you are creating an installed application InstalledAppFlow
in which case you should have created installed (Desktop) credentials on Google developer console. Desktop clients are able to accept the authorization responds from the location they are sending from this being most often localhost and so the authorization server just returns the token back to where the call originated from.
As your code is intended to run as an installed application by giving it web application credentials, will cause it to fail, due to the fact that the application is not sending the proper request.
I have a video here which will show you how to create How to create Google Oauth2 installed application credentials on google developer console.
Upvotes: 2