Google Oauth2 refresh token error using python-social-auth - google-oauth

I'm using python-social-auth and when I try to refresh my Google Oauth2 access token I get the following error:
[2017-02-15 14:41:00,089: ERROR/MainProcess] Task tasks.tasks.test_login[169e5810-489d-4134-af8f-db3b80629fd2] raised unexpected: HTTPError(u'400 Client Error: Bad Request for url: https://accounts.google.com/o/oauth2/token',)
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/celery/app/trace.py", line 240, in trace_task
R = retval = fun(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/celery/app/trace.py", line 438, in __protected_call__
return self.run(*args, **kwargs)
File "/home/paulozullu/dev/workspaces/wopik/wopik/tasks/tasks.py", line 1928, in test_login
social.refresh_token(strategy)
File "/usr/local/lib/python2.7/dist-packages/social/storage/base.py", line 54, in refresh_token
response = backend.refresh_token(token, *args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/social/backends/oauth.py", line 418, in refresh_token
request = self.request(url, **request_args)
File "/usr/local/lib/python2.7/dist-packages/social/backends/base.py", line 225, in request
response.raise_for_status()
File "/usr/local/lib/python2.7/dist-packages/requests/models.py", line 909, in raise_for_status
raise HTTPError(http_error_msg, response=self)
HTTPError: 400 Client Error: Bad Request for url: https://accounts.google.com/o/oauth2/token
I use the following code to refresh the access token:
from social.apps.django_app.utils import load_strategy
w_user = WUser.objects.get(auth_user=A('username','xxxx'))
social = UserSocialAuth.objects.get(user_id=w_user.auth_user.id)
strategy = load_strategy()
social.refresh_token(strategy)
Am I doing something wrong?

I had the same problem when calling social.get_access_token(load_strategy()). If you don't want to implement Google sign-in manually, I used this workaround which forces the user to re-authenticate to refresh their tokens.
try:
strategy = load_strategy()
access_token = social.get_access_token(ls)
except HTTPError as e:
return HttpResponseRedirect(reverse('social:begin', kwargs={'backend': "google-oauth2"}))

As yilmazhuseyin pointed above, the issue is related to refresh token not being present. You need to pass access_type='offline' in the parameters in order for Google to return the refresh token. This can be done by adding the following in settings.py for python-social-auth in django:
SOCIAL_AUTH_GOOGLE_OAUTH2_AUTH_EXTRA_ARGUMENTS = {
'access_type': 'offline',
}
More details can be found in Google OAuth 2.0 documentation.

Related

Unable to signup user from custom mobile App

Please guide.
Creating a new mobile app, not able to signup! Returns some error while tryting to call /web/signup and also while directly calling res.users create as sudo.
Please see the error message
The above exception was the direct cause of the following exception:
Traceback (most recent call last): File
"/odoo/odoo-server/odoo/http.py", line 640, in _handle_exception
return super(JsonRequest, self)._handle_exception(exception) File
"/odoo/odoo-server/odoo/http.py", line 316, in _handle_exception raise
exception.with_traceback(None) from
new_causepsycopg2.errors.UndefinedFunction: operator does not exist:
integer = booleanLINE 6: AND (p.company_id=false OR p.company_id ...
Seems this error raised from _get_multi function in ir_property.py
Thanks in advance
I use a custom controller for receiving request from mobile app and tries to call Odoo Core signup (do_signup located in auth_signup/controller/main) function. It reaches up to there and exceution moves to ir_property and returns error as mentioned.
Please see the sample code which try to use
user = {
'name' : user_info['name'],
'phone': user_info['phone'],
'email': 'test#example.com',#user_info['email'] ,
'login': user_info['phone'],
'password': password,
'confirm_password': password,
}
user_info = AuthSignupHome().do_signup(user)
But /web/signup it's a website service type='http'. You need a controller type='json' for call it from your custom mobile app.
I hope this answer can help you.

python configparser key error raised when using Globally

When I'm trying to pass the API endpoint values in the post API file, KeryError has unfortunately been raised. In the baseapi.ini file, I wrote [API] endpoint = value
Post API file:
import requests
from APIs.payLoad import addBookPayload
from Utilities.configration import config
from Utilities.resources import *
url = config()['API']['endpoint']+ApiResources.addBook
header = {"Content-Type": "application/json"}
response = requests.post(url, json=addBookPayload("pl74"), headers=header,)
print(response.json())
response_json = response.json()
book_ID = response_json['ID']
Error:
Traceback (most recent call last):
File "C:\Users\Muhammad Azmul Haq\PycharmProjects\BackEndProject\APIs\PostAPI.py", line 8, in <module>
url = config()['API']['endpoint']+ApiResources.addBook
File "C:\Users\Muhammad Azmul Haq\AppData\Local\Programs\Python\Python39\lib\configparser.py", line 960, in __getitem__
raise KeyError(key)
KeyError: 'API'
Does anyone have an idea what I did wrong Kind regards?
You are not initializing your global variable in config before accessing it. Try assigning value in the current file,
or
Put all configure in the separate configuration file and import that configuration file.

How to read an image sent in body of req in falcon

Sending jpg image in body of POST, using postman to do so:
Reading it with
image_text_similarity.py:
import json
class ImageTextSimilarity():
def on_post(self, req, resp):
image_raw = json.loads(req.stream.read())
which errors out with
Traceback (most recent call last):
File "/home/dario/.local/lib/python3.6/site-packages/gunicorn/workers/sync.py", line 134, in handle
self.handle_request(listener, req, client, addr)
File "/home/dario/.local/lib/python3.6/site-packages/gunicorn/workers/sync.py", line 175, in handle_request
respiter = self.wsgi(environ, resp.start_response)
File "falcon/api.py", line 274, in falcon.api.API.__call__
File "falcon/api.py", line 269, in falcon.api.API.__call__
File "/home/dario/ImageTextSimilarityApp/image_text_similarity.py", line 95, in on_post
image_raw = json.loads(req.stream.read())
File "/usr/lib/python3.6/json/__init__.py", line 349, in loads
s = s.decode(detect_encoding(s), 'surrogatepass')
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte
How do we read the image from the body of the POST request?
Rest of the code is
image_similarity_app.py:
import falcon
from image_text_similarity import ImageTextSimilarity
api = application = falcon.API()
api.req_options.auto_parse_form_urlencoded = True
image_text_similarity_object = ImageTextSimilarity()
api.add_route('/image_text_similarity', image_text_similarity_object)
And starting the service with gunicorn image_similarity_app
I'm not an expert at Postman, but it appears that by choosing binary, you are sending your JPEG image data as the request body: Postman Chrome: What is the difference between form-data, x-www-form-urlencoded and raw
In Falcon, you can simply read the request payload as
jpeg_data = req.stream.read()
(Note that on some app servers such as the stdlib's wsgiref.simple_server, you may need to use the safe Request.bounded_stream wrapper.)
See also Falcon's WSGI and ASGI tutorials for inspiration; they use are very related topic (building an image service) to illustrate the basic concepts of the framework. You'll find examples how to handle RESTful image resources: upload, convert, store, list, serve, cache etc.

bot.sendAudio and bot.sendPhoto methods in telepot return { 'error code' : 400 , 'Bad Request: wrong HTTP URL specified'}

I am using the
telepot.Bot(bot_id).sendAudio(chat_id, file_url)
method, is supposed to send the file, but it returns
Traceback (most recent call last):
File "C:\Users\vinu\AppData\Local\Programs\Python\Python37\lib\site-packages\telepot\__init__.py", line 1158, in collector
callback(item)
File "bot.py", line 72, in handle
bot.sendAudio(chat_id, url)
File "C:\Users\vinu\AppData\Local\Programs\Python\Python37\lib\site-packages\telepot\__init__.py", line 556, in sendAudio
return self._api_request_with_file('sendAudio', _rectify(p), 'audio', audio)
File "C:\Users\vinu\AppData\Local\Programs\Python\Python37\lib\site-packages\telepot\__init__.py", line 496, in _api_request_with_file
return self._api_request(method, _rectify(params), **kwargs)
File "C:\Users\vinu\AppData\Local\Programs\Python\Python37\lib\site-packages\telepot\__init__.py", line 491, in _api_request
return api.request((self._token, method, params, files), **kwargs)
File "C:\Users\vinu\AppData\Local\Programs\Python\Python37\lib\site-packages\telepot\api.py", line 155, in request
return _parse(r)
File "C:\Users\vinu\AppData\Local\Programs\Python\Python37\lib\site-packages\telepot\api.py", line 150, in _parse
raise exception.TelegramError(description, error_code, data)
telepot.exception.TelegramError: ('Bad Request: wrong HTTP URL specified', 400, {'ok': False, 'error_code': 400, 'description': 'Bad Request: wrong HTTP URL specified'})
the same happened with sendPhoto, but I used python requests to send photos
response =requests.post('https://api.telegram.org/bot/sendphoto', files=files`)
I either want to know why the sendAudio() and sendPhoto() methods work or the http url to send audio
with telepot bot.SendPhoto and bot.sendVideo and bot.sendAudio work either with files and urls that contains a file.
In your case it seems that you used and url and it was uncorrect, can you share it?
In my experience it can be because the url contains & instead of &

flask-jwt-extended current_user identity = None when creating non-fresh access token from refresh token

In my flask app (python 2.7), I am trying to trigger the access token to refresh via the refresh token whenever it expires with the #jwt.expired_token_loader decorator. Both the access token and refresh token are stored in a cookie (JWT_TOKEN_LOCATION = 'cookies').
I am utilizing the same code provided in the documentation (https://flask-jwt-extended.readthedocs.io/en/latest/tokens_in_cookies.html) to do this and I am able to successfully generate a new access token. However, upon generation of a new access token the identity claim of the access token is equal to None (get_raw_jwt()). No matter what I do to the refresh token or the access token whenever I print the jwt_claims or attempt to grab the current user with current_user = get_jwt_identity() it returns the identity as None. It is important for me to know which user is submitting queries to the Neural Net so I can properly keep track of which queries were submitted by what users (one-to-many relationship).
I have tried troubleshooting (decoding) the refresh_token and I ran into a separate issue: When I try to decode the refresh_token, with decode_token(), I get a long traceback that ends in InvalidSignatureError: Signature verification failed. I took the refresh_token and ran it through https://jwt.io and it decodes the token. I can see in the decoded token that the "identity" claim is providing me the user's identity, but it tells me that the token is not verified. However, once I check the secret base64 encoded box on the screen the signature becomes verified and the signature portion of the jwt changed along with it. I attempt to decode this modified jwt that https://jwt.io provided me with the decode_token function and it still provides me the same error: InvalidSignatureError: Signature verification failed.
I have spent hours reading everything google provides me on flask-jet-extended and PyJWT and I cannot figure out how to fix it. I have tried modifying my JWT_SECRET_KEY configuration to different strings and even encoding it with base64 and none of this solves the issues. I have turned on and off the JWT_COOKIE_CSRF_PROTECT configuration. I have turned on and off JWT_ACCESS_COOKIE_PATH and JWT_REFRESH_COOKIE_PATH.I have tried to decode both the refresh_token_cookie and CSRF_refresh_token cookie. I have attempted to run decode_token() with the refresh_token_cookie and CSRF_refresh_token cookie while providing the csrf_value=request.cookies.get('csrftoken') argument. I have tried using the decode() function from jwt directly (
from jwt import decode).
I just don't know what else to do and cannot find any additional online resources. Any help is much appreciated!!
My next step is either to move my authentication system to flask-jet-simple or PyJWT. I really want to use JWT to authenticate my users. I do not know how to combine JWT with flask-login or if this is even possible. I can't manage to find any resources online where someone has utilized flask-login with JWT. I did find a fairly recent repo called flask-jwt-login that I might try to use if I can't figure this out. Ultimately I would like to stay with flask-jwt-extended. I have other parts of this web app I need to focus on and want to get his part squared away.
Anyways, here is my code, the workflow starts on the /login page. This will redirect you to the /NN page. Once the access token expires, if you try to reload the /NN page it will reroute itself to the /token/refresh page. Once it refreshes the token, it will return back to the /NN page.
Please let me know if I need to upload any additional files.
P.S. This is my first post on stack overflow so forgive me for any formatting issues.
application.py
from flask import url_for,render_template, redirect,request, jsonify,flash,\
make_response, session
from flask_jwt_extended import (create_access_token, create_refresh_token,
jwt_required, get_jwt_identity, get_jwt_claims,get_current_user,
set_access_cookies,set_refresh_cookies,
unset_jwt_cookies, get_raw_jwt, jwt_refresh_token_required,decode_token)
from jwt import decode
from forms import RegisterForm, LoginForm, NNForm
from models import Users
from website import app,db,jwt
#ToDo When the token expires I get an HTTP status code of 401 I can use expired_token_loader refresh token.
#app.route('/token/refresh', methods=['GET','POST'])
#jwt_refresh_token_required
#jwt.expired_token_loader
def refresh():
#Create the new access token
ref_token = request.cookies.get('refresh_token_cookie')
csrftoken = request.cookies.get('csrftoken')
decode_ref_token = decode_token(ref_token)
current_user = get_jwt_identity()
print('ref_token:', ref_token)
print('current_user:', current_user, get_raw_jwt())
access_token = create_access_token(identity=current_user)
#Set the JWT access cookie in the response
print('from refresh():', request.url)
response = make_response(redirect(request.url))
set_access_cookies(response,access_token)
#set_refresh_cookies()
return response
#app.route('/token/remove', methods=['POST'])
def logout():
#ToDo Still need to build the logout page.
response = make_response(redirect(url_for('logout_page')))
unset_jwt_cookies(response)
return response
#app.route('/register/', methods=['GET','POST'])
def register_page():
form = RegisterForm(request.form)
print( request.method, form.validate_on_submit())
if request.method == "POST" and form.validate_on_submit():
user = Users(form.first_name.data, form.last_name.data, \
form.email.data, form.password.data, form.organization.data)
user.save_to_db()
flash("Thanks for Registering. Please login")
return redirect(url_for("NN_page"))
return render_template('register.html',form=form)
#app.route('/login/', methods=['GET','POST'])
def login_page():
form = LoginForm(request.form)
print(request.method, request.form)
if request.method == "POST":
#This checks if the user is in the db and returns the user obj.
user = form.validate_on_submit()
if user:
access_token = create_access_token(identity=user.email, fresh=True)
refresh_token = create_refresh_token(identity=user.email)
response = make_response(redirect(url_for('NN_page')))
set_access_cookies(response, access_token)
set_refresh_cookies(response, refresh_token)
#response.headers['Authorization'] = 'Bearer {}'.format(access_token)
print(response)
return response
#return jsonify({'access_token':access_token})
#return redirect((url_for("NN_page")))
return render_template('login_page.html', form=form)
#jwt.invalid_token_loader #This allows me to stop people who have not logged in yet.
def missing_JWT_token(msg):
print('from missing_JWT_token:', msg)
return redirect(url_for('login_page'))
# return "The site being accessed requires a valid JWT to view." \
# "Error: {}".format(msg)
#app.route('/NN/', methods=['GET','POST'])
#jwt_required
def NN_page():
jwt_claims = get_raw_jwt()
print(jwt_claims)
print('cookie keys:', request.cookies.get('refresh_token_cookie'))
user = get_jwt_identity()
print('User:',user)
form = NNForm(request.form, headers=request.headers)
print(request.form, form.validate_on_submit())
if request.method == "POST" and form.validate_on_submit():
return redirect((url_for("success_NN_submission")))
return render_template('NN_page.html', form=form)
config.py
import os
from datetime import timedelta
from base64 import b64encode
secret_key = os.urandom(24)
jwt_secret_key = b64encode('I_love_my_smokes!')
class BaseConfig(object):
SECRET_KEY = secret_key
SQLALCHEMY_DATABASE_URI = 'sqlite:///Protein_NN.db'
SQLALCHEMY_TRACK_MODIFICATION = False
#JWT_SECRET_KEY = jwt_secret_key
JWT_ACCESS_TOKEN_EXPIRES = timedelta(minutes=10)
JWT_REFRESH_TOKEN_EXPIRES = timedelta(minutes=1)
JWT_TOKEN_LOCATION = 'cookies'
#JWT_ACCESS_COOKIE_PATH = '/NN/'
#JWT_REFRESH_COOKIE_PATH ='/token/refresh'
JWT_COOKIE_CSRF_PROTECT = False
SESSION_COOKIE_SECURE = True
class DevelopmentConfig(BaseConfig):
DEBUG = True
JWT_ACCESS_TOKEN_EXPIRES = timedelta(seconds=5)
SESSION_COOKIE_SECURE = False
#PROPOGATE_EXCEPTION = True
#EMAIL SETTINGS
MAIL_SERVER = 'smtp.gmail.com'
MAIL_PORT = 465
#MAIL_PORT = 587 # This is for TLS
MAIL_USE_TLS = False
MAIL_USE_SSL = True
#MAIL_USERNAME = os.environ['EMAIL_USER']
#MAIL_PASSWORD = os.environ['EMAIL_PASSWORD']
#BOOTSTRAP_SERVE_LOCAL = True
This is what get_raw_jwt() returns after the access token has been refreshed by the refresh token.
{'user_claims': {}, u'jti': u'9fb01b6c-619b-4fe6-91d3-73f8609f2f61',
u'exp': 1547022397, u'iat': 1547022392, u'fresh': False,
u'type': u'access', u'nbf': 1547022392, u'identity': None}
As you can see the identity claim is equal to None.
Here is the traceback I see:
Traceback (most recent call last):
File "/Users/Danny/.virtualenvs/Raghav_NN_WebApp/lib/python2.7/site-packages/flask/app.py", line 2309, in __call__
return self.wsgi_app(environ, start_response)
File "/Users/Danny/.virtualenvs/Raghav_NN_WebApp/lib/python2.7/site-packages/flask/app.py", line 2295, in wsgi_app
response = self.handle_exception(e)
File "/Users/Danny/.virtualenvs/Raghav_NN_WebApp/lib/python2.7/site-packages/flask/app.py", line 1741, in handle_exception
reraise(exc_type, exc_value, tb)
File "/Users/Danny/.virtualenvs/Raghav_NN_WebApp/lib/python2.7/site-packages/flask/app.py", line 2292, in wsgi_app
response = self.full_dispatch_request()
File "/Users/Danny/.virtualenvs/Raghav_NN_WebApp/lib/python2.7/site-packages/flask/app.py", line 1815, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/Users/Danny/.virtualenvs/Raghav_NN_WebApp/lib/python2.7/site-packages/flask/app.py", line 1719, in handle_user_exception
return handler(e)
File "/Users/Danny/.virtualenvs/Raghav_NN_WebApp/lib/python2.7/site-packages/flask_jwt_extended/jwt_manager.py", line 93, in handle_expired_error
return self._expired_token_callback()
File "/Users/Danny/Documents/Codes/Ellington/NN App/website/application.py", line 43, in refresh
print('current_user:', current_user, decode('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIzNzVlNWExMy1mNjRiLTQxNmItOTY0ZC0wMDg5ODI4NGY2NGQiLCJleHAiOjE1NDcwMTk5ODUsImlhdCI6MTU0NzAxOTkyNSwidHlwZSI6InJlZnJlc2giLCJuYmYiOjE1NDcwMTk5MjUsImlkZW50aXR5IjoiZGFubnlAbWUuY29tIn0.LVEj6As2Uh_xgTbjm94b0M6mJeD0YLkf9KpgNKTZJOw'))
File "/Users/Danny/.virtualenvs/Raghav_NN_WebApp/lib/python2.7/site-packages/jwt/api_jwt.py", line 92, in decode
jwt, key=key, algorithms=algorithms, options=options, **kwargs
File "/Users/Danny/.virtualenvs/Raghav_NN_WebApp/lib/python2.7/site-packages/jwt/api_jws.py", line 156, in decode
key, algorithms)
File "/Users/Danny/.virtualenvs/Raghav_NN_WebApp/lib/python2.7/site-packages/jwt/api_jws.py", line 223, in _verify_signature
raise InvalidSignatureError('Signature verification failed')
InvalidSignatureError: Signature verification failed
Having those two separate decorators on your refresh function won’t work the way you want it to. The expired loader decorator isn’t going to have a current user set because the jwt isn’t valid when that callback function is called.
Instead try breaking out the refresh code into a helper function used by both decorators independently:
def refresh_token(username):
# return flask response from here
#jwt.expired_token_loader
def handle_expired_token():
# get username here from raw jwt
username = 'todo'
return refresh_token(username)
#app.route(‘/refresh)
#jwt_refresh_token_required
def refresh_endpoint():
username = get_current_identity()
return refresh_token(username)
You could also use a custom decorator instead of the jwt_required decorator and achieve a similar thing. Some examples of that are discussed here: https://gitter.im/flask-jwt-extended/Lobby?at=5c1a9b37c35a3002474ddf3d