GOV.UK Frontend Flask is a community tool of the GOV.UK Design System. The Design System team is not responsible for it and cannot support you with using it. Contact the maintainers directly if you need help or you want to request a feature.
This is a template Flask app using the GOV.UK Frontend and GOV.UK Design System which is designed to get a new project started quicker. It is also a reference implementation of two core packages:
- GOV.UK Frontend Jinja which provides Jinja macros of GOV.UK components
- GOV.UK Frontend WTForms which provides WTForms widgets to integrate the above Jinja macros into form generation and validation
The app is provided intentionally bare, with just the essential parts that all services need, such as error pages, accessibility statement, cookie banner, cookie page and privacy notice. It uses a number of other packages to provide the features described below with sensible and best-practice defaults. Please read the next steps section for guidance on how to start building out your app on top of this template.
- Docker
Create a new repository using this template, with the same directory structure and files. Then clone a local copy of your newly created repository.
In the compose.yml
file you will find a number of environment variables. These are injected as global variables into the app and pre-populated into page templates as appropriate. Enter your specific service information for the following:
- CONTACT_EMAIL
- CONTACT_PHONE
- DEPARTMENT_NAME
- DEPARTMENT_URL
- SERVICE_NAME
- SERVICE_PHASE
- SERVICE_URL
You must also set a new unique SECRET_KEY
, which is used to securely sign the session cookie and CSRF tokens. It should be a long random bytes
or str
. You can use the output of this Python command to generate a new key:
python -c 'import secrets; print(secrets.token_hex())'
./build.sh
docker compose up --build
You should now have the app running on https://localhost/. Accept the browsers security warning due to the self-signed HTTPS certificate to continue.
There are some helpful demos included by default that show all of the components available from GOV.UK Frontend Jinja and a selection of forms and validation patterns from GOV.UK Frontend WTForms. These are located in the app/demos
and app/templates/demos
directories, along with the demos
blueprint. Use them for reference whilst building your service, but make sure to delete them, along with the relevant section in build.sh
, before deploying the app.
To run the tests:
python -m pytest --cov=app --cov-report=term-missing --cov-branch
flowchart TB
cache1(Redis):::CACHE
Client
prox1(NGINX):::PROXY
web1(Flask app):::WEB
web2[/Static files/]:::WEB
Client <-- https:443 --> prox1 <-- http:5000 --> web1
prox1 -- Read only --> web2
web1 -- Write --> web2
web1 <-- redis:6379 --> cache1
subgraph Proxy container
prox1
end
subgraph Web container
web1
web2
end
subgraph Cache container
cache1
end
classDef CACHE fill:#F8CECC,stroke:#B85450,stroke-width:2px
classDef PROXY fill:#D5E8D4,stroke:#82B366,stroke-width:2px
classDef WEB fill:#FFF2CC,stroke:#D6B656,stroke-width:2px
Please refer to the specific packages documentation for more details.
Custom CSS and JavaScript files are merged and minified using Flask Assets and Webassets. This takes all *.css
files in app/static/src/css
and all *.js
files in app/static/src/js
and outputs a single minified file to both app/static/dist/css
and app/static/dist/js
respectively.
CSS is minified using CSSMin and JavaScript is minified using JSMin. This removes all whitespace characters, comments and line breaks to reduce the size of the source code, making its transmission over a network more efficient.
Merged and minified assets are browser cache busted on update by modifying the filename with their MD5 hash using Flask Assets and Webassets. The MD5 hash is appended to the file name, for example custom-d41d8cd9.css
instead of a query string, to support certain older browsers and proxies that ignore the querystring in their caching behaviour.
Uses Flask WTF and WTForms to define and validate forms. Forms are rendered in your template using regular Jinja syntax.
If a submitted form has any validation errors, an error summary component is shown at the top of the page, along with individual field error messages. This follows the GOV.UK Design System validation pattern and is built into the base page template.
Messages created with Flask's flash
function will be rendered using the GOV.UK Design System notification banner component. By default the blue "important" banner style will be used, unless a category of "success" is passed to use the green version.
Uses Flask WTF to enable Cross Site Request Forgery protection per form and for the whole app.
CSRF errors are handled by creating a flash message notification banner to inform the user that the form they submitted has expired.
- Forces all connections to
https
. - Enables HTTP Strict Transport Security.
- Sets Flask's session cookie to
secure
, so it will never be set if your application is somehow accessed via a non-secure connection. - Sets Flask's session cookie to
httponly
, preventing JavaScript from being able to access its content. - Sets X-Frame-Options to
SAMEORIGIN
to avoid clickjacking. - Sets X-Content-Type-Options to prevent content type sniffing.
- Sets a strict Referrer-Policy of
strict-origin-when-cross-origin
that governs which referrer information should be included with requests made.
A strict Content Security Policy (CSP) is set to mitigate Cross Site Scripting (XSS) and packet sniffing attacks. This prevents loading any resources that are not in the same domain as the application by default.
A strict Permissions Policy is set to deny the use of browser features by default.
Uses Flask Compress to compress response data. This inspects the Accept-Encoding
request header, compresses using either gzip, deflate or brotli algorithms and sets the Content-Encoding
response header. HTML, CSS, XML, JSON and JavaScript MIME types will all be compressed.
Uses Flask Limiter to set request rate limits on routes. The default rate limit is 2 requests per second and 60 requests per minute (whichever is hit first) based on the client's remote IP address. Every time a request exceeds the rate limit, the view function will not get called and instead a HTTP 429 status will be returned.
Rate limit storage can be backed by Redis using the RATELIMIT_STORAGE_URL
config value in config.py
, or fall back to in-memory if not present. Rate limit information will also be added to various response headers.
- Matt Shaw (Primary maintainer)
This software is provided "as-is" without warranty. Support is provided on a "best endeavours" basis by the maintainers and open source community.
If you are a civil servant you can sign up to the UK Government Digital Slack workspace to contact the maintainers listed above and the community of people using this project in the #govuk-design-system channel.
Otherwise, please see the contribution guidelines for how to raise a bug report or feature request.