Configuration
The mwen.io issuer is configured through a combination of environment variables (for secrets and deployment-specific values) and a YAML file (for non-secret, non-deployment-specific settings). Environment variables always take priority.
Configuration priority
1. Environment variables — highest priority, always override
2. issuer.config.yaml — operator config file, committed to version control
3. Built-in code defaults — lowest priority
The resolved configuration is cached for the lifetime of the server process.
Environment variables
Required in all modes
| Variable | Description | Example |
|---|---|---|
DATABASE_URL | PostgreSQL connection string | postgresql://user:pass@host:5432/issuer |
NEXTAUTH_SECRET | Secret for admin portal session cookie signing and encryption | openssl rand -hex 32 |
NEXTAUTH_URL | Canonical base URL of the issuer — must match the URL the browser navigates to | https://issuer.yourorg.com |
NEXTAUTH_URLmust point to the URL users navigate to — i.e. your HTTPS proxy or load balancer URL, not the raw Next.js port (3003). NextAuth uses this for session cookie validation and redirects.
Identity
| Variable | Description | Example |
|---|---|---|
ISSUER_DID | Your issuer's DID. Must start with did: | did:web:issuer.yourorg.com |
ISSUER_DOMAIN | Domain used for OID4VCI audience validation | issuer.yourorg.com |
ISSUER_CATEGORY | Issuer vertical category | employer |
Valid ISSUER_CATEGORY values: government, employer, academic, learning-platform.
Signing keys
Set one of the following depending on your deployment mode:
| Variable | Mode | Description |
|---|---|---|
ISSUER_SIGNING_KEY | Self-hosted | Hex-encoded 32-byte signing key. All credentials are signed with this key. Generate with openssl rand -hex 32. |
ISSUER_MASTER_KEY | SaaS | Hex-encoded 32-byte HKDF master key. Per-tenant signing keys are derived from this. Store in a secrets manager — never commit to version control. |
Rotating
ISSUER_MASTER_KEYinvalidates the signatures on all previously issued credentials across all tenants. Plan rotation carefully.
Mode
| Variable | Description | Default |
|---|---|---|
SAAS_MODE | Set to true to enable multi-tenant SaaS mode | false |
Identity adapter
| Variable | Description | Example |
|---|---|---|
ADAPTER_TYPE | Identifier for the credential-subject data adapter | mock-gov-db |
ADAPTER_CONFIG | JSON string of adapter-specific non-secret settings | {"baseUrl":"https://ldap.yourorg.com"} |
Available adapter types: mock-gov-db, ldap, scim, student-registry.
Optional
| Variable | Description |
|---|---|
ISSUER_CONFIG_PATH | Absolute path to an alternative YAML config file. Useful for Docker volume mounts. |
PORT | Override the Next.js listen port (default: 3003). |
YAML configuration file
Non-secret settings live in issuer.config.yaml at the root of apps/issuer/. This file is safe to commit. An annotated reference is in issuer.config.example.yaml.
server:
port: 3003
host: 0.0.0.0
identity:
did: did:web:issuer.yourorg.com
domain: issuer.yourorg.com
category: employer
signing:
mode: self-hosted # "self-hosted" | "saas"
adapter:
type: ldap
config:
baseUrl: https://ldap.yourorg.com
baseDN: dc=yourorg,dc=com
YAML field reference
| Field | Type | Description |
|---|---|---|
server.port | integer | Port Next.js binds to (not the proxy port) |
server.host | string | Bind address |
identity.did | string | Issuer DID — must start with did: |
identity.domain | string | Domain for OID4VCI audience validation |
identity.category | string | Issuer vertical category |
signing.mode | "self-hosted" | "saas" | Signing key strategy |
adapter.type | string | Adapter identifier |
adapter.config | object | Adapter-specific non-secret settings |
Any value set in environment variables will override the corresponding YAML field.
Production checklist
Before deploying to production:
-
ISSUER_SIGNING_KEY(self-hosted) orISSUER_MASTER_KEY(SaaS) — generated fresh, stored in secrets manager -
NEXTAUTH_SECRET— generated fresh, stored in secrets manager -
NEXTAUTH_URL— set to your production HTTPS URL (notlocalhost) -
ISSUER_DID— set to your productiondid:web -
ISSUER_DOMAIN— set to your production domain -
DATABASE_URL— pointing to your production PostgreSQL instance -
SAAS_MODE— set correctly (truefor SaaS, leave unset for self-hosted)
Related pages
- Deployment Modes — self-hosted vs SaaS
- Getting Started — first-time setup
- SaaS Onboarding — tenant management in SaaS mode