Benji Benji - 2 months ago 15
Python Question

werkzeug.routing.BuildError BuildError: ('oauth_authorize', {'provider': 'twitter'}, None)

I'm trying to add Login with twitter redirect in my login page. Which is called login.html.

<li><a href="{{ url_for('oauth_authorize', provider='twitter') }}">Login with Twitter</a></li>


upon clicking that URL it throws me BUILDERROR.

BuildError: ('oauth_callback', {'provider': 'twitter'}, None)


Here is the code.

@user_blueprint.route('/authorize/<provider>')
def oauth_authorize(provider):
if not current_user.is_anonymous:
return rredirect(url_for('main.home'))
oauth = OAuthSignIn.get_provider(provider)
return oauth.authorize()


That is my views.py the oauth_authorize function.
@user_blueprint.route('/callback/')

def oauth_callback(provider):
if not current_user.is_anonymous:
return redirect(url_for('main.home'))
oauth = OAuthSignIn.get_provider(provider)
social_id, username, email = oauth.callback()
if social_id is None:
flash('Authentication failed.')
return redirect(url_for('user.login'))
user = User.query.filter_by(social_id=social_id).first()
if not user:
user = UserProfile(social_id=social_id, nickname=username, email=email)
db.session.add(user)
db.session.commit()
login_user(user, True)
return redirect(url_for('user.login'))


I've been trying to debug the problem.
I have a mixture feelings about the oauth.py code I have.

from rauth import OAuth1Service, OAuth2Service
from flask import current_app, url_for, request, redirect, session


class OAuthSignIn(object):
providers = None

def __init__(self, provider_name):
self.provider_name = provider_name
credentials = current_app.config['OAUTH_CREDENTIALS'][provider_name]
self.consumer_id = credentials['id']
self.consumer_secret = credentials['secret']

def authorize(self):
pass

def callback(self):
pass

def get_callback_url(self):
return url_for('oauth_callback', provider=self.provider_name,
_external=True)

@classmethod
def get_provider(self, provider_name):
if self.providers is None:
self.providers = {}
for provider_class in self.__subclasses__():
provider = provider_class()
self.providers[provider.provider_name] = provider
return self.providers[provider_name]


class FacebookSignIn(OAuthSignIn):
def __init__(self):
super(FacebookSignIn, self).__init__('facebook')
self.service = OAuth2Service(
name='facebook',
client_id='512038548997732',
client_secret='a5a480e8da592d5c16feeee5426976b4',
authorize_url='https://graph.facebook.com/oauth/authorize',
access_token_url='https://graph.facebook.com/oauth/access_token',
base_url='https://graph.facebook.com/'
)

def authorize(self):
return redirect(self.service.get_authorize_url(
scope='email',
response_type='code',
redirect_uri=self.get_callback_url())
)

def callback(self):
if 'code' not in request.args:
return None, None, None
oauth_session = self.service.get_auth_session(
data={'code': request.args['code'],
'grant_type': 'authorization_code',
'redirect_uri': self.get_callback_url()}
)
me = oauth_session.get('me?fields=id,email').json()
return (
'facebook$' + me['id'],
me.get('email').split('@')[0], # Facebook does not provide
# username, so the email's user
# is used instead
me.get('email')
)


class TwitterSignIn(OAuthSignIn):
def __init__(self):
super(TwitterSignIn, self).__init__('twitter')
self.service = OAuth1Service(
name='twitter',
consumer_key='pNU7LEHOLEAJH3lQRNwOjiJMH',
consumer_secret='WFe5DVdi5JZ6KtuyRWYP9BkC8905EUp0N56junLtde1vL5w2NR',
request_token_url='https://api.twitter.com/oauth/request_token',
authorize_url='https://api.twitter.com/oauth/authorize',
access_token_url='https://api.twitter.com/oauth/access_token',
base_url='https://api.twitter.com/1.1/'
)

def authorize(self):
request_token = self.service.get_request_token(
params={'oauth_callback': self.get_callback_url()}
)
session['request_token'] = request_token
return redirect(self.service.get_authorize_url(request_token[0]))

def callback(self):
request_token = session.pop('request_token')
if 'oauth_verifier' not in request.args:
return None, None, None
oauth_session = self.service.get_auth_session(
request_token[0],
request_token[1],
data={'oauth_verifier': request.args['oauth_verifier']}
)
me = oauth_session.get('account/verify_credentials.json').json()
social_id = 'twitter$' + str(me.get('id'))
username = me.get('screen_name')
return social_id, username, None # Twitter does not provide email


This is a traceback error

Traceback (most recent call last):
File "/usr/local/lib/python2.7/site-packages/flask/app.py", line 1836, in __call__
return self.wsgi_app(environ, start_response)
File "/usr/local/lib/python2.7/site-packages/flask/app.py", line 1820, in wsgi_app
response = self.make_response(self.handle_exception(e))
File "/usr/local/lib/python2.7/site-packages/flask/app.py", line 1403, in handle_exception
reraise(exc_type, exc_value, tb)
File "/usr/local/lib/python2.7/site-packages/flask/app.py", line 1817, in wsgi_app
response = self.full_dispatch_request()
File "/usr/local/lib/python2.7/site-packages/flask/app.py", line 1477, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/usr/local/lib/python2.7/site-packages/flask/app.py", line 1381, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/usr/local/lib/python2.7/site-packages/flask/app.py", line 1475, in full_dispatch_request
rv = self.dispatch_request()
File "/usr/local/lib/python2.7/site-packages/flask_debugtoolbar/__init__.py", line 125, in dispatch_request
return view_func(**req.view_args)
File "/Users/Ben/Desktop/flask_practise/project/user/views.py", line 81, in oauth_authorize
return oauth.authorize()
File "/Users/Ben/Desktop/flask_practise/oauth.py", line 86, in authorize
params={'oauth_callback': self.get_callback_url()}
File "/Users/Ben/Desktop/flask_practise/oauth.py", line 22, in get_callback_url
_external=True)
File "/usr/local/lib/python2.7/site-packages/flask/helpers.py", line 312, in url_for
return appctx.app.handle_url_build_error(error, endpoint, values)
File "/usr/local/lib/python2.7/site-packages/flask/app.py", line 1641, in handle_url_build_error
reraise(exc_type, exc_value, tb)
File "/usr/local/lib/python2.7/site-packages/flask/helpers.py", line 305, in url_for
force_external=external)
File "/usr/local/lib/python2.7/site-packages/werkzeug/routing.py", line 1616, in build
raise BuildError(endpoint, values, method)
BuildError: ('oauth_callback', {'provider': 'twitter'}, None)


SOULUTION ----
Woops! I feel like an idiot. I had been changing file on a wrong directory. All I had to do was add the user_blueprint at my oauth.py file. Now it works fine!

Answer

Because you're using Blueprints, in your Jinja template you'll need to call the endpoint like this

url_for('user_blueprint.oauth_authorize', provider='twitter')
Comments