Open source (self-hosted)

Affinidi provides an open-source Control Plane implementation that can be self-hosted.

Deploy the open-source Control Plane API server on your own infrastructure. The server handles participant discovery and connection offer management for DIDComm peer-to-peer messaging. It also acts as the sole trusted JWT issuer for Matrix homeserver authentication, issuing short-lived tokens so participants can join Matrix group chat without handling Matrix credentials directly.

The Control Plane API is built with Dart and packaged as a Docker image.

1. Prerequisites

2. Clone the repository

git clone git@github.com:affinidi/affinidi-meetingplace-controlplane-api-dart.git
cd affinidi-meetingplace-controlplane-api-dart

3. Set up the Control Plane instance

  1. Copy the example Docker Compose file.
cp examples/docker/local/docker-compose.example.yml docker-compose.yml
  1. Copy the example configuration file.
cp examples/config/config.example.yml config.yml
  1. Configure environment variables.

    Open docker-compose.yml and update the required values, including storage settings, the API endpoint, and secrets. For a full list of supported variables, see the environment variables reference.

    Tip: Set CONTROL_PLANE_DID to did:localhost:<SERVER_PORT> for local testing. For example, if SERVER_PORT is 3000, use did:localhost:3000.

  2. Generate key pairs for DIDComm Auth.

mkdir -p ./keys ./params ./secrets

openssl ecparam -name secp256k1 -genkey -noout -out ./keys/secp256k1.pem
openssl ecparam -name prime256v1 -genkey -noout -out ./keys/p256.pem

openssl genpkey -algorithm Ed25519 -out ./keys/ed25519.pem
openssl pkey -in keys/ed25519.pem -pubout -out ./keys/ed25519-pub.pem
  1. Run the setup script to generate JSON Web Keys (JWKs) from the key pairs.
dart run script/setup.dart
  1. Start the server.
docker-compose up --build

Open the configured host and port in a browser to confirm the server is running. The default local address is http://localhost:3000. You should see the following page:

Control Plane API Server running

Control Plane API Server

4. Test the Control Plane connection

Use either approach below to confirm the server responds correctly.

4.1 Run the client example

The repository includes a Dart client example in examples/client/ that runs a full connection workflow: authentication, device registration, offer creation, offer discovery, and offer acceptance.

  1. Navigate to the client example directory.
cd examples/client
  1. Copy the example environment file.
cp .env.example .env
  1. Confirm API_ENDPOINT and CONTROL_PLANE_DID in .env match your running server. The defaults match the local Docker setup:
API_ENDPOINT=http://localhost:3000
CONTROL_PLANE_DID=did:localhost:3000
  1. Install dependencies.
dart pub get
  1. Run the example. The server must be running.
dart run example_native_flow.dart

Successful output shows Alice and Bob completing the full connection workflow.

4.2 Send a REST challenge request

Send a challenge request to the authentication endpoint. Replace <CONTROLPLANE_URL> with your server URL.

curl -X POST \
  -H "Content-Type: application/json" \
  -d '{"did": "did:peer:<UNIQUE_ID>"}' \
  <CONTROLPLANE_URL>/v1/authenticate/challenge

Expected response:

{"challenge":"<JWT>"}

A challenge response confirms the server is accepting requests. For the full REST API reference, see the Control Plane OSS repository.

What’s next

  Integrate Affinidi Meeting Place into your applications

  Configure DIDComm Mediator to send messages