Documentation | Settings | Request behavior | Source
Implements the shared contract with one provider per deployment. Target: Python 3.11, Azure Functions v4, Python v2 programming model.
Sample deployment: follow the five-step guide, then complete provider authentication and validation.
Custom package development: follow these steps from python/:
- Create the local settings below. Select a fixed provider ID from providers/, configure it, and complete provider authentication.
- Use a virtual environment, install requirements.txt and pytest, and run tests/. Start Core Tools here, on loopback only, without tunnels. It has no Easy Auth.
- For manual deployment, publish to a compatible Linux Python Function with dependencies or remote build. Inspect the package for private settings, complete the Easy Auth trust checklist, and run authorized deployed checks to verify platform authentication.
Regional continuity: use the Front Door guide and include Python-specific package, startup, dependency, and telemetry checks.
Run Core Tools from python/. Create an untracked local.settings.json beside
host.json, starting from the shared sample.
For local evaluation, start Azurite and replace the test-key placeholder in this minimal setup:
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "python",
"EPP_DECRYPTION_KEY_PEM": "<base64 of your local test private PEM>"
}
}For live delivery, use the shared settings table
for EPP_PROVIDER_NAME, both channel endpoints, authentication, and adapter-specific options.
Keep values as strings, including EPP_PROVIDER_TIMEOUT_MS: "1500". Replace the placeholders.
Store API keys in provider-named Key Vault secrets. Each selected channel requires a valid
endpoint. An invalid or missing endpoint returns an error without using the other channel.
Core Tools loads Values into os.environ. Direct Python and pytest do not. Restart after edits.
Use a local test PEM because Core Tools cannot resolve Key Vault references locally. Keep Azurite
settings local.
In Azure, configure the same app settings and use a Key Vault reference for the private PEM. Provider secrets use managed identity, not a developer CLI login. Keep local evaluation on loopback.
POST /api/SendOtp follows the shared request/response contract.
Easy Auth authenticates the caller. The handler then validates and decrypts the payload. It never
forwards or returns the incoming Authorization header.
Use mode: 2 or "evaluation" to validate
authentication and decryption without a provider send. Live success confirms acceptance,
not handset receipt. Check a timeout before retrying.
For built-in message and voice mapping, see Soprano and Telesign.
To add Twilio, follow the Twilio integration guide. Keep caller authentication and public responses in the shared handler.
For diagnostics, use Application Insights and runtime-specific log discovery. Verify which Python logging properties the host/export pipeline preserves.
The cache switches and defaults apply here. Disabling the selected cache removes startup preparation, polling, and cross-request reuse, not live credential acquisition.
With caching enabled, API keys use Key Vault and cachetools.TTLCache. OAuth uses managed identity
and the Azure Identity SDK. A daemon polls every 30 seconds. See the
credential caching guide.
| Source | Purpose |
|---|---|
| function_app.py | Typed request orchestration and direct provider selection |
| src/config.py | Shared deployment settings |
| src/models.py | Typed Microsoft Entra ID payload, delivery context, provider request and result dataclasses |
| src/jwe.py | Pinned JWE decryption and typed delivery-context conversion |
| src/provider.py | Shared HTTPS transport, timeout handling and endpoint status mapping |
| src/credentials.py | CredentialTokenService, ApiKeyCache and AccessTokenCache |
| src/otp_log.py | Fixed standard-logging event definitions and immutable request context |
| src/providers/ | Provider-owned credentials, requests and response mapping |
| src/secrets.py | Key Vault transport. Bundle caching belongs to ApiKeyCache. |
Add a provider by subclassing PhoneProviderBase, declaring its credential specification, and
implementing build_request and map_response. Return ProviderResult with the coarse endpoint
outcome and a fixed safe failure classification. Raw provider JSON remains local to the provider.
See production readiness when planning a live service.