Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion TECHNICAL.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ and managed-identity access to credentials.

## Single-region architecture

![Single-region External Phone Provider architecture](docs/images/single-region-architecture.png)
![Single-region component overview showing Microsoft Entra ID, Easy Auth, the Function and adapter, Key Vault, Application Insights, and the phone provider](docs/images/single-region-architecture.png)

*Component overview, not a delivery timeline. The numbered delivery arrow does not mean
the Function waits for handset receipt; see the [request sequence](docs/BRING-YOUR-OWN-PROVIDER.md#end-to-end-endpoint-request)
for live SMS response ordering and the end user's verification steps.*

Microsoft Entra ID sends an authenticated, encrypted request. Easy Auth checks the caller,
then the Function decrypts the request using its Key Vault-backed key. For a live request, the
Expand All @@ -25,6 +29,8 @@ with capacity and quota for your hosting plan. The provider-secret path applies
integrations; OAuth integrations use managed-identity token exchange instead. Credential caching
depends on the [selected cache settings](docs/CONTRACT.md#credential-caching-and-refresh), and
[log formats vary by runtime](docs/MONITORING.md#runtime-specific-log-discovery).
Telemetry comes from the Function host/worker; the schematic telemetry arrow does not mean
Easy Auth rejections produce Function request logs.

An authorized, valid encrypted **evaluation request (`mode: 2`)** returns the matching nonce
without submitting a message to the provider. When caching is enabled, credential preparation
Expand Down
54 changes: 53 additions & 1 deletion docs/BRING-YOUR-OWN-PROVIDER.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,37 @@ Before deploying, ask your tenant administrator to confirm
[eligibility, testing, and activation with Microsoft](ONBOARDING.md#before-purchasing-or-deploying).
Deploying the endpoint alone does not enable tenant policy.

## End-to-end endpoint request

This is a browser-based **SMS sign-in example after approved endpoint activation**. Your
application is the user's existing sign-in app, **not** the dedicated endpoint app registration
created during setup. Do not add a redirect URI to that endpoint registration to copy this flow.

![End-user SMS sign-in sequence: a person opens an app, follows the redirect to Microsoft Entra ID, receives a provider-delivered SMS after an authorized SendOtp call, enters the code on the sign-in page, and accesses the app only after identity and application checks succeed. Provider acceptance and phone delivery are separate observations.](images/request-sequence.png)

*Original UML sequence; [open the scalable diagram](images/request-sequence.svg).
Solid arrows are requests/delivery; dashed arrows are replies. The `par` frame separates
provider acceptance from recipient delivery; it does not promise their order or successful delivery.
This is a successful example, not a completed live test. Use the
[endpoint error reference](CONTRACT.md#epp-response-json) for rejected or failed endpoint requests.*

The person reads the SMS on their phone and enters its code in the **Microsoft Entra ID sign-in
page**, as described in Microsoft's [text-message verification instructions](https://learn.microsoft.com/en-us/entra/identity/authentication/concept-authentication-phone-options#text-message-verification).
Microsoft Entra ID checks the code and remaining sign-in requirements; the application validates
the sign-in result and applies its access rules. The
[browser redirect/token exchange](https://learn.microsoft.com/en-us/entra/identity-platform/v2-protocols-oidc#protocol-flow-sign-in)
belongs to that application, not this Function.

The Function only delivers the supplied message. For live requests, its `200` response means provider acceptance,
**not phone receipt, a correct user-entered code, or application access**. Evaluation (`mode: 2`)
tests the endpoint without sending a message; it is not an end-user sign-in.
Voice and other sign-in flows can have different prompts; confirm their experience through the
[approved validation procedure](ONBOARDING.md#validate-the-deployed-endpoint), rather than assuming
they use this SMS screen or a generic voice-MFA gesture.

The steps below explain the endpoint's part of the sequence. The
[architecture view](../TECHNICAL.md#single-region-architecture) shows its separate key and credential paths.

<a id="1-establish-caller-authentication"></a>

## 1. Verify the caller
Expand Down Expand Up @@ -188,14 +219,35 @@ or send-retry loop. Keep service secrets in Key Vault, not in settings or source
3. Add tests in the directory above for registration, request mapping, missing credentials,
recognized acceptance, rejection, unknown responses, and timeouts on each supported channel.
Check that evaluation sends nothing, live success waits for acceptance, and failures omit the
nonce. Use fake credentials and service responses; run your runtime's tests and build.
nonce. Use fake credentials and service responses; [run the offline tests](#run-the-offline-tests)
before building your package.
4. [Package your changed source](../TECHNICAL.md#build-zips-locally), not an unchanged public
release. C# needs publish output; Python needs the documented Linux remote build.
Follow [manual deployment](ONBOARDING.md#optional-local-development-and-manual-deployment)
to deploy the custom package and apply cloud settings and vault permissions separately.
Retain the [Easy Auth trust checks](ONBOARDING.md#manual-deployment-trust-checklist), then
complete the validation below.

### Run the offline tests

Use a **full repository checkout**, not a downloaded Function release ZIP: the ZIPs omit tests,
and the suites use the shared `tests/fixtures/contract.json`. Run the unchanged suite first,
then rerun it after adding your integration. You do not need a tenant, app registration,
`local.settings.json`, Azurite, Core Tools, or provider account for these tests.

Choose only your runtime's instructions:
[JavaScript](../javascript/README.md#run-offline-tests),
[C#](../dotnet/README.md#run-offline-tests), or
[Python](../python/README.md#run-offline-tests). Each gives the working folder, tools, and commands.
Use a terminal without production or deployed provider settings in its environment.
Dependency preparation needs the package registry; the tests use local test keys and
fake credentials/transport rather than Azure sign-in or live sends.

Use the test runner's final summary and exit code: no collected tests, a missing module, or a
failed restore is not a passing run. These commands follow the repository's
[CI workflow](../.github/workflows/ci.yml). A pass checks the application, not deployed Easy Auth,
provider authorization, or delivery; continue with the separate acceptance checks below.

<a id="step-7-check-endpoints-timeouts-and-privacy"></a>
<a id="6-validate-before-activation"></a>

Expand Down
9 changes: 8 additions & 1 deletion docs/FRONTDOOR.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@ approved by the deployment owners; the observed results below do not establish t

## Architecture: one URL, multiple origins

![Multi-region External Phone Provider architecture with Azure Front Door](images/multi-region-architecture.png)
![Multi-region component overview showing Microsoft Entra ID, Azure Front Door, two regional Function Apps with Key Vault and Application Insights, and a shared phone provider](images/multi-region-architecture.png)

*Component overview, not a deployment template or delivery timeline. Match private-key material,
not vault version IDs or resource names. The green dashed arrows are responses, not health probes.*

The diagram shows the design, not the exact test deployment. Its region names are examples.
Custom domains and Premium/WAF are optional and weren't part of the Standard-tier test.
Expand All @@ -54,6 +57,10 @@ consistent and use the same RSA key**, rather than copying every setting literal
The SMS/voice arrows show live delivery. Evaluation returns the nonce without contacting the provider.
The diagram's provider-secret arrows apply to API-key integrations; OAuth uses each region's
outbound managed identity. Match the key material across regions, not the vault URLs or version IDs.
For response timing and separate recipient delivery, see the
[request sequence](BRING-YOUR-OWN-PROVIDER.md#end-to-end-endpoint-request).
Health probes require the [separate readiness handler](#3-provide-a-non-delivering-readiness-endpoint),
which is not shown in this overview or included in the release packages.

| Component | Purpose |
|---|---|
Expand Down
31 changes: 26 additions & 5 deletions docs/ONBOARDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,29 @@ Review the deployment plan, then retain `deployment-*.json` and the public certi
The [setup output guide](../setup/docs/README.md#read-the-deployment-summary) explains the remaining
fields. `policyChanged: false` is expected, not a failed deployment.

Inspect cloud settings in **Azure portal > Function App > Settings > Environment variables**.
They are setup-managed; do not recreate them from the local sample or bulk-copy another app's
settings. Do not export all settings into a ticket. Changes can restart the worker, and reruns
can restore setup-managed values.
To find your endpoint's cloud settings:

1. In **Azure portal > Function Apps**, open the name in `resources.functionApp` in your saved
deployment summary. Check its subscription and resource group against `subscriptionId` and
`resources.resourceGroup`; do not select an app just because its display name looks similar.
2. Open **Settings > Environment variables > App settings**. Use the **Search** box to find
`EPP_PROVIDER_NAME`, `EPP_PROVIDER_SMS_ENDPOINT`, or `EPP_PROVIDER_VOICE_ENDPOINT`, then use
the table below to compare the approved routing configuration privately.
3. Find `EPP_DECRYPTION_KEY_PEM` by **Name**, but keep its value hidden. It is the private-key
reference, not a provider API key. Do not select **Show values** to export settings or include
them in a screenshot. Use the [key-reference checks](../setup/docs/Troubleshooting.md#certificate-selection-reuse-or-cleanup-fails)
if resolution fails.

[![Official Azure portal example with Settings, Environment variables, and the App settings tab highlighted; all setting values remain hidden.](images/onboarding/function-app-settings.png)](images/onboarding/function-app-settings.png)

*Navigation example from [Microsoft's Function settings instructions](https://learn.microsoft.com/en-us/azure/azure-functions/functions-how-to-use-azure-function-app-settings#get-started-in-the-azure-portal).
`function-app-1` is a demo name; use `resources.functionApp`. The generic host settings shown
are not an EPP checklist, and FC1/EP1 settings differ.
[Unmodified source](https://github.com/MicrosoftDocs/azure-docs/blob/1067858212cfae5f69de14fe53a3432eb461b052/articles/azure-functions/media/functions-how-to-use-azure-function-app-settings/azure-function-app-main.png),
Copyright (c) Microsoft Corporation, [CC BY 4.0](https://github.com/MicrosoftDocs/azure-docs/blob/1067858212cfae5f69de14fe53a3432eb461b052/LICENSE).*

These settings are setup-managed; do not recreate them from the local sample or bulk-copy another
app's settings. Changes can restart the worker, and reruns can restore setup-managed values.

| Value or setting | Source / verification | Customer action |
|---|---|---|
Expand All @@ -124,7 +143,9 @@ a missing, empty, or invalid selected endpoint fails closed.

There are **three separate trust paths**: Easy Auth admits the Microsoft caller; the Key Vault
certificate decrypts its JWE; provider credentials authorize outbound delivery. The HTTPS
certificate is separate again. Fix the failing path rather than replacing unrelated IDs or keys.
certificate is separate again. Use the [request sequence](BRING-YOUR-OWN-PROVIDER.md#end-to-end-endpoint-request)
to distinguish provider acceptance, phone receipt, and the user's code verification. Fix the failing path rather than
replacing unrelated IDs or keys.

## Complete provider authentication

Expand Down
Binary file added docs/images/onboarding/certificate-version.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/onboarding/function-app-settings.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/request-sequence.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
88 changes: 88 additions & 0 deletions docs/images/request-sequence.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading