flask api with authentication
Flask API with OAuth authentication
Use the JWT (json web token) library with Flask to create a Restful api with OAuth.
It needs to authenticate with username password to get an access token first, and then call the specific API using the token.
On the server side, it creates endpoint /login for requiring a token.
The specific API helloworld uses another endpoint.
The '@jwt_required()' decorator enables the authentication using token.
from flask import Flask, jsonify, request, Response, make_response
from flask_restful import Api, Resource
from flask_jwt_extended import JWTManager, create_access_token, jwt_required, get_jwt_identity
app = Flask(__name__)
api = Api(app) #restful api
# Setup the Flask-JWT-Extended extension
app.config['JWT_SECRET_KEY'] = 'super-secret' # Secret key for JWT, Change this in production
jwt = JWTManager(app)
# Sample users - you would typically store these in a database
users = {
'user1': 'password1',
'user2': 'password2'
}
# Authentication endpoint
# if username password is good, return an access token through 'create_access_token'
# needs to jsonify the reponses to be compatible with Restful
class UserLogin(Resource):
def post(self):
data = request.get_json()
username = data.get('username', None)
password = data.get('password', None)
if not username or not password or users[username] != password:
response = make_response(jsonify({"msg": "Invalid credentials"}),400,)
else:
access_token = create_access_token(identity=username)
response = make_response(jsonify({"access_token": access_token}),200,)
response.headers["Content-Type"] = "application/json"
return response
# API endpoint
# jwt_required protects a route. It kicks out requests without a valid JWT token.
class HelloWorld(Resource):
@jwt_required()
def get(self):
current_user = get_jwt_identity()
response = make_response(jsonify({"message": f"Hello, {current_user}! You're authenticated."}),200,)
response.headers["Content-Type"] = "application/json"
return response
# API routes
api.add_resource(UserLogin, '/login')
api.add_resource(HelloWorld, '/hello')
if __name__ == '__main__':
app.run(debug=True)
On the client side, it needs to log in to get a JWT token first. This is done by sending the username, password to the authentication endpoint.
When a token is returned, use it as Bearer token in the request headers to call the actual API endpoint, i.e. helloworld in this case.
import requests
# Base URL of the Flask application
base_url = 'http://localhost:5000'
# Sample credentials for authentication
username = 'user1'
password = 'password1'
# Login to obtain JWT token
login_url = f'{base_url}/login'
login_data = {'username': username, 'password': password}
response = requests.post(login_url, json=login_data)
if response.status_code == 200:
access_token = response.json()['access_token'] #get the JWT token
headers = {'Authorization': f'Bearer {access_token}'} # use the Token in the headers
# Call the helloworld API endpoint
hello_url = f'{base_url}/hello'
response = requests.get(hello_url, headers=headers)
if response.status_code == 200:
print(response.json())
else:
print('Failed to call helloworld API:', response.status_code)
else:
print('Failed to authenticate:', response.status_code)
Security / HTTPS / secured API
The previous API is by default in HTTP protocol, so all the requests are in plain text, i.e. very insecure because the username password and tokens can be seen by the public.
To secure the API, it needs to turn on HTTPS. You can enable HTTPS by configuring your server to use SSL/TLS certificates.
This typically involves obtaining a valid SSL certificate from a trusted Certificate Authority (CA) or a self-signed certificate (for internal use) and configuring your Flask application server (e.g., Gunicorn) to use the certificate for HTTPS connections.
To run a Flask app to use HTTPS, the app.run method needs to include the ssl_context.
if __name__ == '__main__':
# Enable HTTPS by providing SSL/TLS certificate and key files
app.run(host='0.0.0.0', port=443, ssl_context=('cert.pem', 'key.pem'))
Replace 'cert.pem' and 'key.pem' with the paths to your SSL/TLS certificate and private key files, respectively.
Generate self-signed certificate (the key and cert pem files)
This can be done using tools like OpenSSL.
Once installed, use below command to create a private RSA key with 2048 bit
openssl genrsa -out private_key.pem 2048
Then generate a Certificate Signing Request
openssl req -new -key private_key.pem -out csr.pem
Finally generate the self-signed certificate using the Signing request and private key
openssl x509 -req -days 365 -in csr.pem -signkey private_key.pem -out certificate.pem
The private_key.pem and certificate.pem can be used to run the Flask app as SSL context.
Note the self-signed certificate is not trusted by default, so clients will receive warnings about it.