Skip to content

Environment Variables

All ProtocolSoup backend services share a common set of core variables. Individual services add protocol-specific configuration on top.

Variable Default Description
SHOWCASE_BASE_URL http://localhost:8080 Public URL used in endpoint URLs, redirect URIs, and token issuer claims. In production this must be a pathless HTTPS origin with no trailing slash, query, or fragment.
SHOWCASE_LISTEN_ADDR :8080 Address and port the service binds to.
SHOWCASE_CORS_ORIGINS http://localhost:3000,http://localhost:5173 Comma-separated list of allowed CORS origins for browser clients.
SHOWCASE_ENV demo Runtime environment.
BUILD_COMMIT (empty) Full deployed source commit exposed by /health. Production deployment workflows set this automatically so conformance evidence can be bound to an immutable build. The wallet harness uses the same variable.
SHOWCASE_MOCK_IDP true Enable built-in mock identity provider with demo users and clients.
SHOWCASE_DEBUG false Enable debug logging.
SHOWCASE_PALETTE_DB (empty — palette disabled) Path to the prebuilt palette SQLite index. Required in SHOWCASE_ENV=production when palette search is enabled. Docker images built from Dockerfile.backend and Dockerfile.fly default to /app/palette.db. See Palette content index.
Variable Default Description
OAUTH2_REPLAY_REDIS_URL (in-memory in development/tests) Redis URL for atomic private_key_jwt (client_id, jti) replay reservations through exp + 60s. Also backs the RFC 9449 DPoP proof jti replay stores for both oauth2 and OID4VCI (distinct key prefix and instance from the private_key_jwt store). Production accepts a reachable rediss:// URL, and fails startup without it or when it cannot be reached. Runtime Redis errors fail the token request closed with server_error. Local Compose supplies an isolated Redis instance. Store production credentials as a platform secret.
SHOWCASE_DPOP_NONCE_REQUIRED false Enables the RFC 9449 §8 server-provided nonce challenge at authorization-server token endpoints – oauth2’s /oauth2/token and OID4VCI’s own /oid4vci/token. Off by default: DPoP itself remains fully functional without it, since RFC 9449 treats the nonce as optional hardening, not a baseline requirement. When enabled, a proof lacking the current nonce is rejected with use_dpop_nonce and a DPoP-Nonce response header; the client retries with a fresh proof echoing that value.
SHOWCASE_DPOP_RESOURCE_NONCE_REQUIRED false Enables the same challenge, independently, at OID4VCI’s resource-server endpoints (/oid4vci/credential, /oid4vci/nonce, /oid4vci/deferred_credential) for tokens bound via DPoP. Kept as a separate switch from SHOWCASE_DPOP_NONCE_REQUIRED because RFC 9449 §8.2 requires the AS and RS nonce spaces to be independent, even where – as with OID4VCI issuing and validating its own tokens – both roles run in the same process.
SSF_STREAM_CLIENT_SECRET (auto-generated) Secret for the seeded ssf-stream-client confidential client (client_credentials, ssf.read / ssf.manage). Pin as a platform secret in production so Stream Management tokens stay usable across restarts. The current secret is listed at GET /oauth2/demo/clients.
Variable Default Description
OIDC_DYNAMIC_REGISTRATION_ENABLED true Enables open Dynamic Client Registration at POST /oidc/register and advertises registration_endpoint / request_uri_parameter_supported only when true.
OIDC_DYNAMIC_REGISTRATION_TTL 2h Lifetime of dynamically registered clients. Expired clients are removed from the in-memory store.
OIDC_DYNAMIC_REGISTRATION_MAX_CLIENTS 200 Maximum number of live dynamic clients. Further registrations return invalid_client_metadata.
OIDC_DYNAMIC_REGISTRATION_RATE_LIMIT 30 Maximum registration attempts per source key within the rate window.
OIDC_DYNAMIC_REGISTRATION_RATE_WINDOW 1m Sliding window used by the registration rate limiter.
OIDC_PAIRWISE_SUBJECT_SALT (generated in-memory when empty) Durable secret used to derive deterministic OIDC pairwise subjects. Set a platform secret in production so pairwise sub values remain stable across restarts.
OIDC_KEY_ROTATION_TOKEN (empty — disabled) Bearer token required for POST /oidc/admin/rotate-keys. Leave empty to keep the rotation endpoint disabled.
Variable Default Description
FEDERATION_SERVICE_URL - Upstream URL for the federation service.
SCIM_SERVICE_URL - Upstream URL for the SCIM service.
SSF_SERVICE_URL - Upstream URL for the SSF service.
SPIFFE_SERVICE_URL - Upstream URL for the SPIFFE service.
VC_SERVICE_URL - Upstream URL for the VC service (if separate from federation).
Variable Default Description
SCIM_API_TOKEN - Bearer token required for all SCIM API requests and outbound client operations. The SCIM service refuses to start without it in production.
SCIM_RETENTION 24h Go duration after which visitor-created SCIM users and groups are deleted, based on updated_at. 0 disables the reaper. After each sweep, demo users and groups are re-seeded.
Variable Default Description
LOOKINGGLASS_SESSION_IDLE_TTL 30m Idle lifetime of an in-memory Looking Glass session, measured from last activity (updated_at).
LOOKINGGLASS_SESSION_MAX_TTL 4h Absolute lifetime of an in-memory Looking Glass session, measured from creation. Connected websockets are closed on eviction.
Variable Default Description
SSF_RECEIVER_TOKEN - Bearer token the receiver accepts for event delivery.
SSF_AS_ISSUER - Authorization server iss checked on Stream Management access tokens.
SSF_AS_JWKS_URI - JWKS URL used to verify Stream Management bearer JWTs. When set, those APIs require Authorization: Bearer or X-Looking-Glass-Session.
SSF_AS_INTROSPECT_URI - RFC 7662 introspection URL used by the split SSF Transmitter to check Stream Management token revocation.
SSF_RESOURCE SHOWCASE_BASE_URL JWT aud the SSF Transmitter expects. The OAuth 2.0 token endpoint issues ssf.read / ssf.manage client-credentials tokens with this audience and a 900 second lifetime.
FEDERATION_SERVICE_URL loopback from listen addr On the SSF service, federation base URL for CAEP revoke-subject. Compose: http://federation-service:8080. Fly/monolith: http://127.0.0.1:8080.
SSF_TO_FEDERATION_TOKEN - Shared bearer token; set on both SSF and federation. Production secret — set via fly secrets set, never via committed config. Without it the CAEP session-revoked demo hop returns 401.
Variable Default Description
SPIFFE_AGENT_SOCKET /run/spire/sockets/agent/agent.sock Path to the SPIRE agent Workload API socket. Required for full SPIRE mode.
SPIFFE_TRUST_DOMAIN protocolsoup.local SPIFFE trust domain.
Variable Default Description
WALLET_TARGET_BASE_URL https://protocolsoup.com URL of the VC verifier/issuer service for OID4VP submissions and the default OID4VCI target.
WALLET_ALLOWED_CORS_ORIGINS https://protocolsoup.com,https://www.protocolsoup.com,https://protocolsoup.fly.dev Comma-separated allowed browser origins.
WALLET_DEFAULT_SUBJECT did:example:wallet:alice Default holder DID seed for demo sessions. It identifies wallet key material, not an issuer identity-record ID; automatic OID4VCI bootstrap uses the issuer’s designated default identity.
WALLET_DEFAULT_CREDENTIAL_FORMAT mso_mdoc Default stored and presented credential format when a request does not name a format or configuration. mso_mdoc is the default (the mDL); dc+sd-jwt and the W3C formats remain selectable.
WALLET_DID_METHOD key DID method for the wallet holder identifier (e.g. key, web).
WALLET_DEFAULT_SIGNING_ALG ES256 Default holder-binding signing algorithm. ES256 (EC P-256) matches the mso_mdoc default; other wallet-supported algorithms apply to the JOSE formats.
WALLET_SESSION_TTL 20m Go duration for in-memory session lifetime.
WALLET_STRICT_SESSION_ISOLATION true Enforce strict session boundaries between demo runs.
WALLET_ALLOW_EXTERNAL_VERIFIERS true Allow OID4VP request_uri and OID4VCI endpoint fetches outside the configured target/issuer origin. External destinations must be HTTPS. The wallet resolves DNS, re-validates redirects, and refuses private, loopback, link-local, multicast, or shared-address destinations. Failed request_uri fetches report HTTP status without reflecting upstream bodies.
WALLET_TRUSTED_VERIFIER_ATTESTATION_ISSUERS (empty) Comma-separated issuer URLs the wallet trusts for verifier_attestation request validation.
WALLET_DEVICE_KEY_PATH (empty) File path for the persistent mso_mdoc holder device key (EC P-256). Empty uses an ephemeral key; set a durable path so stored mdoc device bindings survive restarts.
WALLET_VERIFIER_X509_TRUST_ANCHOR_PEM System roots only Additional PEM CA trust anchors used when the wallet validates x509_san_dns and x509_hash request-object chains. Certificates carried in x5c are untrusted chain material and are never promoted to roots. Hosted ProtocolSoup CI copies the last certificate from {SHOWCASE_DATA_DIR}/oid4vp/x509_request_signer_chain.pem into this secret.
WALLET_MDOC_IACA_ROOT_PEM (unset) PEM-encoded IACA root certificate(s) the wallet trusts before storing an issued mso_mdoc. Without an explicit root the wallet rejects mdoc issuance rather than trusting the credential’s own x5chain. Multiple PEMs are additive.
WALLET_CLIENT_ATTESTATION_ATTESTER_JWK_JSON (unset) Attester private JWK (+ x5c) used to mint OAuth-Client-Attestation JWTs. Together with WALLET_CLIENT_ATTESTATION_KEY_ATTESTATION_JWK_JSON, enables the wallet HAIP issuance path.
WALLET_CLIENT_ATTESTATION_KEY_ATTESTATION_JWK_JSON (unset) Attester private JWK (+ x5c) used to mint OID4VCI Appendix D key_attestation JWTs for HAIP credential proofs.
WALLET_OID4VCI_ATTESTED_CLIENT_ID protocolsoup-wallet Attested client_id / attestation JWT sub when HAIP attestation material is configured.
WALLET_CLIENT_ATTESTATION_ISSUER https://wallet.protocolsoup.com/attester iss claim on client attestation JWTs.
WALLET_KEY_ATTESTATION_KEY_STORAGE (unset) Comma-separated key_storage attack-potential levels asserted in key attestation (for example iso_18045_moderate). Omit unless the claim is honest for this software wallet.
WALLET_KEY_ATTESTATION_USER_AUTHENTICATION (unset) Comma-separated user_authentication attack-potential levels asserted in key attestation. Omit unless honest.

