This project servers as a template project for a full stack application containing the following components:
- Frontend written in Bootstrap.
- Keycloak auth engine handling authentication and authorization.
- RESTful backend service written in FastAPI (i.e. a Python application).
- PostgreSQL database for persisting data.
The intent of this GitHub project is that it can be cloned and modified to get you quickly up and running for whatever kind of full stack application you need to implement. The components and libraries used facilitate loose couplings between things, so it should be easy to replace a component with something else, if you prefer that. For now, we provide a Docker Compose stack for the development environment (do not use this "as is" directly in production!), but it should be a fairly easy task translate this to e.g. a Helm chart facilitating a Kubernetes deployment giving you all the fancy scalability features etc. of Kubernetes.
- Docker and Docker Compose.
Docker and Docker Compose is all you need in order to get the development environment up and running, but it will probably be nice to have the following installed too for local development:
- Python and Poetry (for dependency management).
- The npm CLI for the Bootstrap frontend development (most easlily set up with nvm).
The development environment can be started with
$ docker compose up -d --build
This will fire up the entire stack with hot-reloading enabled for both the backend and the frontend, so changes to the code should be picked up automatically. The docker-compose.yml also contains a Traefik service serving as a reverse proxy for the stack. The components of the application can be accessed on these URLs:
- Frontend: http://localhost:8080/frontend
(log in with
bruce/bruce
). - Backend: all URL paths under
http://localhost:8080/backend
(see endpoints in main.py and endpoints.py). - Keycloak (auth): http://localhost:8080/auth
(log in with
admin/admin
). - Traefik UI: http://localhost:8180.
More details can be found in docker-compose.yml.
The development docker-compose.yml file contains the following services:
A PostgreSQL DB for storing all data needed by the application.
An init container setting up and maintaining the application database tables using Alembic.
An init container populating the database with some dummy data for development purposes. The Python library SQLAlchemy is used for the database communication.
The Keycloak container handling all the authentication and authorization stuff.
An init container waiting for Keycloak to be ready. Other Docker Compose services needing a running Keycloak instance can depend on this service to have completed successfully before starting.
An init container responsible for configuring Keycloak, e.g. setting up realms and clients. The configuration of Keycloak is handled by Terraform by using this Keycloak provider.
The FastAPI RESTful backend (REST API written in Python). The application is running async and the database communication is also handled by the asyncio facilities in SQLAlchemy.
An Nginx web server serving the Bootstrap
frontend. Note that this service is not started by default since
another service (webpack
) takes care of serving the frontend and
enabling hot-reloading. The service is included for inspiration when
running in production (note, however, that the configuration used
here is not in anyway optimized for production). If you wish to test
out the Nginx service, it can be started with the --profile nginx
flag.
A Webpack service running the Bootstrap frontend with hot-reloading enabled, i.e. source code changes will be picked automatically.
A reverse proxy for (some of) the above components.
Most of the endpoints in the backend are protected and thus require
authentication via the
openid-connect
(OIDC) protocol. In practice, this means that you will need an OIDC token
from Keycloak that must be passed along in an Authorization
header
when calling the backend. An OIDC token can be obtained from Keycloak as follows
(for the user bruce
created in the realm named app
by the Terraform code in
the keycloak-init
container):
$ curl -d 'grant_type=password&client_id=app&username=bruce&password=bruce' \
"http://localhost:8080/auth/realms/app/protocol/openid-connect/token | jq .
{
"access_token": "eyJhbGciOiJSU...7ZC9Q",
"expires_in": 300,
"refresh_expires_in": 1800,
"refresh_token": "eyJhbGciOiJIUzUxMiI...ss7r-k8w",
"token_type": "Bearer",
"not-before-policy": 0,
"session_state": "6e88088d-b61c-4aee-a032-08d33e35e611",
"scope": "email profile"
}
The access_token
can be sent in an Authorization
header to the backend
like this:
$ curl -H "Authorization: Bearer eyJhbGciOiJSU...7ZC9Q" "http://localhost:8080/backend/require/auth"
which will just respond with a decoded token as an example payload. If the backend endpoint is called without the authorization header, you will get an HTTP 401 status code.
Feel free to create an issue on this GitHub project if you experience any problems. Pull requests are welcome, but let us discuss matters first via an issue before making the pull request.
- Think about how to prepare for production
- Add license