This repository shows how to integrate Authentik into event-sourced systems. In our case the event-sourced system is a .NET Critter Stack application utilizing Marten as event-store and Wolverine as the app's backbone.
Once you complete the setup, the backend synchronizes user registrations and deletions from Authentik. Furthermore, it allows authorized actions against the backend - from the frontend using the JWT obtained through Authentik.
To run this sample you must have Docker installed on your machine.
- Overview
- Prerequisites
- Introduction
- Start the services
- Configure Authentik
- Configure the backend
- Configure the frontend
- Complete the setup
- What the fully set up stack is capable of
This README walks you through how to set up Authentik for our use case and configure the backend and frontend services for the integration. Make sure to have a text file or similar ready, to cache configuration values obtained during the Authentik setup. These will be needed to configure the backend and frontend afterwards.
| Value | Used for |
|---|---|
| Authentik app slug | Backend and frontend configuration |
| Authentik client ID | Backend and frontend configuration |
| Backend service account password/API token | Backend API access |
From the terminal, navigate to the repository root and run:
docker compose up -dThis spins up a Postgres database - used by the backend and Authentik, the event-sourced backend, our frontend and the required Authentik services.
This configuration section expects you to be logged in as an administrator on the Authentik dashboard.
Open the initial setup page - you might need to refresh the page after a few seconds: http://localhost:9000/if/flow/initial-setup/
Then proceed in the following order:
- Register your admin account.
- After registration you will be redirected. Find and click Create a new application - if prompted select Create with Provider.
- Configure the application according to the table below, keep other settings at default and click Continue.
| Setting | Value |
|---|---|
| Application Name | Example |
| Slug | example |
- Choose a provider type: select OAuth2/OpenID Connect, then click Continue.
- Configure the provider according to the table below, and then click Continue.
| Setting | Value |
|---|---|
| Authorization flow | implicit |
| Client type | public - Note the Client ID for later |
| Redirect URIs | Strict + http://localhost:3000/auth/callback |
| Authentication Flow | default-authentication-flow |
| Scopes | move offline_access to selected |
- Configure Bindings: skip over this section for this example.
- Click Submit to create the application.
If you want to read up a little more about the application setup, I recommend the first-steps article by Authentik.
This section walks you through how to set up a webhook which sends user-specific events to our backend. For the purpose of this example I kept the webhook configuration very basic.
HMAC computation is omitted. If you plan to expose your webhook endpoint to the internet, it is strongly recommended to add HMAC support for security reasons!
Our backend expects requests to be formatted as follows:
{
"event_type": "model_created",
"pk": 1
}The webhook-body-mapping uses Python to create a webhook request body as shown above.
- Navigate to Customization > Property Mappings.
- Click Create to add a mapping.
- Select Webhook Mapping, at the bottom of the list, and then click Next.
- Set the Name to
backend-webhook-mapper, copy-paste the Python Expression provided below, and then click Create.
body = request.context["notification"].body
event_type, _, payload = body.partition(": ")
marker = "'model': {'pk': "
try:
pk = int(payload.split(marker, 1)[1].split(",", 1)[0])
except (IndexError, ValueError):
pk = None
return {
"event_type": event_type or None,
"pk": pk,
}The Python code above extracts the pk and event_type from the notification body, then returns an object formatted as our backend expects it.
The mapper intentionally keeps parsing minimal for this sample.
Review or replace it for more advanced use cases, which you might have in a production scenario.
- Navigate to Event > Notification Transports.
- Click Create to add a new transport.
- Define notification transport properties using the configuration settings from the table below, and then click Create.
| Setting | Value |
|---|---|
| Name | backend-webhook-transport |
| Send once | Enabled |
| Mode | Webhook (generic) |
| Webhook URL | http://backend:8080/authentik/webhook |
| Webhook Body Mapping | backend-webhook-mapper |
The policies we create in this section decide which events are forwarded to our backend. You will need to create two policies, one for detecting user registrations and one for detecting user deletions.
Follow these steps to create a new policy. You will need to do this twice - for both policies:
- Navigate to Customization > Policies.
- Click Create to add a new policy.
- Select Event Matcher Policy, at the top of the list, and then click Next.
- Configure the policy according to the settings from the table below, and then click Create.
| Setting | Value |
|---|---|
| Name | user-created |
| Execution Logging | Disabled |
| Action | Model Created |
| Model | User (authentik_core) |
| Setting | Value |
|---|---|
| Name | user-deleted |
| Execution Logging | Disabled |
| Action | Model Deleted |
| Model | User (authentik_core) |
- Navigate to Event > Notification Rules.
- Click Create to add a new rule.
- Define notification rule properties according to the settings from the table below, and then click Create.
| Setting | Value |
|---|---|
| Name | notify-backend-user-lifetime |
| Send notification to event user | Enabled |
| Transports | backend-webhook-transport |
| Severity | Notice |
Double-check that the selected transport is present in the "Selected transports" box.
Next up we bind the previously created policies to the notification rule. This also needs to be repeated twice for both policies we created.
- Expand the collapsed notify-backend-user-lifetime rule
- Click Bind existing Policy/Group/User, and define the binding according to the settings from the table below, and then click Create.
| Setting | Value |
|---|---|
| Policy | user-created |
| Enabled | Enabled |
| Failure result | Don't pass |
| Setting | Value |
|---|---|
| Policy | user-deleted |
| Enabled | Enabled |
| Failure result | Don't pass |
Next up, we're setting up a new service account which we will use to access the Authentik API from our backend. We use the API to fetch a complete user object, for further processing, from Authentik once we receive a user-model-created event.
- Navigate to Directory > Users.
- Click New Service Account to add a new service account.
- Configure the user properties according to the settings from the table below, and then click Create Service Account.
| Setting | Value |
|---|---|
| Username | backend |
| Create group | Disabled |
| Expiring | Disabled |
- Note the Password, for later configuration steps.
- Under User folders > Root > goauthentik.io > service-accounts, click on the backend username.
- Navigate to the tab Groups, and then click Add to existing group.
- In the Groups to add, click the plus symbol.
- Select the group authentik Admins and click Add, and then click Add again.
Now the user has admin privileges, the only thing left to do is to allow the usage of our previously saved password as an API key.
- Navigate to Directory > Tokens and App passwords.
- Identify the entry for the backend user, and select the Edit action under the Actions column.
- Set the Intent to API Token, and then click Update.
If you forgot to save the password previously, you have the option to use the copy action located next to the Edit option from step 10.
In order to have a self-service user registration flow we need to install the default-enrollment-flow.
- Download the flow template from Authentik here.
- Navigate to Flows and Stages > Flows.
- Click Import and select the downloaded flow file, and then click Import.
All backend settings are to be configured in the backend/Backend/appsettings.json file. Open the appsettings.json file and copy/paste your noted settings.
{
"Authentik": {
"AppSlug": "<your-noted-app-slug>",
"ClientId": "<your-noted-client-id>",
"ApiKey": "<your-noted-service-account-password>"
}
}All frontend settings are to be configured in the frontend/.env file. Open the .env file and copy/paste your noted settings.
VITE_AUTHENTIK_APP_SLUG=<your-noted-app-slug>
VITE_AUTHENTIK_CLIENT_ID=<your-noted-client-id>In order to complete the setup we need to redeploy our backend and frontend services with the configured settings. To do this execute the following command:
docker compose up -d --build backend --build frontendFinally open the frontend to log in, register and observe backend events: http://localhost:3000
You can now open the frontend.
- You can register, which triggers a
user-registeredevent in the backend. - If you login, you can trigger a protected backend endpoint for demonstration purposes
- Via the Authentik dashboard you can create or delete users and see backend events flowing via the frontend