Skip to main content

Prerequisites

Before you begin, ensure you have:
  • Docker and Docker Compose installed
  • curl and jq for API testing
  • A terminal with bash or zsh

Launch QIMEM with Docker

1

Start the platform

Clone the repository and launch all services:
git clone <repository-url>
cd qimem
docker compose up --build
This starts:
  • postgres - PostgreSQL database on port 5432
  • qimem-api - Encryption API on port 8080 (stateful mode)
  • Health checks run automatically
2

Verify the service is healthy

curl -fsS http://localhost:8080/health
Expected response:
{"status":"ok"}

Example 1: Encrypt and Decrypt Data

1

Create an encryption key

KEY_ID=$(curl -fsS -X POST http://localhost:8080/keys \
  -H 'content-type: application/json' \
  -d '{}' | jq -r '.key_id')
echo "Created key: $KEY_ID"
Response shape:
{"key_id":"<uuid>"}
Keys are generated with AES-256-GCM by default. The UUID is used to reference the key in subsequent operations.
2

Encrypt data

ENVELOPE=$(curl -fsS -X POST http://localhost:8080/encrypt \
  -H 'content-type: application/json' \
  -d "{\"key_id\":\"${KEY_ID}\",\"input\":\"hello\"}" | jq -r '.envelope')
echo "Encrypted envelope: $ENVELOPE"
The input field accepts plaintext strings. The response contains a base64-encoded envelope with:
  • Version identifier
  • Algorithm metadata
  • Key ID reference
  • Nonce (IV)
  • Ciphertext
  • Authentication tag
3

Decrypt data

curl -fsS -X POST http://localhost:8080/decrypt \
  -H 'content-type: application/json' \
  -d "{\"input\":\"${ENVELOPE}\"}"
Response:
{"plaintext":"hello"}
Decryption automatically extracts the key ID from the envelope and retrieves the corresponding key from the store.

Example 2: QAuth Identity and JWT Tokens

For QAuth features, use the qauth-api binary instead of qimem-api. Update your Docker Compose or run:
cargo run --bin qauth-api
1

Create a realm

Realms provide multi-tenancy isolation:
curl -fsS -X POST http://localhost:8080/v1/auth/realms \
  -H 'content-type: application/json' \
  -d '{"id":"acme","name":"Acme Corporation"}'
2

Create a role with permissions

curl -fsS -X POST http://localhost:8080/v1/auth/roles \
  -H 'content-type: application/json' \
  -d '{
    "realm_id":"acme",
    "name":"admin",
    "permissions":["keys:encrypt","keys:decrypt"]
  }'
3

Create a client

Clients represent applications that authenticate users:
CLIENT_RESPONSE=$(curl -fsS -X POST http://localhost:8080/v1/auth/clients \
  -H 'content-type: application/json' \
  -d '{"realm_id":"acme","redirect_uris":["http://localhost/callback"]}')

CLIENT_ID=$(echo $CLIENT_RESPONSE | jq -r '.client_id')
CLIENT_SECRET=$(echo $CLIENT_RESPONSE | jq -r '.client_secret')
Save the client_secret securely - it’s only returned once during creation.
4

Create a user

curl -fsS -X POST http://localhost:8080/v1/auth/users \
  -H 'content-type: application/json' \
  -d '{
    "realm_id":"acme",
    "username":"alice",
    "password":"secret-password",
    "roles":["admin"]
  }'
5

Authenticate and get JWT tokens

TOKEN_RESPONSE=$(curl -fsS -X POST http://localhost:8080/v1/auth/token \
  -H 'content-type: application/json' \
  -d "{
    \"client_id\":\"${CLIENT_ID}\",
    \"client_secret\":\"${CLIENT_SECRET}\",
    \"realm_id\":\"acme\",
    \"username\":\"alice\",
    \"password\":\"secret-password\"
  }")

ACCESS_TOKEN=$(echo $TOKEN_RESPONSE | jq -r '.access_token')
REFRESH_TOKEN=$(echo $TOKEN_RESPONSE | jq -r '.refresh_token')
echo "Access token: $ACCESS_TOKEN"
6

Introspect the access token

curl -fsS -X POST http://localhost:8080/v1/auth/token/introspect \
  -H 'content-type: application/json' \
  -d "{\"token\":\"${ACCESS_TOKEN}\"}"
This returns token metadata including user ID, realm, roles, and expiration.
7

Refresh the token

curl -fsS -X POST http://localhost:8080/v1/auth/token/refresh \
  -H 'content-type: application/json' \
  -d "{\"refresh_token\":\"${REFRESH_TOKEN}\"}"
Returns a new access token and refresh token pair.
8

Revoke the token

curl -fsS -X POST http://localhost:8080/v1/auth/token/revoke \
  -H 'content-type: application/json' \
  -d "{\"token\":\"${ACCESS_TOKEN}\"}"
Response:
{"revoked":true}
Subsequent introspection requests will fail with a 400 status.

Key Rotation Example

1

Encrypt with the original key

ENVELOPE_V1=$(curl -fsS -X POST http://localhost:8080/encrypt \
  -H 'content-type: application/json' \
  -d "{\"key_id\":\"${KEY_ID}\",\"input\":\"sensitive data\"}" | jq -r '.envelope')
2

Rotate the key

NEW_KEY=$(curl -fsS -X POST http://localhost:8080/rotate \
  -H 'content-type: application/json' \
  -d "{\"key_id\":\"${KEY_ID}\"}")
echo "New key created: $NEW_KEY"
The original key is marked inactive but remains in the store for decryption.
3

Old envelopes still decrypt

curl -fsS -X POST http://localhost:8080/decrypt \
  -H 'content-type: application/json' \
  -d "{\"input\":\"${ENVELOPE_V1}\"}"
This succeeds because rotated keys remain available for decrypt operations.

Next Steps

Installation Guide

Detailed setup for production environments

API Reference

Complete API documentation and request/response schemas

Build docs developers (and LLMs) love