I am currently looking for a way to secure a REST API using token based authentication. I am developing the API in Python using Flask and have discovered the flask-security extension which seems to have a lot of interesting features.
One of the features mentioned in the documentation is Token Authentication.
According to the documentation:
Token based authentication is enabled by retrieving the user auth token by performing an HTTP POST with the authentication details as JSON data against the authentication endpoint. A successful call to this endpoint will return the user’s ID and their authentication token. This token can be used in subsequent requests to protected resources.
I am however still a bit confused on how to implement this feature using flask-security. Some online research has led me to using things such as @auth_token_required but I am having some trouble to put everything together. The flask-security documentation itself is not very helpful.
For example, how can a user get an authentication token? what is the authentication endpoints?
It would be great if you could lead me in the right direction. Code examples would be awesome too :-)
To install it, type sudo apt install python3-venv in your terminal and then you are good to go. If you are on windows then use something like virtualenv to make a virtual environment. This will create a folder named venv in the flask project which will contain the project specific libraries.
Flask-Security allows you to quickly add common security mechanisms to your Flask application. They include: Session based authentication. Role management.
Integrate the Security Library The code for a working OAuth secured Python Flask API is provided below: The OAuth filter is configured to run before API requests. The filter verifies the token signature and the expected issuer / audience claims. API routes can then access JWT claims in the request object.
Endpoint is /login, you post your credentials as json request body:
{'email':'[email protected]', 'password':'1234'}
However for this to work you need to disable the csrf tokens in your flask app (thanks Mandar Vaze):
app.config['WTF_CSRF_ENABLED'] = False
Then you do each request with the token in the HTTP headers:
Authentication-Token:WyI1NTE1MjhmNDMxY2Q3NTEwOTQxY2ZhYTgiLCI2Yjc4NTA4MzBlYzM0Y2NhZTdjZjIxNzlmZjhiNTA5ZSJd.B_bF8g.t1oUMxHr_fQfRUAF4aLpn2zjja0
Or as query string:
http://localhost:5000/protected?auth_token=WyI1NTE1MjhmNDMxY2Q3NTEwOTQxY2ZhYTgiLCI2Yjc4NTA4MzBlYzM0Y2NhZTdjZjIxNzlmZjhiNTA5ZSJd.B_bF8g.t1oUMxHr_fQfRUAF4aLpn2zjja0
Client example in python 3:
import requests
import json
#do the login
r = requests.post('http://localhost:5000/login',
data=json.dumps({'email':'[email protected]', 'password':'1234'}),
headers={'content-type': 'application/json'})
response = r.json()
print(response) #check response
token = response['response']['user']['authentication_token'] #set token value
#Now you can do authorised calls
r = requests.get('http://localhost:5000/protected',
headers={'Authentication-Token': token})
print(r.text)
Angular example snippet to obtain the token:
$http.post('/login', {"email": $scope.formdata.login,"password":$scope.formdata.password}).
success(function(results) {
$window.sessionStorage.token = results.response.user.authentication_token;
});
Angular example snippet to visit protected pages:
if ($window.sessionStorage.getItem('token')) {
config.headers['Authentication-Token'] = $window.sessionStorage.getItem('token');
}
I found Flask-Security's token-based not a good candidate for my project. I recommend using JWT token instead.
The problems with Flask-Security's token based authentication.
Check out JWT (pyjwt or flask-jwt) token, it solves all the above problems and more.
Authentication endpoint is /login
Look at the code of flask-security here specifically views.py: _render_json()
login() calls _render_json which in turn calls get_auth_token() - and returns the auth token.
Problem (for me) is to get this to work. For me request.json seems empty (hence this does not work)
{"email": "[email protected]", "password": "test123"}
Hopefully this helps you move forward a little.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With