Skip to content

Maxi10022/authentik-critter-stack-sample

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

41 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Authentik with Critter Stack

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.

Prerequisites

To run this sample you must have Docker installed on your machine.

Table of contents

Introduction

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.

Values to note during setup

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

Start the services

From the terminal, navigate to the repository root and run:

docker compose up -d

This spins up a Postgres database - used by the backend and Authentik, the event-sourced backend, our frontend and the required Authentik services.

Configure Authentik

This configuration section expects you to be logged in as an administrator on the Authentik dashboard.

Create your Authentik project

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:

  1. Register your admin account.
  2. After registration you will be redirected. Find and click Create a new application - if prompted select Create with Provider.
  3. Configure the application according to the table below, keep other settings at default and click Continue.
Setting Value
Application Name Example
Slug example
  1. Choose a provider type: select OAuth2/OpenID Connect, then click Continue.
  2. 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
  1. Configure Bindings: skip over this section for this example.
  2. 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.

Create the Authentik webhook

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
}

Create a Webhook body mapping

The webhook-body-mapping uses Python to create a webhook request body as shown above.

  1. Navigate to Customization > Property Mappings.
  2. Click Create to add a mapping.
  3. Select Webhook Mapping, at the bottom of the list, and then click Next.
  4. 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.

Create a notification transport

  1. Navigate to Event > Notification Transports.
  2. Click Create to add a new transport.
  3. 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

Create notification policies

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:

  1. Navigate to Customization > Policies.
  2. Click Create to add a new policy.
  3. Select Event Matcher Policy, at the top of the list, and then click Next.
  4. Configure the policy according to the settings from the table below, and then click Create.
user-created
Setting Value
Name user-created
Execution Logging Disabled
Action Model Created
Model User (authentik_core)
user-deleted
Setting Value
Name user-deleted
Execution Logging Disabled
Action Model Deleted
Model User (authentik_core)

Create a notification rule

  1. Navigate to Event > Notification Rules.
  2. Click Create to add a new rule.
  3. 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.

  1. Expand the collapsed notify-backend-user-lifetime rule
  2. Click Bind existing Policy/Group/User, and define the binding according to the settings from the table below, and then click Create.
Bind settings user-created
Setting Value
Policy user-created
Enabled Enabled
Failure result Don't pass
Bind settings user-deleted
Setting Value
Policy user-deleted
Enabled Enabled
Failure result Don't pass

Set up Authentik API access

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.

  1. Navigate to Directory > Users.
  2. Click New Service Account to add a new service account.
  3. 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
  1. Note the Password, for later configuration steps.
  2. Under User folders > Root > goauthentik.io > service-accounts, click on the backend username.
  3. Navigate to the tab Groups, and then click Add to existing group.
  4. In the Groups to add, click the plus symbol.
  5. 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.

  1. Navigate to Directory > Tokens and App passwords.
  2. Identify the entry for the backend user, and select the Edit action under the Actions column.
  3. 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.

Add the default-enrollment-flow

In order to have a self-service user registration flow we need to install the default-enrollment-flow.

  1. Download the flow template from Authentik here.
  2. Navigate to Flows and Stages > Flows.
  3. Click Import and select the downloaded flow file, and then click Import.

Configure the backend

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>"
  }
}

Configure the frontend

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>

Complete the setup

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 frontend

Finally open the frontend to log in, register and observe backend events: http://localhost:3000

See the sample in action

You can now open the frontend.

  • You can register, which triggers a user-registered event 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

About

Sample .NET Critter Stack application showing how to integrate Authentik authentication, JWT-based frontend/backend calls, and user lifecycle webhooks.

Topics

Resources

Stars

Watchers

Forks