Getting Started
This guide walks through setting up the mwen.io issuer server in self-hosted mode — the simplest path to issuing your first credential. If you are deploying in SaaS mode to serve multiple organisations, start here to verify the basics, then see SaaS Onboarding.
Prerequisites
| Tool | Version | Purpose |
|---|---|---|
| Node.js | 20+ | Runtime (via nvm or fnm recommended) |
| Docker | Any recent | PostgreSQL container |
| mkcert | Any | Local TLS certificates |
| Caddy | 2.x | HTTPS reverse proxy (NextAuth requires HTTPS) |
The mwen.io browser extension must be installed in your browser to complete the operator registration flow and to test credential issuance.
Step 1 — Clone and install
Clone the monorepo and install dependencies from the root:
git clone https://github.com/mwenio/mwen.io.git
cd mwen.io
npm install
Step 2 — Start PostgreSQL
The issuer requires a PostgreSQL database. A docker-compose.yml is provided in apps/issuer/:
docker-compose up -d
This starts a PostgreSQL container on port 5432 with the credentials pre-configured in .env.local.self-hosted.
Step 3 — Apply migrations and seed
From apps/issuer/:
npm run db:migrate # applies all Prisma migrations and RLS policies
npm run db:seed # creates the default tenant and test data
Verify the migration state:
npx prisma migrate status
# Expected: "Database schema is up to date!"
Step 4 — Start the server
Use the mode-specific start script rather than npm run dev directly. The script copies the correct environment file to .env.local first:
npm run dev:self-hosted
The Next.js server starts on port 3003. In a separate terminal, start the HTTPS proxy:
npm run proxy
The issuer is now available at https://localhost:3002.
Step 5 — Register the first operator
Open https://localhost:3002/login in your browser (with the mwen.io extension installed).
- Click Sign in with mwen.io — the extension presents your identity to the issuer.
- Because no operator exists yet, you are redirected to
/register. - Complete the registration form. You are the first operator, so you are automatically assigned the
OWNERrole on the default tenant.
You are now logged in to the issuer admin portal.
Step 6 — Issue your first credential
From the admin portal:
- Go to Credentials → New Offer.
- Select a schema (e.g.
employee-identity-v1). - Enter the subject's details and click Create Offer.
- A QR code appears. Scan it with the mwen.io extension on your mobile device, or open the offer link in a browser with the extension installed.
- The wallet displays the credential offer preview. Accept it.
- The credential is stored in the wallet.
What happens next
The credential is now in the wallet. The wallet holder can present it to any relying party app that accepts verified-issuer or (if you configured a government category) government trust level credentials.
Configuration
The default self-hosted environment file at apps/issuer/.env.local.self-hosted is pre-configured for local development. For a production deployment you will need to:
- Set
ISSUER_SIGNING_KEYto a freshly-generated secret (runopenssl rand -hex 32) - Set
NEXTAUTH_SECRETto a freshly-generated secret - Set
ISSUER_DIDto your productiondid:web(e.g.did:web:issuer.yourorg.com) - Set
ISSUER_DOMAINto your production domain - Set
DATABASE_URLto your production PostgreSQL connection string - Set
NEXTAUTH_URLto your production base URL
See Configuration for a full reference of all variables.
Related pages
- Deployment Modes — understanding self-hosted vs SaaS
- Configuration — all environment variables and YAML config
- SaaS Onboarding — creating and managing tenants in SaaS mode