Launch on 01/01/2027Licenses available from 01/01/2027
PreviewThis page documents the release that launches on 01/01/2027. Packages, images and sign-up open then, and details may change before it.
Docs / Reference / Configuration

Configuration

Ready
TL;DR

A deployment is configured entirely through environment variables — no config-file format to learn, and no secrets compiled into the binary. ydfi bootstrap writes a richly-commented .env with every variable documented inline; ydfi validate-env checks it before you boot. The surface is deliberately small — around 45 variables in total: a small set you must set (database, secrets, PKI, license, deployment URL), and the rest have sensible defaults you reach for only when a deployment genuinely needs them (mode, ports, logging, attestation policy). Anything more granular than that — rate-limit windows, cache sizes, background-worker cadence — is a compiled constant, not a variable, so there is nothing to misconfigure there.

Who this is for: whoever stands up or tunes a deployment. You should not need to write any of this by hand — Deploy and ydfi bootstrap generate it. This page is the map for when you want to know what a variable does.

How it works#

One mechanism, start to finish: environment variables.

There is no YAML, no TOML, no config file with its own syntax and its own bugs. Everything the server reads — connection strings, ports, key material, feature flags, every tuning constant — comes from the environment. That is a deliberate choice: it is the one configuration surface every container runtime, orchestrator, and secrets manager already knows how to fill, and it keeps secrets out of the binary and out of any file you might commit. The three cryptographic secrets are just variables like the rest; you generate them with ydfi secret generate-* and hand them in the same way.

The path from nothing to a running deployment is two commands and a check:

# writes a fully-commented .env + the PKI + the secrets $ ydfi bootstrap --license-file license.jwt --out .env # confirms every required variable is present and well-formed $ ydfi validate-env --env-file .env
ⓘ Production is a setting, and it fails closed

YDFI_SERVER_ENV takes production, development, or test. Production turns the safety checks on — strict TLS, no insecure bypasses, no dev fallbacks. development and test relax them for local work and are the only modes where the loud *_TEST_BYPASS escape hatches are honoured. A live deployment runs production; anything else is validated with a warning.

What you must set#

These have no safe default — the server refuses to start without them. ydfi bootstrap fills every one; the table is here so you know what each is for.

Every secret a deployment holdsThree, all held by the operator, each with a stated consequence of loss.SECRETWHAT IT DOESIF IT IS LOSTDeployment root keyheld by the operatorsigns every certificate in thedeploymentFull re-key. Every relying party lockedout until they install new materialStored-secret keyheld by the operatorencrypts what is held at restThose stored secrets cannot be recoveredAll three are read from the environment, and none is fetched from a vendorThere is no integration with any particular secrets service. The server reads configured paths andvariables; how those are filled — a mounted volume, a platform’s own secret store, a manual copy — isthe operator’s choice and stays their choice.
Three secrets a deployment holds, what each one does, and what its loss costs.
VariableWhatForm
YDFI_SERVER_DB_URIPostgres connection for the deployment.postgres://…
YDFI_PRIMARY_ENCRYPTION_KEYAES-256 key that encrypts TOTP secrets at rest. Supports a key-id so you can rotate.ID:KEY (6+64 hex)
YDFI_SERVER_LICENSE_PATHThe license JWT the deployment runs on. See Get a license.file path
YDFI_SERVER_DEPLOYMENT_URLThe public URL this deployment serves at. Enrollment and challenge QR links are built from it.https://…
YDFI_SERVER_TLS_CERT / _TLS_KEYThe mTLS leaf the RP-facing (identity) listener presents.file paths
YDFI_SERVER_CLIENT_CAThe CA the identity listener trusts to authenticate relying parties.cert file
YDFI_SERVER_PHONE_TLS_CERT / _TLS_KEY / _CLIENT_CAThe same three, for the unified phone listener (enrollment + auth-challenge delivery).file paths
YDFI_SERVER_ROOT_CA_CERT_PATH / _ROOT_CA_KEY_PATHSigns RotateCertificate responses when a relying party rotates its own cert.file paths
ⓘ One that is optional for a reason

