I'm using Flask OauthLib following this tutorial, trying to make a basic OAuth2 client to use with Foursquare.com: https://flask-oauthlib.readthedocs.org/en/latest/client.html#oauth2-client
After I grant permission to use the app, I get redirected to a page with this text:
{
"meta": {
"code": 400,
"errorDetail": "Missing access credentials. See https://developer.foursquare.com/docs/oauth.html for details.",
"errorType": "invalid_auth"
},
"response": {}
}
What is wrong? How do I fix this? Thanks.
Foursquare app settings:
Redirect URI(s):
https://127.0.0.1:5000/login/authorized
github.py (A slightly modified version of https://github.com/lepture/flask-oauthlib/blob/master/example/github.py )
from flask import Flask, redirect, url_for, session, request, jsonify
from flask_oauthlib.client import OAuth
app = Flask(__name__)
app.debug = True
app.secret_key = 'development'
oauth = OAuth()
foursquare = oauth.remote_app(
'foursquare',
app_key='FOURSQUARE',
consumer_key='XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
consumer_secret='XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
)
app.config['FOURSQUARE'] = dict(
consumer_key='XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
consumer_secret='XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
base_url='https://api.foursquare.com/',
request_token_url=None,
access_token_url='https://foursquare.com/oauth2/access_token',
authorize_url='https://foursquare.com/oauth2/authenticate',
)
oauth.init_app(app)
#app.route('/')
def index():
if 'foursquare_token' in session:
me = foursquare.get('v2/users/self')
return jsonify(me.data)
return redirect(url_for('login'))
#app.route('/login')
def login():
return foursquare.authorize(callback=url_for('authorized', _external=True))
#app.route('/logout')
def logout():
session.pop('foursquare_token', None)
return redirect(url_for('index'))
#app.route('/login/authorized')
def authorized():
resp = foursquare.authorized_response()
if resp is None:
return 'Access denied: reason=%s error=%s' % (
request.args['error'],
request.args['error_description']
)
session['foursquare_token'] = (resp['access_token'], '')
me = foursquare.get('v2/users/self')
return jsonify(me.data)
#foursquare.tokengetter
def get_foursquare_oauth_token():
return session.get('foursquare_token')
if __name__ == '__main__':
app.run('127.0.0.1', debug=True, port=5000, ssl_context=('/Users/XXXXX/Development/Certificates/server.crt', '/Users/XXXXX/Development/Certificates/server.key'))
You need to define a scope too: for example:
request_token_params={
'scope': [
'https://mail.google.com/',
'https://www.googleapis.com/auth/admin.directory.user.readonly',
'https://www.googleapis.com/auth/admin.directory.orgunit.readonly',
'https://www.googleapis.com/auth/admin.directory.group.readonly',
'https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/userinfo.profile',
'https://www.googleapis.com/auth/plus.profile.emails.read',
]
Related
I implemented auth0 quickstart python 01-login with my Flask Application and am receiving this response:
{ "message": "mismatching_state: CSRF Warning! State not equal in request and response." }
Here is a snippet of that code logic:
from models import setup_db, Bay, db_drop_and_create_all
from flask_sqlalchemy import SQLAlchemy
from flask_cors import CORS
from jinja2 import Environment, PackageLoader
from flask import Flask, render_template, request, Response, flash, redirect, url_for, jsonify, abort,session
from sqlalchemy import Column, String, Integer, create_engine,and_
from auth import AuthError, requires_auth
from functools import wraps
from os import environ as env
from werkzeug.exceptions import HTTPException
from dotenv import load_dotenv, find_dotenv
from authlib.integrations.flask_client import OAuth
from six.moves.urllib.parse import urlencode
import json
import constants
ENV_FILE = find_dotenv()
if ENV_FILE:
load_dotenv(ENV_FILE)
AUTH0_CALLBACK_URL = env.get(constants.AUTH0_CALLBACK_URL)
AUTH0_CLIENT_ID = env.get(constants.AUTH0_CLIENT_ID)
AUTH0_CLIENT_SECRET = env.get(constants.AUTH0_CLIENT_SECRET)
AUTH0_DOMAIN = env.get(constants.AUTH0_DOMAIN)
AUTH0_BASE_URL = 'https://' + AUTH0_DOMAIN
AUTH0_AUDIENCE = env.get(constants.AUTH0_AUDIENCE)
def create_app(test_config=None):
# create and configure the app
app = Flask(__name__)
oauth = OAuth(app)
auth0 = oauth.register(
'auth0',
client_id=AUTH0_CLIENT_ID,
client_secret=AUTH0_CLIENT_SECRET,
api_base_url=AUTH0_BASE_URL,
access_token_url=AUTH0_BASE_URL + '/oauth/token',
authorize_url=AUTH0_BASE_URL + '/authorize',
client_kwargs={
'scope': 'openid profile email',
},
)
app.secret_key = constants.SECRET_KEY
app.debug = True
configedDB = setup_db(app)
if not configedDB:
abort(500)
#app.errorhandler(Exception)
def handle_auth_error(ex):
response = jsonify(message=str(ex))
response.status_code = (ex.code if isinstance(ex, HTTPException) else 500)
return response
'''
#TODO: Set up CORS. Allow '*' for origins. Delete the sample route after completing the TODOs
'''
CORS(app, resources={r"/api/*": {"origins": "*"}})
'''
#TODO: Use the after_request decorator to set Access-Control-Allow
'''
#app.after_request
def after_request(response):
response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization,true')
response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS')
return response
#----------------------------------------------------------------------------#
# Controllers.
#----------------------------------------------------------------------------#
#app.route('/')
def index():
return render_template('index.html')
#app.route('/callback')
def callback_handling():
#auth0 = app.config['auth0']
token = auth0.authorize_access_token()
resp = auth0.get('userinfo')
userinfo = resp.json()
print('>>>USER_INFO',userinfo)
session[constants.JWT_PAYLOAD] = userinfo
session[constants.PROFILE_KEY] = {
'user_id': userinfo['sub'],
'name': userinfo['name'],
'picture': userinfo['picture']
}
return redirect('/manager/bay/all')
#app.route('/login')
def login():
#auth0 = app.config['auth0']
#state = uuid.uuid4().hex
#redirect_url = url_for("auth.callback", _external=True)
#auth0.save_authorize_state(redirect_uri=redirect_url, state=state)
return auth0.authorize_redirect(redirect_uri=AUTH0_CALLBACK_URL, audience=AUTH0_AUDIENCE) #, state=state
#app.route('/logout')
def logout():
session.clear()
params = {'returnTo': url_for('home', _external=True), 'client_id': AUTH0_CLIENT_ID}
return redirect(auth0.api_base_url + '/v2/logout?' + urlencode(params))
Please note that for my .env file I have:
AUTH0_CLIENT_ID='l6yng5LFtKZIFZ6I56XXXXXXXX'
AUTH0_DOMAIN='double-helixx.us.auth0.com'
AUTH0_CLIENT_SECRET='egP3YRyAqtnHjtIkmnzWMPC0btJ3oN-odV001t9pgbKvc6nlT96PPrYsVeJzxTce'
AUTH0_CALLBACK_URL='http://127.0.0.1:5000/callback'
AUTH0_AUDIENCE='MYIMAGE'
Maybe this is the cause of the error from my side?
Python Samples Failing Out of the Box
authlib/issues
authlib-client-error-state-not-equal-in-request-and-response
It seems this is a recent issue for some people as well shown in here:
https://github.com/auth0-samples/auth0-python-web-app/issues/58
My auth0 Urls are:
I have an auth.py file as well that I have implemented- that may be the cause of the error?
import json
from flask import request, _request_ctx_stack
from functools import wraps
from jose import jwt
from urllib.request import urlopen
AUTH0_DOMAIN = 'double-helixx.us.auth0.com'
ALGORITHMS = ['RS256']
API_AUDIENCE = 'image'
## AuthError Exception
'''
AuthError Exception
A standardized way to communicate auth failure modes.
'''
class AuthError(Exception):
def __init__(self, error, status_code):
self.error = error
self.status_code = status_code
## Auth Header
'''
# implement get_token_auth_header() method
it should attempt to get the header from the request
it should raise an AuthError if no header is present
it should attempt to split bearer and the token
it should raise an AuthError if the header is malformed
return the token part of the header
'''
def get_token_auth_header():
"""Obtains the Access Token from the Authorization Header
"""
auth = request.headers.get('Authorization', None)
if not auth:
raise AuthError({
'code': 'authorization_header_missing',
'description': 'Authorization header is expected.'
}, 401)
parts = auth.split()
if parts[0].lower() != 'bearer':
raise AuthError({
'code': 'invalid_header',
'description': 'Authorization header must start with "Bearer".'
}, 401)
elif len(parts) == 1:
raise AuthError({
'code': 'invalid_header',
'description': 'Token not found.'
}, 401)
elif len(parts) > 2:
raise AuthError({
'code': 'invalid_header',
'description': 'Authorization header must be bearer token.'
}, 401)
token = parts[1]
return token
'''
# implement check_permissions(permission, payload) method
#INPUTS
permission: string permission (i.e. 'post:drink')
payload: decoded jwt payload
it should raise an AuthError if permissions are not included in the payload
!!NOTE check your RBAC settings in Auth0
it should raise an AuthError if the requested permission string is not in the payload permissions array
return true otherwise
'''
def check_permissions(permission, payload):
if 'permissions' not in payload:
raise AuthError({
'code': 'invalid_claims',
'description': 'Permissions not included in JWT.'
}, 400)
if permission not in payload['permissions']:
raise AuthError({
'code': 'unauthorized',
'description': 'Permission not found.'
}, 403)
return True
'''
# implement verify_decode_jwt(token) method
#INPUTS
token: a json web token (string)
it should be an Auth0 token with key id (kid)
it should verify the token using Auth0 /.well-known/jwks.json
it should decode the payload from the token
it should validate the claims
return the decoded payload
!!NOTE urlopen has a common certificate error described here: https://stackoverflow.com/questions/50236117/scraping-ssl-certificate-verify-failed-error-for-http-en-wikipedia-org
'''
def verify_decode_jwt(token):
jsonurl = urlopen(f'https://{AUTH0_DOMAIN}/.well-known/jwks.json')
jwks = json.loads(jsonurl.read())
unverified_header = jwt.get_unverified_header(token)
rsa_key = {}
if 'kid' not in unverified_header:
raise AuthError({
'code': 'invalid_header',
'description': 'Authorization malformed.'
}, 401)
for key in jwks['keys']:
if key['kid'] == unverified_header['kid']:
rsa_key = {
'kty': key['kty'],
'kid': key['kid'],
'use': key['use'],
'n': key['n'],
'e': key['e']
}
if rsa_key:
try:
payload = jwt.decode(
token,
rsa_key,
algorithms=ALGORITHMS,
audience=API_AUDIENCE,
issuer='https://' + AUTH0_DOMAIN + '/'
)
return payload
except jwt.ExpiredSignatureError:
raise AuthError({
'code': 'token_expired',
'description': 'Token expired.'
}, 401)
except jwt.JWTClaimsError:
raise AuthError({
'code': 'invalid_claims',
'description': 'Incorrect claims. Please, check the audience and issuer.'
}, 401)
except Exception:
raise AuthError({
'code': 'invalid_header',
'description': 'Unable to parse authentication token.'
}, 400)
raise AuthError({
'code': 'invalid_header',
'description': 'Unable to find the appropriate key.'
}, 400)
'''
#TODO implement #requires_auth(permission) decorator method
#INPUTS
permission: string permission (i.e. 'post:drink')
it should use the get_token_auth_header method to get the token
it should use the verify_decode_jwt method to decode the jwt
it should use the check_permissions method validate claims and check the requested permission
return the decorator which passes the decoded payload to the decorated method
'''
def requires_auth(permission=''):
def requires_auth_decorator(f):
#wraps(f)
def wrapper(*args, **kwargs):
token = get_token_auth_header()
payload = verify_decode_jwt(token)
check_permissions(permission, payload)
return f(payload, *args, **kwargs)
return wrapper
return requires_auth_decorator
Any ideas?
Using the following code, I've setup a flask app:
https://gist.github.com/ugik/a218a599b1af0ea06b1b38e3a5132078#file-flaskfbmapi-ai-rig
import requests
import json
from flask import Flask, request
import apiai
# FB messenger credentials
ACCESS_TOKEN = "EAAKsKOJ37rUBAKVZAQ21bn...UsZCXx6UWqQ6XuQr7OHnBYL3xD3Sy5u1ZAZCwip0XnTAHq25CsIpxRsbxZALRHOOguKm2unY7I06LRAZDZD"
# api.ai credentials
CLIENT_ACCESS_TOKEN = "78c0e0...d9404a2"
ai = apiai.ApiAI(CLIENT_ACCESS_TOKEN)
app = Flask(__name__)
#app.route('/', methods=['GET'])
def verify():
# our endpoint echos back the 'hub.challenge' value specified when we setup the webhook
if request.args.get("hub.mode") == "subscribe" and request.args.get("hub.challenge"):
if not request.args.get("hub.verify_token") == 'foo':
return "Verification token mismatch", 403
return request.args["hub.challenge"], 200
return 'Hello World (from Flask!)', 200
def reply(user_id, msg):
data = {
"recipient": {"id": user_id},
"message": {"text": msg}
}
resp = requests.post("https://graph.facebook.com/v2.6/me/messages?access_token=" + ACCESS_TOKEN, json=data)
print(resp.content)
#app.route('/', methods=['POST'])
def handle_incoming_messages():
data = request.json
sender = data['entry'][0]['messaging'][0]['sender']['id']
message = data['entry'][0]['messaging'][0]['message']['text']
# prepare API.ai request
req = ai.text_request()
req.lang = 'en' # optional, default value equal 'en'
req.query = message
# get response from API.ai
api_response = req.getresponse()
responsestr = api_response.read().decode('utf-8')
response_obj = json.loads(responsestr)
if 'result' in response_obj:
response = response_obj["result"]["fulfillment"]["speech"]
reply(sender, response)
return "ok"
if __name__ == '__main__':
app.run(debug=True)
However, at line 51 there is an error in my server logs:
UnboundLocalError: local variable 'response' referenced before
assignment
Which I understand the root of the cause is "response" is defined only within the if statement, however, since it is not my code, I'm having trouble defining the variable outside. Will this work if I place this code after line 48:
response = response_obj["result"]["fulfillment"]["speech"]
I am making a simple WebApp using Flask framework in python. It will take user inputs for email and name from my website (www.anshulbansal.esy.es) and will check if email exists in database (here database is supposed as dictionary for now) then it will not work further, but if it doesn't exists in database, it will send a random link to the submitted email and if the user clicks the link, then its info will be added to my database.
It's almost done but this error in coming in my way. Check out this code:
from flask import Flask, render_template, request, redirect, url_for
from flask_mail import Mail, Message
import random
import string
def random_generator(size=6, chars=string.ascii_letters + string.digits):
return ''.join(random.choice(chars) for x in range(size))
subscribers_d = {'anshul.bansal5#yahoo.com': 'Anshul Bansal', 'anshul.bansal3#yahoo.com': 'Bansal', 'anshul.bansal#yahoo.com': 'Anshul',}
app = Flask(__name__)
mail = Mail(app)
app.config.update(
MAIL_SERVER='smtp.gmail.com',
MAIL_PORT=465,
MAIL_USE_TLS = False,
MAIL_USE_SSL=True,
MAIL_USERNAME='anshul.bansal950#gmail.com',
MAIL_PASSWORD="It's Secret"
)
#app.route('/')
def index():
return render_template("index.html")
#app.route('/submit', methods=['POST'])
def submit():
if request.method == "POST":
v_name = request.form['vname']
v_email = request.form['vemail']
return send_mail(v_name, v_email)
else:
return redirect(url_for("/"))
random_link_sent = random_generator(20)
#app.route("/")
def send_mail(v_name, v_email):
if v_email in subscribers_d:
return "Oh! It seems that you have already registered."
else:
msg = Message('Confirm Subscription', sender=['anshul.bansal950#gmail.com'], recipients=[v_email])
msg.html = "<h3>Confirm Subscription</h3>" \
"<p>Hi! </p>" + v_name + "<p> , Please click on below link to subscribe</p>" \
"Link: " + ' www.anshulbansal.esy.es/' + random_link_sent
mail.send(msg)
return 'Check Your Inbox For Confirmation Email'
#app.route("/<random_link_sent>")
def confirm(random_link_sent):
return "You have registered on " + random_link_sent
subscribers_d[v_email] = v_name
if __name__ == "__main__":
app.run(debug=True)
But this code is giving me a builtins.ConnectionRefusedError Error.
But before 2-3 attempts of sending email were successful without any error.
How do I resolve it?
Here is the screenshot of error
You should update configuration before you initialize Mail:
app = Flask(__name__)
app.config.update(
DEBUG = True,
MAIL_SERVER = 'smtp.gmail.com',
MAIL_PORT = 587,
MAIL_USE_TLS = True,
MAIL_USE_SSL = False,
MAIL_USERNAME = 'your_username#gmail.com',
MAIL_PASSWORD = 'your_password',
)
mail = Mail(app)
I'm trying to authorize my application with twitter login authentication but after login into Twitter, It is not redirecting into my main page. It shows error:
SCREENSHOT
Here is my source code:
from flask import Flask
from flask import g, session, request, url_for, flash
from flask import redirect, render_template
from flask_oauth import OAuth
app = Flask(__name__)
app.debug = True
app.secret_key = 'development'
oauth = OAuth()
# Use Twitter as example remote application
twitter = oauth.remote_app('twitter',
base_url='https://api.twitter.com/1/',
request_token_url='https://api.twitter.com/oauth/request_token',
access_token_url='https://api.twitter.com/oauth/access_token',
authorize_url='https://api.twitter.com/oauth/authorize',
consumer_key='xxxxxxx',
consumer_secret='xxxxxxx'
)
#twitter.tokengetter
def get_twitter_token():
if 'twitter_oauth' in session:
resp = session['twitter_oauth']
return resp['oauth_token'], resp['oauth_token_secret']
#app.before_request
def before_request():
g.user = None
if 'twitter_oauth' in session:
g.user = session['twitter_oauth']
#app.route('/')
def index():
tweets = None
if g.user is not None:
resp = twitter.request('statuses/home_timeline.json')
if resp.status == 200:
tweets = resp.data
else:
flash('Unable to load tweets from Twitter.')
return render_template('index.html', tweets=tweets)
#app.route('/tweet', methods=['POST'])
def tweet():
if g.user is None:
return redirect(url_for('login', next=request.url))
status = request.form['tweet']
if not status:
return redirect(url_for('index'))
resp = twitter.post('statuses/update.json', data={
'status': status
})
if resp.status == 403:
flash('Your tweet was too long.')
elif resp.status == 401:
flash('Authorization error with Twitter.')
else:
flash('Successfully tweeted your tweet (ID: #%s)' % resp.data['id'])
return redirect(url_for('index'))
#app.route('/login')
def login():
callback_url = url_for('oauthorized', next=request.args.get('next'))
return twitter.authorize(callback=callback_url or request.referrer or None)
#app.route('/logout')
def logout():
session.pop('twitter_oauth', None)
return redirect(url_for('index'))
#app.route('/oauthorized')
def oauthorized():
resp = twitter.authorized_response()
if resp is None:
flash('You denied the request to sign in.')
else:
session['twitter_oauth'] = resp
return redirect(url_for('index'))
if __name__ == '__main__':
app.run()
PLEASE HELP ME...
ANY KIND OF HELP WOULD BE APPRECIATED!!
in your oauthorized function remove resp = twitter.authorized_response() statement and add a resp parameter to the function. it would be something like this:
#app.route('/oauthorized')
#twitter.authorized_response
def oauthorized(resp):
if resp is None:
flash('You denied the request to sign in.')
else:
session['twitter_oauth'] = resp
return redirect(url_for('index'))
I am using token based authentication to restrict the access to user for my site, I am getting following error
{"_status": "ERR", "_error": {"message": "Please provide proper credentials", "code": 401}}weber#weber-desktop:/var/www/lunar-cloud-web-ui/kukunako$
my sample code shown below.
class TokenAuth(TokenAuth):
def check_auth(self, token, allowed_roles, resource, method):
accounts = app.data.driver.db['people']
return accounts.find_one({'token': token})
app = Eve(__name__,static_url_path='/static', auth = TokenAuth)
app.debug = True,
app.config.update(
DEBUG=True,
#EMAIL SETTINGS
MAIL_SERVER='smtp.gmail.com',
MAIL_PORT=465,
MAIL_USE_SSL=True,
MAIL_USERNAME = '<username>',
MAIL_PASSWORD = '<password>'
)
mail=Mail(app)
socketio = SocketIO(app)
def create_token(user):
payload = {
'sub': str(user['_id']),
'iat': datetime.now(),
'exp': datetime.now() + timedelta(days=14)
}
token = jwt.encode(payload, TOKEN_SECRET)
return token.decode('unicode_escape')
def login_required(f):
#wraps(f)
def decorated_function(*args, **kwargs):
if not request.headers.get('Authorization'):
response = jsonify(error='Missing authorization header')
response.status_code = 401
return response
payload = parse_token(request)
if datetime.fromtimestamp(payload['exp']) < datetime.now():
response = jsonify(error='Token has expired')
response.status_code = 401
return response
g.user_id = payload['sub']
return f(*args, **kwargs)
return decorated_function
#app.route('/auth/login', methods=['POST'])
def login():
accounts = app.data.driver.db['people']
user = accounts.find_one({'email': request.json['email']})
if not user:
response = jsonify(error='Your email does not exist')
response.status_code = 401
return response
if not user['email_confirmed'] == True:
response = jsonify(error='Email is not confirmed')
response.status_code = 401
return response
if not user or not check_password_hash(user['password']['password'], request.json['password']):
response = jsonify(error='Wrong Email or Password')
response.status_code = 401
return response
token = create_token(user)
return jsonify(token=token)
my all code is show in following for settings file and server code file
settings file
server code file
How are you testing it?
I can think of two possible problems.
JWT token needs to be base64 encoded
You may have forgotten : at the end
e.g. If your token is as follows (Taken from jwt.io site)
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
You need to do the following:
$ echo 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ:' | base64
ZXlKaGJHY2lPaUpJVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5LmV5SnpkV0lpT2lJeE1qTTBOVFkzT0Rrd0lpd2libUZ0WlNJNklrcHZhRzRnUkc5bElpd2lZV1J0YVc0aU9uUnlkV1Y5LlRKVkE5NU9yTTdFMmNCYWIzMFJNSHJIRGNFZnhqb1laZ2VGT05GaDdIZ1E6Cg==
Now use this as follows (with curl)
curl -H "Authorization Basic ZXlKaGJHY2lPaUpJVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5LmV5SnpkV0lpT2lJeE1qTTBOVFkzT0Rrd0lpd2libUZ0WlNJNklrcHZhRzRnUkc5bElpd2lZV1J0YVc0aU9uUnlkV1Y5LlRKVkE5NU9yTTdFMmNCYWIzMFJNSHJIRGNFZnhqb1laZ2VGT05GaDdIZ1E6Cg==" http://127.0.0.1:5000/my_secure_endpoint