OID4VP Verifier (VC And Federation Services)

Section titled “OID4VP Verifier (VC And Federation Services)”
Variable Default Description
OID4VP_VERIFIER_ATTESTATION_ISSUER <SHOWCASE_BASE_URL>/oid4vp/verifier-attestation Issuer URL published for verifier attestation metadata and JWKS.
OID4VP_VERIFIER_ATTESTATION_CLIENT_ID verifier_attestation:<SHOWCASE_BASE_URL host> Verifier client_id used when client_id_scheme=verifier_attestation.
OID4VP_VERIFIER_ATTESTATION_PRIVATE_KEY_PEM Ephemeral in-memory key PEM-encoded stable signing key for verifier attestation JWTs and JWKS. Set this in production so attestation validation survives restarts and deploys.
OID4VP_X509_SANDNS_CLIENT_ID x509_san_dns:<SHOWCASE_BASE_URL host> Verifier client_id used when client_id_scheme=x509_san_dns. Must match a DNS SAN on the leaf certificate.
OID4VP_X509_SANDNS_CERT_CHAIN_PEM Ephemeral generated chain PEM-encoded certificate material for x509_san_dns and x509_hash. The request object’s x5c contains the leaf/intermediate chain and excludes the root trust anchor. When unset, a CA + leaf are generated and persisted under {DataDir}/oid4vp when a data directory is configured.
OID4VP_X509_SANDNS_PRIVATE_KEY_PEM Ephemeral key PEM-encoded private key matching the leaf certificate used for x509_san_dns / x509_hash request signing. When unset, generated alongside the auto-provisioned chain. Set both PEM variables to pin an externally issued certificate.
OID4VP_SD_JWT_TRUST_ANCHOR_PEM (unset) PEM CA root(s) trusted for independently issued certificate-backed SD-JWT VC presentations (no first-party issuance lineage). The credential x5c must contain only leaf/intermediate certificates and chain to this independently configured root. First-party HAIP dc+sd-jwt credentials that match issuance lineage do not need this variable: their Token Status List is verified with the same issuer key already bound to the credential.
OID4VP_SD_JWT_TRUST_ANCHOR_PEM_FILE (unset) File containing the SD-JWT VC issuer trust anchor PEM when the inline variable is not used.
MDOC_IACA_ROOT_PEM (unset) PEM-encoded external ISO/IEC 18013-5 IACA root certificate(s) the verifier trusts for mso_mdoc presentations. These roots are combined with roots loaded from MDOC_IACA_ROOT_PEM_FILE and the local issuer’s persisted iaca_root.pem.
MDOC_IACA_ROOT_PEM_FILE (unset) Path to additional IACA root PEM(s). File roots, inline roots, and the issuer-persisted root under SHOWCASE_MDOC_PKI_PATH or {DataDir}/mdoc are additive, allowing a combined issuer/verifier deployment to validate both external and locally issued mdocs.
SHOWCASE_MDOC_PKI_PATH {DataDir}/mdoc (else ephemeral) Persistent store directory for the OID4VCI issuer’s ISO/IEC 18013-5 mso_mdoc PKI (IACA root + document-signer chain). The OID4VP verifier loads the same iaca_root.pem here as its mso_mdoc trust anchor. Point this at a durable volume in any deployment that issues and verifies mso_mdoc in the same app. When neither this nor a data dir is set, the issuer PKI is ephemeral (regenerated on each boot) and the verifier has no trust anchor, so every mso_mdoc presentation is denied with mdoc_trust_anchor_unavailable.
Variable Default Description
MDOC_ISSUER_COUNTRY US Two-letter country code used in the ISO/IEC 18013-5 issuer PKI (IACA root and document-signer) certificate subjects.
MDOC_ISSUER_ORG ProtocolSoup Organization name used in the ISO/IEC 18013-5 issuer PKI certificate subjects.
OID4VCI_CLIENT_ATTESTATION_TRUST_ANCHOR_PEM (unset) PEM-encoded CA certificate(s) the issuer trusts to anchor the x5c chain on incoming OAuth 2.0 Attestation-Based Client Authentication JWTs (OAuth-Client-Attestation header, draft-ietf-oauth-attestation-based-client-auth). Required to accept client_attestation client authentication at the token endpoint. When unset, the issuer refuses any request that presents attestation headers (invalid_client) rather than silently downgrading to a weaker method; credential issuer metadata’s token_endpoint_auth_methods_supported also omits attest_jwt_client_auth in that case.
OID4VCI_KEY_ATTESTATION_TRUST_ANCHOR_PEM (unset) PEM-encoded CA certificate(s) the issuer trusts to anchor the x5c chain on OID4VCI 1.0 Appendix D.1 Key Attestation JWTs carried in the proof JWT’s key_attestation JOSE header. Required for credential configurations that set key_attestations_required (e.g. MobileDrivingLicenceMsoMdocHAIP). When unset, a credential request against a key-attestation-required configuration is rejected with invalid_proof.
  • SHOWCASE_BASE_URL is the most important variable. It determines the issuer, entity ID, redirect URIs, and metadata URLs across all protocols. Always set it to the origin your clients actually use. Production startup fails unless it is a pathless HTTPS origin such as https://protocolsoup.example.com (no trailing slash or subpath). In development, the OAuth RFC 8414 metadata endpoint returns 503 for an HTTP or pathful base URL rather than publishing a non-conformant issuer.
  • Production OAuth deployments must set OAUTH2_REPLAY_REDIS_URL as a secret using rediss://. Do not place Redis credentials in Compose files, fly.toml, or source control.
  • When running behind a reverse proxy or load balancer, set SHOWCASE_BASE_URL to the external URL (e.g. https://protocolsoup.example.com) rather than the internal address.
  • SHOWCASE_CORS_ORIGINS must include the origin of your frontend. If the UI is at https://app.example.com, add that origin.
  • For SCIM, set SCIM_API_TOKEN to any secret string. Clients must include Authorization: Bearer <your-token> on every request.
  • To enable real verifier_attestation OID4VP flows, publish the verifier issuer URL from the verifier service and add that issuer to the wallet’s WALLET_TRUSTED_VERIFIER_ATTESTATION_ISSUERS allow-list.
  • x509_san_dns and the HAIP x509_hash prefix work out of the box. When the PEM env vars are unset, an ECDSA P-256 CA + leaf certificate chain is auto-provisioned with the leaf SAN bound to the deployment hostname from SHOWCASE_BASE_URL; with a data dir it is persisted under {DataDir}/oid4vp and reloaded on restart so the x509_hash client_id stays stable across restarts (wallets that pin by leaf hash keep a consistent verifier identity). Provide your own PEM chain and key to pin an externally issued certificate.
  • To verify mso_mdoc (ISO/IEC 18013-5) presentations, point the verifier at the issuer’s IACA root via MDOC_IACA_ROOT_PEM (or MDOC_IACA_ROOT_PEM_FILE). The trust anchor is the IACA root, never the document-signer certificate. When the issuer and verifier run in the same deployment, set SHOWCASE_MDOC_PKI_PATH (or SHOWCASE_DATA_DIR) to a durable volume so the issuer persists iaca_root.pem and the verifier loads it automatically as its trust anchor; without it the PKI is ephemeral and presentations are denied with mdoc_trust_anchor_unavailable.