Skip to content

Configuration

Configuration is loaded with precedence environment variables → config file → built-in defaults (highest first). The config file is entra-emulator.config.json in the working directory, or the path in CONFIG_FILE; an absent file is not an error. The merged object is validated at startup; any failure aborts with a non-zero exit naming the offending key(s) — no partial boot.

Env keyConfig-file fieldTypeDefaultDescription
HOSThoststringlocalhostBind host (bind-only; does not affect advertised origins). Docker uses 0.0.0.0.
PORTportint 1–655358443Listen port.
TENANT_IDtenantIdGUID11111111-1111-1111-1111-111111111111The single fixed tenant; also the allowlisted {tenant} path value.
ORIGIN_MODEoriginModesubdomains | compatsubdomainssubdomains advertises login./portal./graph.<baseDomain>; compat collapses every advertised origin to https://localhost:<port>.
BASE_DOMAINbaseDomainhostnameentra.localhostApex for the three subdomains and the wildcard cert.
LOCAL_DOMAINSlocalDomainsCSV → []stringemptyExtra apex domains; each adds cert SANs (apex + wildcard) and hosts-file entries.
PUBLIC_ORIGINpublicOriginURLderivedWhen set, all three origins collapse to it (legacy single-origin).
LOGIN_ORIGIN / PORTAL_ORIGIN / GRAPH_ORIGINloginOrigin etc.URLderivedPer-surface overrides; win over PUBLIC_ORIGIN and ORIGIN_MODE.
ISSUERissuerURL${loginOrigin}/${tenantId}/v2.0Must equal discovery issuer and token iss.
DB_PATHdbPathpath./data/entra-emulator.dbSQLite file.
TLS_ENABLEDtls.enabledbooltruefalse → plain HTTP on loopback.
TLS_CERT / TLS_KEYtls.certPath / tls.keyPathpathautoCustom PEM pair; setting exactly one is a validation error.
TLS_CERT_DIRtls.certDirpath./data/tlsWhere the auto-generated cert/key persist.
REQUIRE_PASSWORDrequirePasswordboolfalsePassword form instead of the account picker.
REQUIRE_CONSENTrequireConsentboolfalseShow a consent screen during authorize before issuing the code.
SEED_ON_STARTseedOnStartbooltrueApply the deterministic seed when the DB has no tenant row.
TOKEN_LIFETIME_AUTH_CODE_SECONDStokenLifetimes.authCodeint300Auth code TTL (single-use).
TOKEN_LIFETIME_ID_SECONDStokenLifetimes.idTokenint3600ID token TTL.
TOKEN_LIFETIME_ACCESS_SECONDStokenLifetimes.accessTokenint3600Access token TTL.
TOKEN_LIFETIME_REFRESH_SECONDStokenLifetimes.refreshTokenint86400Refresh token TTL (rotating, rolling).
TOKEN_LIFETIME_DEVICE_CODE_SECONDStokenLifetimes.deviceCodeint900Device code TTL.
DEVICE_CODE_INTERVAL_SECONDSdeviceCodeIntervalint5Advertised device-code poll interval.
GRAPH_RESOURCE_IDgraphResourceIdstringhttps://graph.microsoft.comDefault audience for Graph access tokens.
MANAGED_IDENTITY_SECRETmanagedIdentitySecretstringmanaged-identity-secretMatched against X-IDENTITY-HEADER on /msi/token (dev value).
MANAGED_IDENTITY_CLIENT_IDmanagedIdentityClientIdGUIDseeded daemon appThe system-assigned managed identity’s appId.
LOG_LEVELlogLevelenuminfo`error
CONFIG_FILEpath./entra-emulator.config.jsonConfig-file location.

Origin derivation (order of precedence per surface)

Section titled “Origin derivation (order of precedence per surface)”
  1. Explicit per-surface override (LOGIN_ORIGIN / PORTAL_ORIGIN / GRAPH_ORIGIN).
  2. PUBLIC_ORIGIN — collapses all three to one origin.
  3. ORIGIN_MODE=compat — collapses all three to ${scheme}://localhost:${port}.
  4. Default: ${scheme}://{login|portal|graph}.${baseDomain}:${port}.

issuer derives from the resolved login origin unless ISSUER is set explicitly. HOST/PORT are bind-only and never leak into advertised URLs (a container binds 0.0.0.0 while advertising localhost).

  • TENANT_ID must be a lowercase GUID; PORT in range; origins/issuer must parse as URLs.
  • Exactly one of TLS_CERT/TLS_KEY set → error (“both or neither”).
  • Lifetimes must be positive integers.
  • The frozen, validated config struct is the single source read by every package.