YDFI_SERVER_LICENSE_VERIFY_KEYS_PATH is not required on a production build — the Ydentifi root every license chains to is compiled into it, and it refuses to start while the variable is set, so it must be left unset there. Only a development build reads it. See Get a license and Releases.

ⓘ Two more gotchas in this list

The phone-listener mTLS trio auto-generates from an in-process PKI fixture outside production — only a production build forces you to supply it. The root CA pair must be the same root your mTLS verifier already trusts, or a relying party that rotates its cert ends up with one that chains to nothing the server accepts.

A minimal .env#

ydfi bootstrap writes the full, richly-commented file; once the required core above is filled in, this is the shape it reduces to — a single .env a production deployment boots on. The secrets shown are placeholders (generate real ones with ydfi secret generate-*); the paths point at the PKI bootstrap emitted.

# Mode — production turns the safety checks on and fails closed. YDFI_SERVER_ENV=production YDFI_SERVER_DEPLOYMENT_URL=https://auth.acme.example # Database — must exist; the stack applies migrations before the server starts. YDFI_SERVER_DB_URI=postgres://ydentifi:PASSWORD@db.internal:5432/ydentifi?sslmode=verify-full # Secret — an ID:KEY pair. YDFI_PRIMARY_ENCRYPTION_KEY=a1b2c3:0f8e…d42 # License file. Verified at startup; a running server checks it for changes about once a minute. # In a container, mount the directory that holds it, never the file on its own. YDFI_SERVER_LICENSE_PATH=/etc/ydentifi/license.jwt # mTLS — RP-facing (identity) listener. YDFI_SERVER_TLS_CERT=/etc/ydentifi/pki/identity.crt YDFI_SERVER_TLS_KEY=/etc/ydentifi/pki/identity.key YDFI_SERVER_CLIENT_CA=/etc/ydentifi/pki/client-ca.crt # mTLS — phone listener (enrollment + challenge delivery). YDFI_SERVER_PHONE_TLS_CERT=/etc/ydentifi/pki/phone.crt YDFI_SERVER_PHONE_TLS_KEY=/etc/ydentifi/pki/phone.key YDFI_SERVER_PHONE_CLIENT_CA=/etc/ydentifi/pki/phone-client-ca.crt # Root CA — signs RotateCertificate; the same root your verifier trusts. YDFI_SERVER_ROOT_CA_CERT_PATH=/etc/ydentifi/pki/root-ca.crt YDFI_SERVER_ROOT_CA_KEY_PATH=/etc/ydentifi/pki/root-ca.key
ⓘ A production build needs no verify-keys path

There is deliberately no YDFI_SERVER_LICENSE_VERIFY_KEYS_PATH here — the Ydentifi root is compiled into a production binary, which refuses to start while the variable is set, so it stays unset. The two listener ports keep their defaults (50051 and 50052), as does everything under the tuning knobs. Run ydfi validate-env before boot.

Commonly set#

These have defaults, so they are optional — but they are the ones you actually reach for.

VariableWhatDefault
YDFI_SERVER_ENVMode: production / development / test. Selects which safety checks apply.—
YDFI_SERVER_PORTThe RP-facing (identity) gRPC listener.50051
YDFI_SERVER_PHONE_PORTThe unified device listener (onboard + gateway on one port).50052
YDFI_ADMIN_SERVER_PORTThe admin gRPC listener, when the admin server runs.50060
YDFI_ADMIN_SERVER_BIND_ADDRLoopback by default; set 0.0.0.0 deliberately to expose admin remotely (pair with a firewall).127.0.0.1
YDFI_SERVER_MANAGEMENT_PORTpprof + the public Prometheus scrape.6060
YDFI_SERVER_INTERNAL_METRICS_PORTThe full metric surface, behind mTLS, for internal-only cardinality. The public scrape above works either way.0 (off)
YDFI_SERVER_LOG_LEVEL / _LOG_FORMATVerbosity, and text vs JSON for log aggregation. Security events are written at any level.—
YDFI_SERVER_ENABLE_REFLECTIONgRPC reflection on the relying-party listener, so tools can explore the API without proto files. The phone listener never serves it. Off in production unless you want it.false
YDFI_SERVER_SERVICE_NAMEOTel resource name — matters once multiple instances feed one collector.ydentifi-server
YDFI_SERVER_OTEL_COLLECTOR_URL / _OTEL_SAMPLE_RATEOpenTelemetry tracing, if you run a collector.—

