Closed Lepiloff closed 5 years ago
Hi @Lepiloff,
It looks like you're using InstalledAppFlow
, which is for applications installed on devices. It sounds like you are developing a web server application?
run_local_server
uses a default host of localhost
for the redirect_uri, which is fine when you run the project locally but won't work once your project is deployed.
Please take a look at the Python documentation for the OAuth2 Web Server flow. There are code snippets and a complete example using flask that should be helpful.
Please do let us know if you have additional questions.
@busunkim96 thank you for answering.
Yes, I use web server application. Google API documentation in some places not very clear. Now I know that run_local_server
uses only for locall projects. It is very strange that there are no good examples on the Internet for using Django and Google API for my purposes. I will try to deal with this problem
I'm trying to change the code according to the link you gave me. My code
import google_auth_oauthlib.flow
from googleapiclient.discovery import build
from django.urls import reverse
from django.http import HttpResponse, HttpResponseRedirect
import os
os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'
SCOPES = 'https://www.googleapis.com/auth/drive'
cred = os.path.join(settings.BASE_DIR, 'credentials.json')
Function for upload file:
def file_to_drive(request, import_file=None):
state = request.session['state']
if state is None:
authorize(request)
else:
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
cred, scopes=SCOPES, state=state)
flow.redirect_uri = "http://localhost:8000/oauth2callback"
authorization_response = request.build_absolute_uri()
flow.fetch_token(authorization_response=authorization_response)
credentials = flow.credentials
service = build('drive', 'v3', credentials=credentials)
file_metadata = {
'name': 'My Report',
'mimeType': 'application/vnd.google-apps.spreadsheet'
}
media = MediaFileUpload(import_file,
mimetype='text/html',
resumable=True)
file = service.files().create(body=file_metadata,
media_body=media,
fields='id').execute()
print('File ID: %s' % file.get('id'))
return (f"https://docs.google.com/document/d/{file.get('id')}/edit")
And function for user authorization
def authorize(request):
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
cred, scopes=SCOPES)
flow.redirect_uri = "http://localhost:8000/oauth2callback"
authorization_url, state = flow.authorization_url(
access_type='offline',
include_granted_scopes='true')
request.session['state'] = state
return HttpResponseRedirect(authorization_url)
urls.py
path('oauth2callback', authorize, name='authorize'),
path('to_drive', file_to_drive, name='file_to_drive'),
In function file_to_drive
searching for the value of the state
parameter from the session, if it is not found, the authorize
function is called. In the end, I get a message
oauthlib.oauth2.rfc6749.errors.MismatchingStateError: (mismatching_state) CSRF Warning! State not equal in request and response.
Error traseback
File "/home/y700/projects/CV/cv-base/ems/base/utils.py", line 119, in file_to_drive
flow.fetch_token(authorization_response=authorization_response)
File "/home/y700/Env/cv-base-XRtgVf2K/lib/python3.7/site-packages/google_auth_oauthlib/flow.py", line 263, in fetch_token
self.client_config['token_uri'], **kwargs)
File "/home/y700/Env/cv-base-XRtgVf2K/lib/python3.7/site-packages/requests_oauthlib/oauth2_session.py", line 208, in fetch_token
state=self._state)
File "/home/y700/Env/cv-base-XRtgVf2K/lib/python3.7/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/y700/Env/cv-base-XRtgVf2K/lib/python3.7/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.
[13/Sep/2019 13:19:52] "GET /to_drive HTTP/1.1" 500 98701
the error is caused by a string
flow.fetch_token(authorization_response=authorization_response)
Hi @Lepiloff. It looks like you're getting an error about mismatching states. There is a bit more info about state here in the description of the parameters. State needs to match in the request and response.
I think you'll want to write one more function.
In the flask example down towards the bottom of the page, you'll see there are two routes for the OAuth flow.
/authorize
is called to initiate the authorization flow. It concludes by redirecting the user to the Google OAuth2 server. The state is stored in the session This state is used later in the callback.
@app.route('/authorize')
def authorize():
# Create flow instance to manage the OAuth 2.0 Authorization Grant Flow steps.
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
CLIENT_SECRETS_FILE, scopes=SCOPES)
# The URI created here must exactly match one of the authorized redirect URIs
# for the OAuth 2.0 client, which you configured in the API Console. If this
# value doesn't match an authorized URI, you will get a 'redirect_uri_mismatch'
# error.
flow.redirect_uri = flask.url_for('oauth2callback', _external=True)
authorization_url, state = flow.authorization_url(
# Enable offline access so that you can refresh an access token without
# re-prompting the user for permission. Recommended for web server apps.
access_type='offline',
# Enable incremental authorization. Recommended as a best practice.
include_granted_scopes='true')
# Store the state so the callback can verify the auth server response.
flask.session['state'] = state
return flask.redirect(authorization_url)
/oauth2callback
processes the response from the OAuth2 server. This is where the user is sent after they've authorized your app. The state is verified in the authorization server response.
@app.route('/oauth2callback')
def oauth2callback():
# Specify the state when creating the flow in the callback so that it can
# verified in the authorization server response.
state = flask.session['state']
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
CLIENT_SECRETS_FILE, scopes=SCOPES, state=state)
flow.redirect_uri = flask.url_for('oauth2callback', _external=True)
# Use the authorization server's response to fetch the OAuth 2.0 tokens.
authorization_response = flask.request.url
flow.fetch_token(authorization_response=authorization_response)
# Store credentials in the session.
# ACTION ITEM: In a production app, you likely want to save these
# credentials in a persistent database instead.
credentials = flow.credentials
flask.session['credentials'] = credentials_to_dict(credentials)
return flask.redirect(flask.url_for('test_api_request'))
Closing due to lack of activity. Please file a new issue if you are experiencing this problem.
Gracias ^^
Hello All, Please let me know if anybody has any example for Django with Youtube Data API.
Hey @Lepiloff can you help me regarding this, how do you solve the problem you are facing, like how do you implement the code for web server using python. I am not able to get any relatable answer on the entire internet. Actually I want to send mails to users using gmail api. And it is running fine on localhost( using desktop application), but when I moved this to my server it started showing me the error [Errno 98] Address already in use
. But the port I am activating for the authentication is an empty port on my server.
Hey @Lepiloff can you help me regarding this, how do you solve the problem you are facing, like how do you implement the code for web server using python. I am not able to get any relatable answer on the entire internet. Actually I want to send mails to users using gmail api. And it is running fine on localhost( using desktop application), but when I moved this to my server it started showing me the error
[Errno 98] Address already in use
. But the port I am activating for the authentication is an empty port on my server.
hi dhwaj1902, I have the same issue when deploy my app to server, do you have a solution for this yet?
When developing on a local machine I used standart code to authorize and work with Google disk
I use 8080 as the port parameter value. This works. When deploying a project on a production server, I get a message port is already in use.
Server: Ubuntu 18.04, Nginx, uwsgi, Django
I've changed the port to 5000, everything works on the local machine. I tried to run it on a production server and got a 504 error. I checked the uwsgi log and saw that the end of the file contains a link to authorization.
On the local machine, this link automatically opens in a new window to log on to the account. If try to run the production server again, I will get the [Errno 98] Address already in use error and this error is saved until reboot uwsgi. After the reboot, everything repeats itself again.
I've tried many different port meanings, the same problem with everyone. I think the problem here is not in the specific meaning. After restart uwsgi there is an attempt of authorization (i.e. the value of the port is accepted) but the redirection by reference to OAuth2 does not occur. And it's quite strange that when try again, the error
[Errno 98] Address already in use
What values should I use?