Using Flask and rauth for Github authentication

Recently I made a research about OAuth libraries for Flask. Picture is not bright, most packages are outdated and abandoned. Well known Flask-Oauth is generally dead and I don't recommend to rely on it. Funny that OAuth itself is very simple, after some magic during authentication you have access_token which you only need to add as GET parameter or special header to your request. Probably other providers need more complex logic but it is enough for Github.

Trying to fix Flask-OAuth I asked question on SO and got answer from author of rauth, he recommend to use his library. And this post is my way to payback to him and open source. I made this real life example of how you can use Flask, rauth, Github and sessions to authorize users on your site.

First of all you need to setup your local environment. Make sure that you have installed python, pip and virtualenv. Then setup environment:

If you only want to run my example then you also need Sqlite python binding, which required by SQLAlchemy:

(venv)$ pip install pysqlite

pip install all dependencies, so you should have everything ready.

Now you need to go to Applications sections in your Github settings area and setup new your own. This is example of what I have in my area:

Time for code. This is my main module:

# github.pyfromflaskimport(Flask,flash,request,redirect,render_template,url_for,session)fromflask.ext.sqlalchemyimportSQLAlchemyfromrauth.serviceimportOAuth2Service# Flask configSQLALCHEMY_DATABASE_URI='sqlite:///github.db'SECRET_KEY='\xfb\x12\xdf\xa1@i\xd6>V\xc0\xbb\x8fp\x16#Z\x0b\x81\xeb\x16'DEBUG=True# Flask setupapp=Flask(__name__)app.config.from_object(__name__)db=SQLAlchemy(app)# Use your own values in your real application github=OAuth2Service(name='github',base_url='https://api.github.com/',access_token_url='https://github.com/login/oauth/access_token',authorize_url='https://github.com/login/oauth/authorize',client_id='477151a6a9a9a25853de',client_secret='23b97cc6de3bea712fddbef70a5f5780517449e4',)# modelsclassUser(db.Model):id=db.Column(db.Integer,primary_key=True)login=db.Column(db.String(80),unique=True)name=db.Column(db.String(120))def__init__(self,login,name):self.login=loginself.name=namedef__repr__(self):return'<User %r>'%self.login@staticmethoddefget_or_create(login,name):user=User.query.filter_by(login=login).first()ifuserisNone:user=User(login,name)db.session.add(user)db.session.commit()returnuser# views@app.route('/')defindex():returnrender_template('login.html')@app.route('/about')defabout():ifsession.has_key('token'):auth=github.get_session(token=session['token'])resp=auth.get('/user')ifresp.status_code==200:user=resp.json()returnrender_template('about.html',user=user)else:returnredirect(url_for('login'))@app.route('/login')deflogin():redirect_uri=url_for('authorized',next=request.args.get('next')orrequest.referrerorNone,_external=True)print(redirect_uri)# More scopes http://developer.github.com/v3/oauth/#scopesparams={'redirect_uri':redirect_uri,'scope':'user:email'}print(github.get_authorize_url(**params))returnredirect(github.get_authorize_url(**params))# same path as on application settings page@app.route('/github/callback')defauthorized():# check to make sure the user authorized the requestifnot'code'inrequest.args:flash('You did not authorize the request')returnredirect(url_for('index'))# make a request for the access token credentials using coderedirect_uri=url_for('authorized',_external=True)data=dict(code=request.args['code'],redirect_uri=redirect_uri,scope='user:email,public_repo')auth=github.get_auth_session(data=data)# the "me" responseme=auth.get('user').json()user=User.get_or_create(me['login'],me['name'])session['token']=auth.access_tokensession['user_id']=user.idflash('Logged in as '+me['name'])returnredirect(url_for('index'))if__name__=='__main__':db.create_all()app.run()

<!-- templates/login.html --><!doctype html><title>Login</title><h1>Login</h1><ahref ="">Login with OAuth2</a><h1>About</h1><ahref="">About</a> If you are not logged in then you will be redirected to login page.

Database will be created after start:

(venv)$ python github.py

After start open site in browser and login. access_token saved in session, it is not secure, but enough for example. In real site you can use something like this: