You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 34e3318
Browse filesBrowse the repository at this point in the historyBrowse files
authored
Control credential caches through environment variables (#40)
Co-authored-by: James Xian <jamesxian@microsoft.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copy file name to clipboardExpand all lines: README.md
+3-2Lines changed: 3 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -50,7 +50,7 @@ The single-region request flow is:
50
50
51
51
The diagram's delivery path describes **live requests**. An authorized, valid encrypted
52
52
**evaluation request (`mode: 2`)** returns the matching nonce without submitting a message to the
53
-
provider. Background credential refresh can still run independently. Authentication failures may
53
+
provider. With caching enabled, background credential refresh can still run independently. Authentication failures may
54
54
return **401 or 403**; neither is a successful evaluation.
55
55
56
56
**East US in the diagram is illustrative, not a required or guaranteed deployment location.**
@@ -231,7 +231,8 @@ not just a locally running Function.
231
231
| Controlled live test | The provider accepts the selected SMS or voice request and the test recipient receives the message or call. Provider acceptance alone is not proof of delivery. |
232
232
| Operational visibility | Review Application Insights for the request outcome without recording phone numbers, message bodies, tokens, private keys, or nonce values in shared logs. |
233
233
234
-
Configured workers can acquire credentials at startup without sending an OTP; JavaScript/Python
234
+
With the selected [credential cache](docs/CONTRACT.md#credential-caching-and-refresh) enabled,
235
+
configured workers can acquire credentials at startup without sending an OTP; JavaScript/Python
235
236
also poll for refresh, whereas .NET retrieves replacements on cache misses. Check collected
236
237
`credential_refresh_failed` warnings before live testing; an evaluation success or absence of
Copy file name to clipboardExpand all lines: TECHNICAL.md
+11-4Lines changed: 11 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -178,6 +178,8 @@ how code accesses configuration, not the environment-variable names.
178
178
|`EPP_PROVIDER_TENANT_ID`, `EPP_PROVIDER_SCOPE`| Soprano OAuth | Provider tenant and selected API scope. |
179
179
|`EPP_OUTBOUND_CLIENT_ID`, `EPP_OUTBOUND_MI_CLIENT_ID`| Soprano OAuth | Existing multitenant application and outbound user-assigned managed identity used for client-assertion exchange. |
180
180
|`EPP_PROVIDER_TIMEOUT_MS`| Optional | Decimal milliseconds. Defaults to `1500`, capped at `2500`; not an end-to-end deadline. |
181
+
|`EPP_KEY_VAULT_CACHE_ENABLED`| Optional |`true` enables provider API-key bundle caching; `false` reads the bundle for each live request. Unset defaults to `true`. |
|`EPP_PROVIDER_ACCOUNT_NAME`| Adapter-dependent | Sender/account metadata, not an API key or credential identity. |
182
184
|`KEY_VAULT_URL`| Provider credential lookup | URI of the vault containing the manifest-named provider secrets. Separate from the encryption-key reference. |
183
185
|`AZURE_CLIENT_ID`| Optional | User-assigned managed identity's client ID for Key Vault. Leave unset for system-assigned identity. |
@@ -198,13 +200,18 @@ login; ordinary local machines have no managed-identity endpoint. Use offline te
198
200
evaluation locally, or an explicitly injected test resolver for integration work. Never commit local
199
201
settings, keys or test credentials.
200
202
201
-
Configured providers are [prepared per worker](docs/CONTRACT.md#credential-caching-and-refresh).
203
+
When their selected cache is enabled, configured providers are
204
+
[prepared per worker](docs/CONTRACT.md#credential-caching-and-refresh).
202
205
JavaScript/Python warm credentials and poll for refresh; .NET warms at startup and retrieves
203
206
replacements on cache misses, without a periodic poller. Credential acquisition never sends an OTP.
204
207
Evaluation skips provider work, but configured workers can independently acquire credentials at
205
-
startup. Leave `EPP_PROVIDER_NAME` unset for local evaluation-only work without credential acquisition.
206
-
The setup-written cache switches do not change current checked-in runtime behavior; verify your
207
-
selected package rather than assuming plan selection enables/disables caching.
208
+
startup. Disabling the selected cache skips startup preparation, polling, and cross-request reuse,
209
+
but live requests still acquire credentials. Each switch accepts trimmed, case-insensitive `true` or
210
+
`false`; an invalid selected value fails live credential resolution closed without preventing evaluation.
211
+
The other provider-auth mode's switch is ignored. Setup writes both as `false` for FC1 or `true` for
212
+
EP1; older packages that do not read these settings still require a supporting release. Restart after
213
+
changes. Leave `EPP_PROVIDER_NAME` unset or disable its cache for local evaluation-only work without
214
+
credential acquisition. Platform-managed identity caching and decryption-key references are separate.
208
215
209
216
Core Tools does not resolve Azure Key Vault reference expressions locally. Supply the local test PEM
210
217
or base64 PEM directly; use a reference such as `@Microsoft.KeyVault(SecretUri=https://<vault>.vault.azure.net/secrets/<private-key-secret>/)`
Copy file name to clipboardExpand all lines: docs/CONTRACT.md
+26-10Lines changed: 26 additions & 10 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -125,7 +125,8 @@ there is no API-key fallback. Evaluation skips acquisition. A provider rejection
125
125
Tokens are treated as opaque: the Function checks SDK expiry metadata, not custom JWT claims.
126
126
Soprano remains responsible for signature, issuer, audience, expiry, permissions, and account validation.
127
127
128
-
Credential instances and their SDK caches are reused for the configured tenant/application/identity.
128
+
With `EPP_ACCESS_TOKEN_CACHE_ENABLED=true` (the default), credential instances and their SDK caches
129
+
are reused for the configured tenant/application/identity.
129
130
JavaScript/Python use a [worker-local refresh loop](#credential-caching-and-refresh) for both
130
131
exchange stages. .NET warms at startup and fetches a replacement on a cache miss; it has no poller.
131
132
JavaScript bounds shared acquisition to 2.5 seconds independently of individual waiters;
@@ -135,7 +136,7 @@ in the installed SDK. Python bounds caller waits and SDK connect/read inactivity
135
136
shared synchronous retrieval may finish after a waiter leaves. It uses `get_token_info` for refresh
136
137
hints when supported, otherwise `get_token`; a failed acquisition never falls back to another API.
137
138
138
-
Credential SDK transport retries are disabled. JavaScript/Python failed refreshes use the polling
139
+
Credential SDK transport retries are disabled. With caching enabled, JavaScript/Python failed refreshes use the polling
139
140
cadence below; .NET retries credential acquisition on a later cache miss. These are not end-to-end
140
141
delivery deadlines. JavaScript suppresses SDK logs in the
141
142
acquisition's asynchronous context. Python filters Azure Identity/Core/MSAL records on configured
@@ -200,9 +201,10 @@ are needed. Platform authentication and resolution of the decryption-key referen
200
201
network access. Core Tools has no Easy Auth; local evaluation must remain loopback-only, without tunnels.
201
202
202
203
This describes the evaluation **request path**. Independently, workers with a configured provider
203
-
automatically prewarm and refresh credentials, even if their current traffic is evaluation-only.
204
+
and its cache enabled prepare credentials at startup; JavaScript/Python also poll for refresh,
205
+
even if their current traffic is evaluation-only.
204
206
No background task dispatches an OTP. A worker without `EPP_PROVIDER_NAME` performs no credential
205
-
prewarming, and evaluation does not require that prewarming succeed.
207
+
prewarming. Disabling the selected cache also suppresses this preparation; evaluation never requires it to succeed.
206
208
207
209
There is no diagnostic environment flag. A live request is not an evaluation request. Adapter-specific
208
210
wire fields, where required by an API, remain internal and cannot enable a separate non-delivery mode.
@@ -301,6 +303,8 @@ Set by provisioning. **Identical names across all languages.**
301
303
|`EPP_OUTBOUND_CLIENT_ID`, `EPP_OUTBOUND_MI_CLIENT_ID`| client application and user-assigned identity used for Soprano client-assertion exchange |
302
304
|`EPP_PROVIDER_ACCOUNT_NAME`| sender/source only when required by the selected provider |
303
305
|`EPP_PROVIDER_TIMEOUT_MS`| trimmed ASCII decimal milliseconds; default 1500 for missing/invalid/nonpositive values; capped at 2500. Not a whole-invocation deadline |
306
+
|`EPP_KEY_VAULT_CACHE_ENABLED`|`true`/`false`: API-key bundle caching and startup/refresh; unset defaults to `true`|
307
+
|`EPP_ACCESS_TOKEN_CACHE_ENABLED`|`true`/`false`: OAuth credential caching and startup/refresh; unset defaults to `true`|
304
308
|`EPP_DECRYPTION_KEY_PEM`| single RSA private key for JWE decryption, PEM or base64-encoded PEM; use a Key Vault secret reference in Azure, not a plaintext private key in shared settings |
305
309
|`EPP_ENCRYPTION_KEY_ID`| optional expected JWE `kid`; after successful decryption, a mismatch emits only `encryption_key_id_mismatch`. Advisory, not a key selector or authentication check |
306
310
|`KEY_VAULT_URL`| Key Vault URI for API-key providers |
@@ -342,10 +346,22 @@ subscription activation and changing tenant policy belong to provisioning, not t
342
346
343
347
Provider credentials are process-local, distinct from the platform-resolved decryption-key
344
348
reference. Credential acquisition never sends an OTP or changes caller authentication.
345
-
Restart workers after configuration changes. The setup-written
346
-
`EPP_KEY_VAULT_CACHE_ENABLED` / `EPP_ACCESS_TOKEN_CACHE_ENABLED` switches are not read by the
347
-
current checked-in implementations; verify the selected release before relying on plan-specific
348
-
cache control.
349
+
All runtimes use `EPP_KEY_VAULT_CACHE_ENABLED` for the selected `apiKey` provider or
350
+
`EPP_ACCESS_TOKEN_CACHE_ENABLED` for the selected `oauth` provider. The switches are independent;
351
+
runtime selection does not depend on the hosting plan. Unset defaults to enabled. Values accept
352
+
trimmed, case-insensitive `true` or `false`; blank or other explicit selected values fail live
353
+
credential acquisition closed with a sanitized warning, without blocking evaluation.
354
+
Restart workers after configuration changes. Setup writes both as `false` for FC1 or `true` for EP1;
355
+
deploy a supporting package, since older releases do not read these settings.
356
+
357
+
With caching **disabled**, each live request retrieves a complete Key Vault bundle or uses fresh
358
+
managed-identity/client-assertion SDK credentials for OAuth. There is no startup preparation,
359
+
periodic polling, cross-request credential sharing, or failure cooldown. Request-scoped state is
360
+
discarded after acquisition; Python closes its SDK clients when synchronous acquisition finishes.
361
+
The same expiry checks and acquisition budgets below still apply. Azure's managed-identity service
362
+
and platform Key Vault-reference caching remain outside these switches.
363
+
364
+
With caching **enabled**, each runtime retains its existing policy:
Copy file name to clipboardExpand all lines: docs/ONBOARDING.md
+3-3Lines changed: 3 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -97,7 +97,7 @@ can restore setup-managed values.
97
97
|`KEY_VAULT_URL`| Summary's `resources.keyVault`; vault Overview > Vault URI. | Put Telesign credentials in this vault. Setup grants its Function system identity Key Vault Secrets User. |
98
98
|`EPP_DECRYPTION_KEY_PEM`, `EPP_ENCRYPTION_KEY_ID`| Versioned Key Vault reference and registered encryption credential ID. Summary includes certificate/secret identifiers and expiry, **not** private-key bytes. | Do not view/copy the private key. Assign a [renewal owner](../setup/docs/README.md#encryption-certificate-lifecycle). |
99
99
|`EPP_PROVIDER_TIMEOUT_MS`, `EPP_PROVIDER_RETRY_INTERVAL_MS`| Profile timing values. Runtime provider HTTP timeout is capped at 2500 ms. | Neither is a whole-request deadline; retry interval metadata does **not** enable send retries. |
100
-
|`EPP_KEY_VAULT_CACHE_ENABLED`, `EPP_ACCESS_TOKEN_CACHE_ENABLED`| Setup writes `false` for FC1, `true` for EP1. |Current checked-in runtimes do not read these switches. Verify the selected release before assuming cache control; see[plan guidance](../setup/docs/README.md#service-plan-selection). |
100
+
|`EPP_KEY_VAULT_CACHE_ENABLED`, `EPP_ACCESS_TOKEN_CACHE_ENABLED`| Setup writes `false` for FC1, `true` for EP1. |Independently control API-key/OAuth caching and startup preparation. Unset defaults to `true`; deploy a supporting package and restart after changes. See[plan guidance](../setup/docs/README.md#service-plan-selection). |
101
101
| Application Insights, storage, runtime/package settings and identities | Created/configured for the selected plan; system identity handles vault/storage/telemetry, outbound identity handles Soprano exchange. | Verify telemetry ingestion. Do not copy local emulator settings or EP1-only settings into FC1. |
102
102
| Inbound caller issuer, audience and allowlist | Function App > Authentication; setup configures Easy Auth for the Microsoft phone-provider caller. | Read back platform authentication, not just `EPP_EXPECTED_*` metadata. App settings are not an alternative caller-authentication gate. |
103
103
@@ -212,8 +212,8 @@ this did not demonstrate the expected authentication gate. Transport/redirect er
212
212
passes. This only checks the missing-token case, not all authorization or readiness properties.
213
213
214
214
Evaluation skips provider selection/credential lookup and provider HTTP **on its request path**.
215
-
Configured workers can independently acquire credentials at startup; JavaScript/Python also
216
-
poll for refresh. Do not confuse those background events with an evaluation sending a message.
215
+
With the selected cache enabled, configured workers can independently acquire credentials at startup;
216
+
JavaScript/Python also poll for refresh. Do not confuse those events with an evaluation sending a message.
217
217
218
218
For live requests, `200` with matching nonce means **provider acceptance, not delivery**.
219
219
Soprano voice extracts the first six-digit sequence; Telesign voice paces standalone six-digit
0 commit comments