/flask-cognito-jwt-example

An example serverless web application using Flask and AWS Cognito with JSON Web Tokens (JWT) to protect specific routes, powered by API Gateway and Lambda

Primary LanguagePythonMIT LicenseMIT

Flask - AWS Cognito integration example

An example serverless web application using Flask and AWS Cognito with JSON Web Tokens (JWT) to protect specific routes, powered by API Gateway and Lambda.

Architecture

A high level overview of how the application works is as follows. The Flask application includes a number of blueprints:

  • home: a simple homepage that includes a login link.
  • auth: login, post-login, and logout routes.
  • private: routes that are only accessible after a user has logged in. If a user is not logged in these routes automatically redirect to the Cognito hosted UI.

When accessing the /login route, a user is redirected to the Cognito hosted UI. After successful authentication with the user pool, a JWT is returned to the app through the /postlogin endpoint which is stored in a httponly cookie; this cookie is valid for 30 mins and used to authorise access to any routes that are protected with the @auth_required decorator. The app itself uses flask-cognito-lib for the heaving lifting of validating JWTs and protecting specific routes.

For the deployment side, CDK python code is provided in /deploy. The CDK stacks will deploy the Flask application as a docker container to Lambda, with API Gateway in front. A Cognito User Pool is created along with a User Pool Client for the Flask application.

Getting started

Prequisites:

Setup as follows:

# setup the python environment with poetry
make install

# Populate the .env file the required parameters
cp .env.example .env
vi .env

# deploy the infra (Cognito, API Gateway, Lambda)
cd deploy
cdk deploy --all

# Populate AWS_COGNITO user pool parameters after deploying
# Obtain these values from the Systems Manager Parameter Store
vi .env

# run locally using Workzeug
make local  # or go to the AWS API Gateway URL

# check other useful commands
make help

The Makefile includes helpful commands for setting up a development environment, get started by installing the package into a new virtual environment and setting up pre-commit with make install. Run make help to see additional available commands (e.g. linting, testing, docker, and so on).

The application can be run locally through docker (make docker-build && make docker-run) or from the installed virtualenv with make local. The app should launched at http://localhost:5000 and a login link should redirect you to the Cognito hosted UI to sign up / sign in. Once logged in, a cookie will store the JWT and you will be redirected to the /private page. You may also view details of the JWT at the /token endpoint.

Development

  • Pytest is used for the functional tests of the application (see /tests).
  • Code is linted using flake8
  • Code formatting is validated using Black
  • pre-commit is used to run these checks locally before files are pushed to git
  • The Github Actions pipeline also runs these checks and tests

TODO

  • CORS
  • Serverless deployment with AWS CDK
  • Logout route should also hit the revoke Cognito endpoint
  • Handle JWT authenticated routes in local development (i.e. no Cognito) -> Set AWS_COGNITO_DISABLED to True
  • Populate parameters from SSM at runtime rather than deploy time

Credits

This project was inspired by the blog post Integrating Cognito with Flask by Martin Campbell.