The tuning knobs#

A short, deliberate list — everything else is fixed.

Per-RPC rate-limit windows, cache sizes, and background-worker cadences are not environment variables. They're calibrated as a set — each one sized relative to its neighbors — and letting a deployment override one in isolation risks silently weakening the anti-abuse posture between them without anything catching it. What's left is what's genuinely deployment-specific:

…_DB_MAX_CONNS · …_DB_MIN_CONNS
…_DB_MAX_IDLE_TIME
The Postgres connection pool — size it to your Postgres instance.
…_ATTESTATION_PROFILE
Which platform-attestation checks the server enforces before it trusts a device. Three tiers — in full, below.
…_ATTESTATION_APPLE_TEAM_ID · _APPLE_BUNDLE_ID
…_ANDROID_PACKAGE_NAME · _ANDROID_SIGNING_CERT_SHA256
Which app the profile above checks against. Defaults match Ydentifi’s published apps; override only if you embed the SDK in your own app instead of running ours.
…_SHUTDOWN_TIMEOUT
…_STREAM_MAX_CONNECTION_AGE
Graceful-shutdown grace period (coordinate with your orchestrator's termination grace period), and how often long-lived streams re-handshake.

The attestation profile, in full:

strict
App Attest + Play Integrity + Android Key Attestation. Requires the deploying entity to run its own Google Cloud Project — Play Integrity tokens are encrypted to a key bound to it.
hardware-only
Default for production. App Attest + Android Key Attestation only — no Play Integrity, no Google Cloud Project needed. Keeps the hardware, verified-boot, and app-identity signals; gives up Play Protect’s app-safety verdict and the “installed from Play Store” signal.
off
Default in development/test. Accepts all attestations unconditionally. Reasonable for on-prem or VPN-only deployments, where mTLS plus a device key held behind a biometric check already covers most of what platform attestation adds.

That's the complete list. Rate-limit windows, cache sizes, and reaper cadences ship as fixed, load-tested defaults — there is no environment variable for them.

ⓘ No retention variable for history, by design

There is no setting for how long the deployment keeps a device’s history or the record of what the server did, because it keeps neither: both are log lines on your log pipeline, and their retention is whatever that pipeline already does. A period chosen here would be Ydentifi deciding when your records expire, and a default of any length is wrong for someone — PCI DSS wants twelve months, GDPR pushes the other way, and SOC 2 tests only that you honour whatever you wrote down. Capture standard output, or there is no record.

Validate before you boot#

Configuration mistakes should fail on your terminal, not at start-up in production. ydfi validate-env reads a .env and checks every variable — required ones present, secrets the right length, ports in range, cert files that parse, the deployment URL well-formed — and tells you, per line, what passed, what is a warning, and what would fail.

$ ydfi validate-env --env-file .env ✓ YDFI_SERVER_DB_URI postgres://ydentifi:***@db:5432/ydentifi ✓ YDFI_PRIMARY_ENCRYPTION_KEY 1 key pair(s) ✓ YDFI_SERVER_LICENSE_PATH /etc/ydentifi/license.jwt ! YDFI_SERVER_PORT not set — server will use its compiled default ✓ all checks passed

It is a static check of the file, so it is safe to run anywhere and worth wiring into CI. It does not connect to the database or contact the licensing server — it confirms the shape of the configuration, so the deployment that boots on it boots clean.

Opens on 01/01/2027

Available at launch

Until then, you can try the whole ceremony on your own phone.