Secure the Todo Application

In this getting started exercise, you will enhance the previously built Todo application to secure the Tasks API using JWT access tokens.
Zilla has the concept of a guard that can be defined to control access to any route in the bindings configuration.
In this guide, you will use the JWT guard to enforce authorization of the read:tasks and write:tasks roles when calling the Tasks API.


Step 1: Zilla

In Build a Todo Application, you defined a Tasks API to send commands to the Todo service via Kafka and retrieve a continuously updated stream of tasks from Kafka as needed by the Tasks UX.
Now we secure the Tasks API by requiring the caller to have read:tasks role for the GET request, and write:tasks role for the POST, PUT and DELETE requests.

Configure Zilla

The Zilla engine configuration defines a flow of named bindings representing each step in the pipeline as inbound network traffic is decoded and transformed then encoded into outbound network traffic as needed.
In Build the Todo Application, Step 3: Zilla, you created zilla.json that defined the Tasks API without security.
When routing at each binding, Zilla can guard a route to require that specific roles have been granted to the caller. If the caller does not have the required roles, then the route is ignored. If no routes are viable, then the HTTP request fails with 404 Not Found.
Zilla trusts JWT tokens based on the token issuer, audience and public key of the token provider.
In this example, tokens are issued by Auth0 at and the intended token usage, or audience, is this local Todo app Tasks API at http://localhost:8080/tasks.
Using Zilla Studio, select the Secure the Todo App template from the Load Template dropdown and then press Generate Config to download the corresponding zilla.json configuration file.
Zilla Studio
Alternatively, copy the contents of zilla.json shown below to your local zilla.json file.
This allows the Zilla engine to validate the API caller's JWT access token at the http_server0 binding so that routes further along in the pipeline can verify the caller has the required roles.
The sse_kafka_proxy0 binding is guarded on the /tasks route, requiring read:tasks role.
The http_kafka_proxy0 binding is guarded on the POST, PUT and DELETE routes, requiring write:tasks role.
Then, add the http_filesystem_proxy0 and filesystem_server0 bindings to zilla.json giving the following updated configuration.
zilla.json (updated)
Now run the command below to update the zilla service and force a restart.
docker service update --force \
$(docker stack services example -q -f name=example_zilla)
Let's verify the Tasks API using curl as shown below.
curl -v http://localhost:8080/tasks
> GET /tasks HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.79.1
> Accept: */*
< HTTP/1.1 404 Not Found
< Content-Length: 0
< Access-Control-Allow-Origin: *
As you can see, the GET /tasks API is now secured against unauthorized access, without leaking any information about failed security checks.

Step 2: Test Drive!

Open the browser and enter http://localhost:8080/ to see the secured Todo Application.
Initially you will see an error message caused by attempting to list the current tasks as an unauthorized user without the read:tasks role.
Click the Login button and follow the flow to become an authorized user, then you will see your profile picture in the upper right corner in place of the login button.
For the purposes of this guide, all authorized users are implicitly granted both read:tasks and write:tasks roles for the Tasks API at http://localhost:8080/tasks.
The Todo Application now behaves as expected, with authorized-only access to the Tasks API.