Full Stack Developer
Auth0 Ambassador
Mozilla Reps Mentor
GDG Ranchi Organizer
@mdsbzalam
1. JSON Web Tokens ( JWT )
2. Python Frameworks
3. Flask
4. Django
5. Conclusion
http://bit.ly/pyconid-jwt-token
The header is a JSON Object usually consisting of the type( typ ) , which is JWT, and the algorithm used for encrypting the JWT (alg ):
{
"alg": "HS256",
"typ": "JWT"
}
The Payload is a JSON object that consists of user defined attributes ( called public claims ) . Some attributes are defined in the standard ( these are called reserved claims ).
{
// reserved claim
"iss": "https://myapi.com",
// public claim
"user": "mdsbzalam"
}
The Signature is the encoded header and payload, signed with a secret.
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret
)
This accomplishes several tasks at once, including:
A finished token looks like [encoded header].[encoded payload].[signature] :
http://bit.ly/pyconid-jwt-token
Easy to parse
Easy to Sign
Compact
compared to XML
compared to XML
compared to ...
You get it.
$ pip install jwt
$ python
>>> import jwt
>>> jwt.encode({'jwt':'JSON Web Token'},'secret')
$
......
>>> token = jwt.encode({'py':'Python'},'secret')
>>> jwt.decode(token , 'secret')
{'py':'Python'}
Django is older, more mature, and a little bit more popular.
On GitHub, this framework has around 37k stars, 1.6k contributors, ~200 releases, and more than 16k forks.
On StackOverflow, roughly 1.2% of questions asked in a given month are related to Django.
Flask, although less popular, is not far behind.
On GitHub, Flask has almost 39k stars, ~480 contributors, ~26 releases, and more than 11k forks.
On StackOverflow, up to 0.2% of questions asked in a given month are related to Flask.
from flask import Flask
app = Flask(__name__)
if __name__ == "__main__":
app.run(debug=True)
from flask import Flask
from flask import jsonify
from flask import request
from flask import make_response
...
...
...
@app.route('/login')
def login():
auth = request.authorization
if auth and auth.password == 'pyconid':
return jsonify({'message' : 'logged in})
return make_response('Could not verify!', 401,
{'WWW-Authenticate' :
'Basic realm:"Login Required"'})
...
...
@app.route('/unprotected')
def unprotected():
return jsonify({'message' :
'Anyone can view this.'})
@app.route('/protected')
def protected():
return jsonify({'message' :
'Only available to people
with valid tokens.'})
...
...
import jwt
import datetime
...
...
...
app.config['SECRET_KEY'] = 'indonesia'
...
if auth and auth.password == 'pyconid':
token = jwt.encode({'user': auth.username,
'exp': datetime.datetime.utcnow()
+ datetime.timedelta(seconds=50)},
app.config['SECRET_KEY'])
return jsonify({'message' : 'logged in})
...
...
...
def token_required(f):
@wraps(f)
def decorated(*args, **kwargs):
token = request.args.get('token')
# http://127.0.0.1:5000/protected?token=sqibsq12egvdyw
if not token:
return jsonify({'message' : 'Token is missing'}), 403
try:
data = jwt.decode(token, app.config['SECRET_KEY'])
except:
return jsonify({'message' : 'Token is invalid!'}), 403
return f(*args, **kwargs)
return decorated
...
...
@app.route('/protected')
def protected():
return jsonify({'message' :
'Only available to people
with valid tokens.'})
...
...
@app.route('/protected')
@token_required
def protected():
return jsonify({'message' :
'Only available to people
with valid tokens.'})
...
from flask import Flask, jsonify, request, make_response
import jwt
import datetime
from functools import wraps
app = Flask(__name__)
app.config['SECRET_KEY'] = 'indonesia'
# Token Decorator
def token_required(f):
@wraps(f)
def decorated(*args, **kwargs):
token = request.args.get('token')
if not token:
return jsonify({'message' : 'Token is missing'}), 403
try:
data = jwt.decode(token, app.config['SECRET_KEY'])
except:
return jsonify({'message' : 'Token is invalid!'}), 403
return f(*args, **kwargs)
return decorated
# Unprotected Route and function
@app.route('/unprotected')
def unprotected():
return jsonify({'message' : 'Anyone can view this.'})
# Protected Route and function
@app.route('/protected')
@token_required
def protected():
return jsonify({'message' : 'Only available to people with valid tokens.'})
# Login Route and function
@app.route('/login')
def login():
auth = request.authorization
if auth and auth.password == 'pyconid':
token = jwt.encode({'user': auth.username, 'exp': datetime.datetime.utcnow() + datetime.timedelta(seconds=40)}, app.config['SECRET_KEY'])
return jsonify({'token' : token})
return make_response('Could not verify!', 401, {'WWW-Authenticate' : 'Basic realm:"Login Required"'})
if __name__ == "__main__":
app.run(debug=True)
http://bit.ly/pyconid-jwt-flask-simple
[~]$ python flaskdemo.py
http://bit.ly/pyconid-jwt-flask
http://bit.ly/pyconid-jwt-flask-auth0
http://bit.ly/pyconid-slide
$ pip install django
$ pip install djangorestframework
$ pip install djangorestframework_simplejwt
$ django-admin startproject apiexample
$ cd apiexample
$ python manage.py startapp pyconid
REST_FRAMEWORK = {
...
'DEFAULT_AUTHENTICATION_CLASSES': (
...
'rest_framework_simplejwt.authentication.JWTAuthentication',
)
...
}
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
)
urlpatterns = [
...
url(r'^api/token/$', TokenObtainPairView.as_view(), name='token_obtain_pair'),
url(r'^api/token/refresh/$', TokenRefreshView.as_view(), name='token_refresh'),
...
]
curl \
-X POST \
-H "Content-Type: application/json" \
-d '{"username": "mdsbzalam", "password": "donttellanyone"}' \
http://localhost:8000/api/token/
...
{
"access":"eyJh.wiY29.NH7lU",
"refresh":"eyJh.CIsIm.aERh4"
}
http://bit.ly/pyconid-jwt-django
http://bit.ly/pyconid-jwt-django-auth0
http://bit.ly/pyconid-slide
General JWT Resources
jwt.io
Overview of JWT Signing Algorithms
http://bit.ly/jwt-alg
JWT Handbook
http://bit.ly/jwt-book
JWT Token
http://bit.ly/pyconid-jwt-token
facebook.com/mdsbzalam
@mdsbzalam
@mdsbzalam
https://in.linkedin.com/in/mdsbzalam
mdsbzalam@gmail.com
http://bit.ly/pyconid-slide
@mdsbzalam