A simple Flask app that provides KeyCloak OIDC authN support for any web-app
This repository provides a simple Flask app that (a) performs user authentication with a KeyCloak server using the OIDC Authorization Code Flow and then (b) forward proxies authenticated user requests to a web-app running on the same server. This Flask app must be running locally on the same server as this web-app, e.g., web-app is deployed as a set of containers running on a docker network. The KeyCloak authN endpoint is assumed to be deployed already. The user authentication and request forwarding flow is shown in the diagram below.
- Authentication is enforced by: (1) requiring an access token in the user request header; (2) validating the access token; (3) only forwarding requests with valid access tokens to your web-app. If no token is provided in the user request or the provided token is not valid (e.g., is expired), the user will be redirected to the KeyCloak login page which then kicks off the OIDC authN flow.
- Uses the Flask OIDC library to (a) check user authentication status, (b) keep track of authenticated sessions and (c) perform OIDC Authorization Code Flow authentication before forwarding user requests to the web-app
- Uses the Flask KeyCloak library to broker the OIDC Authorization Code Flow between the Flask app and the KeyCloak server
- Since KeyCloak is used, this provides a very flexible OIDC authN solution since a user can authenticate directly with KeyCloak, or KeyCloak can be used as an identity broker with an external Identity Provider (e.g., github, google) and KeyCloak will handle the additional OIDC authN flow with the Identiy Provider. Either way, this Flask app only needs to integrate ONCE with the KeyCloak server.
This guide provides a quick way to get started with our project. Please see our [docs]([INSERT LINK TO DOCS SITE / WIKI HERE]) for a more comprehensive overview.
- Deploy your web-app on your server and have it listen on localhost on your INTERNAL_APPLICATION_PORT of your choosing
- Setup your web server to listen your desired INBOUND_PORT (e.g., using NGINX server listening on INBOUND_PORT, an AWS ALB with a listener on INBOUND_PORT that forwards requests to the EC2 that your web-app is running on, etc)
- Build a python environment using the environment.yml file provided in this repo. See the Requirements and Setup Instructions below for more details on how to do it
- Set the following environment variables for the Flask app to use internally for the OIDC autnN flow with your KeyCloak server:
- INTERNAL_APPLICATION_PORT: after the user successfully authenticates with the KeyCloak server, the Flask app will forward proxy the user request on this port (i.e., on http://localhost:{INTERNAL_APPLICATION_PORT}); default is port 80
- INBOUND_PORT: this is the inbound port that the user request comes in on, the Flask app listens on this port; default is port 8088
- FLASK_SECRET_KEY: secret key for the Flask app itself, this can be set to any arbitrary value; default is "my_secret_key"
- KEYCLOAK_SERVER_METADATA_URL: OIDC configuration URL that the Flask app will use to identify auth/token/userinfo/certs/etc endpoints for the KeyCloak server, it will be of the form https://{KeyCloak_server_domain_name}/realms/{KeyCloak_realm}/.well-known/openid-configuration; there is no default value
- KEYCLOAK_CLIENT_ID: the KeyCloak Client ID where the Flask app will send the OIDC authN requests; there is no default value
- KEYCLOAK_CLIENT_SECRET: the secret for the client specified in KEYCLOAK_CLIENT_ID; there is no default value
- KEYCLOAK_LOGOUT_URL: the KeyCloak server's logout URL, it will be of the form https://{KeyCloak_server_domain_name}/realms/{KeyCloak_realm}/protocol/openid-connect/logout
- Run the following command:
python flaskProxyWithAuth.py
- If you set up everything correctly, this should work!
To test that auth is working, simply navigate to your web-app at https://{your_webapp_domain_name}:{INBOUND_PORT} and you should be redirected to your KeyCloak server login page. Login and if successful, the Flask app should forward you to your web-app and voila, you've got OIDC authentication with KeyCloak up and running!
- [INSERT LIST OF REQUIREMENTS HERE]
Certain properties and permission settings are necessary in GitHub for builds to run automatically. On local development systems builds may be tested in similar fashion with proper tooling installed.
- Shared PyPi API Token installed in GitHub Repository Secrets named
PYPI_API_TOKEN
. - Permissions to execute GitHub Actions and perform software tag and release.
- Build tooling modules
pip3 install --upgrade build setuptools_scm twine wheel
- Product required modules (
requirements.txt
)
pip3 --exists-action w install -r requirements.txt
- [INSERT STEP-BY-STEP SETUP INSTRUCTIONS HERE, WITH OPTIONAL SCREENSHOTS]
- [INSERT STEP-BY-STEP RUN INSTRUCTIONS HERE, WITH OPTIONAL SCREENSHOTS]
- [INSERT LIST OF COMMON USAGE EXAMPLES HERE, WITH OPTIONAL SCREENSHOTS]
A GitHub Action configuration specifies the series of commands to release and publish the product. Commands are staged and carried out automatically when a tagged release is published to the main branch.
- Edit the
[INSERT YOUR PACKAGE NAME]/version.py
file with the next release version using the web UI on GitHubmain
branch. - Perform a release using the web UI on GitHub
main
branch - Build, packaging and release to PyPi will execute automatically using GitHub Actions Workflows
These instructions must be entered from the local directory checked out from source control.
- Manually update
[INSERT YOUR PACKAGE NAME]/version.py
with the next release version, commit and push to themain
branch:
git add [INSERT YOUR PACKAGE NAME]/version.py && git commit -m "Issue #<issue_number>: Updated version for release." && git push
- Tag using the Git command line:
git tag -a -m "Issue #<issue_number>: Release version <version>" <version>
Note: The <version>
must match that in the [INSERT YOUR PACKAGE NAME]/version.py
file.
3. Package the product:
- Package an
sdist
and atarball
: (traditional)
git checkout [INSERT YOUR PACKAGE NAME]/version.py && python3 -m build --wheel
- ... or package an
sdist
and azip
...
python3 -m build --wheel && python3 setup.py sdist --format=zip
- Publish product to PyPi for public distribution by using Twine:
twine check dist/* && twine upload --verbose
... or as a ZIP ...
twine check dist/* && twine upload --verbose dist/*.whl dist/*.zip
- [INSERT STEP-BY-STEP TEST INSTRUCTIONS HERE, WITH OPTIONAL SCREENSHOTS]
These instructions must be entered from the local directory checked out from source control. A simplified build and release workflow is available for testing locally. Publishing directly to PyPi is not recommended as PyPi permits one upload per release version.
- Clean application:
rm -r build dist __pycache__ *.egg* .egg* ; git checkout [INSERT YOUR PACKAGE NAME]/version.py ; pip3 uninstall [INSERT YOUR PACKAGE NAME] -y
- Build and install release locally:
python3 -m build --wheel && python3 setup.py sdist --format=zip
pip3 install [INSERT YOUR PACKAGE NAME] --no-index --find-links file://${PWD}/dist/
... alternately, install an editable build using Pip tooling ...
pip install -e
- Testing publication to Test PyPi
Twine will prompt for your Test PyPi username and password.
twine check dist/*
twine upload --repository testpypi --verbose dist/*
See our CHANGELOG.md for a history of our changes.
See our [releases page]([INSERT LINK TO YOUR RELEASES PAGE]) for our key versioned releases.
[INSERT LINK TO FAQ PAGE OR PROVIDE FAQ INLINE HERE]
Interested in contributing to our project? Please see our: CONTRIBUTING.md
For guidance on how to interact with our team, please see our code of conduct located at: CODE_OF_CONDUCT.md
For guidance on our governance approach, including decision-making process and our various roles, please see our governance model at: GOVERNANCE.md
See our: LICENSE
[INSERT CONTACT INFORMATION OR PROFILE LINKS TO MAINTAINERS AMONG COMMITTER LIST]