Skip to content
Open
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
30 changes: 14 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# External Phone Provider Azure Function Sample

This **External Phone Provider (EPP)** sample connects Microsoft Entra ID to a phone provider
for SMS and voice one-time passwords.
Guided setup deploys **one regional endpoint** using JavaScript by default, with C# and Python options.
for SMS and voice one-time passwords. Guided setup deploys **one regional endpoint** in JavaScript,
C#, or Python. JavaScript is the default.

> [!IMPORTANT]
> Start in a separate nonproduction environment. Confirm provider access and Microsoft's approved
> test and activation process before deployment.
> Start in a separate nonproduction environment. Before deployment, confirm provider access and
> Microsoft's approved test and activation process.

## Table of contents

Expand All @@ -23,12 +23,12 @@ Guided setup deploys **one regional endpoint** using JavaScript by default, with
- JavaScript, C#, and Python implementations of one [HTTP and trust contract](docs/CONTRACT.md).
- Guided Azure deployment with Easy Auth, Key Vault, and monitoring.
- Evaluation mode checks authentication and decryption without sending a message.
- Built-in provider integrations and an [Add Twilio](docs/BRING-YOUR-OWN-PROVIDER.md) guide.
- Built-in provider integrations and a [BYOT provider guide](docs/BRING-YOUR-OWN-PROVIDER.md).

## Requirements

- Use a separate test environment with a Microsoft Entra ID tenant, Azure subscription, and
unique resource name prefix. Supply a dedicated app registration or create one during guided setup.
- Use a separate test environment with a Microsoft Entra ID tenant, Azure subscription, unique
resource prefix, and dedicated app registration. Guided setup can create the registration.
- Check [roles, permissions, tools, regional availability, and quota](setup/docs/README.md#prerequisites-for-step-2).
- For Telesign, complete the [OAuth profile placeholders](docs/ONBOARDING.md#telesign-oauth-configuration-and-handoff)
before deployment.
Expand All @@ -39,17 +39,15 @@ Guided setup deploys **one regional endpoint** using JavaScript by default, with

![Microsoft Entra ID sends an encrypted request through Easy Auth to a Function, which uses Key Vault and calls the phone provider](docs/images/single-region-architecture.png)

*Easy Auth checks the Microsoft caller before the Function decrypts the request.
Live success confirms provider acceptance. Confirm delivery separately. Evaluation validates the
request without sending a message.
The diagram is a topology overview; current packages read API-key secrets for each live request,
while Azure Identity owns OAuth token caching.
See [architecture details](TECHNICAL.md#single-region-architecture).
[Open the full-size diagram](docs/images/single-region-architecture.png).*
*Easy Auth checks the Microsoft caller before the Function decrypts the request. Evaluation checks
the request without sending. Live success confirms provider acceptance, not delivery. Current
packages read API-key secrets for each live request; Azure Identity caches OAuth tokens. See
[architecture details](TECHNICAL.md#single-region-architecture) or
[open the full-size diagram](docs/images/single-region-architecture.png).*

## Get started

Follow the **[five-step setup guide](docs/GETTING-STARTED.md)** in order:
Follow the **[five-step setup guide](docs/GETTING-STARTED.md)**:

1. <a id="1-get-ready"></a>[Get ready](docs/GETTING-STARTED.md#1-get-ready): confirm access, approvals, permissions, and budget.
2. <a id="2-register-your-application"></a>[Choose the app](docs/GETTING-STARTED.md#2-register-your-application): use an existing registration or create one during setup.
Expand All @@ -72,7 +70,7 @@ Before live use, review [production readiness](TECHNICAL.md#production-readiness
| Resolve a problem | [Troubleshooting](setup/docs/Troubleshooting.md) |
| Monitor the endpoint | [Monitoring](docs/MONITORING.md) |
| Review the API | [Send OTP](docs/CONTRACT.md) |
| Add Twilio | [Twilio integration guide](docs/BRING-YOUR-OWN-PROVIDER.md) |
| Add a provider | [BYOT provider guide](docs/BRING-YOUR-OWN-PROVIDER.md) |
| Work on a runtime | [JavaScript](javascript/README.md), [C#](dotnet/README.md), or [Python](python/README.md) |

<a id="optional-designs"></a>
Expand Down
38 changes: 19 additions & 19 deletions TECHNICAL.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

[Documentation](docs/README.md) | [First deployment](docs/GETTING-STARTED.md) | [HTTP contract](docs/CONTRACT.md)

This reference covers implementation details, app settings, packages, and built-in providers.
This reference covers implementation details, settings, packages, and built-in providers.

| Task | Section |
| --- | --- |
Expand All @@ -22,9 +22,9 @@ This reference covers implementation details, app settings, packages, and built-

See the [single-region diagram in the sample overview](README.md#architecture).

Microsoft Entra ID sends an authenticated, encrypted request. Easy Auth checks the caller, the
Function decrypts the request, and the selected adapter submits a live message. Success means
provider acceptance, not confirmed delivery.
Microsoft Entra ID sends an authenticated, encrypted request. Easy Auth checks the caller. The
Function decrypts the request, and the selected adapter sends the message. Success means provider
acceptance, not delivery.

East US is illustrative. API-key integrations use provider secrets. OAuth integrations use
managed-identity token exchange. See [provider settings and credential acquisition](#provider-settings-and-credential-acquisition)
Expand All @@ -47,15 +47,16 @@ It covers capacity, shared keys, dependencies, readiness, regional recovery dril
| Python (v2 model) | Available | [python/](python/) |

Choose **one language and one provider per Function App**. All implementations share the
[HTTP, configuration, and trust contract](docs/CONTRACT.md). Runtime behavior can differ.
[HTTP and trust contract](docs/CONTRACT.md), but runtime behavior can differ.

For local work, use the selected runtime guide. To add Twilio, use
[Add Twilio](docs/BRING-YOUR-OWN-PROVIDER.md).
For local work, use the selected runtime guide. To add a provider, use the
[BYOT provider guide](docs/BRING-YOUR-OWN-PROVIDER.md).

## Guided EPP setup

Follow the [five-step guide](docs/GETTING-STARTED.md). `Setup-Epp.ps1` retrieves its support files
from one commit and deploys after plan approval. See the [setup reference](setup/docs/README.md#step-2---download-and-run-one-script).
Follow the [five-step guide](docs/GETTING-STARTED.md). `Setup-Epp.ps1` gets its support files from
one commit and deploys only after you approve the plan. See the
[setup reference](setup/docs/README.md#step-2---download-and-run-one-script).

Review [application permissions](setup/docs/README.md#step-1---manually-create-the-application)
and [certificate selection](setup/docs/README.md#encryption-certificate-selection). Setup pins one
Expand All @@ -65,7 +66,7 @@ One deployment accepts SMS and voice. Each request's `channel` selects its confi

## Download a Function ZIP

Guided setup selects and publishes the language ZIP automatically. Use this section for manual deployment.
Guided setup selects and publishes the language ZIP. For a custom deployment:

Open the [package releases](https://github.com/Azure-Samples/ExternalPhoneProvider-AzureFunction-Sample/releases)
and choose the newest stable tag ending in your language ID. Each language release contains
Expand Down Expand Up @@ -102,8 +103,8 @@ pwsh -File ./package-dotnet.ps1
pwsh -File ./package-python.ps1
```

Choose one command. Each ZIP has `host.json` at its root and excludes local settings, credentials,
and tests.
Choose one command. Each ZIP contains root-level `host.json` and excludes local settings,
credentials, and tests.

JavaScript installs production dependencies from the lockfile in a temporary folder. Review
packaging for native dependencies or required lifecycle scripts. It does not modify `node_modules`.
Expand Down Expand Up @@ -140,8 +141,7 @@ not in application environment settings or incoming request data.

## HTTP implementation details

Use [Send OTP](docs/CONTRACT.md) for the public request and response. This section covers runtime
implementation details.
See [Send OTP](docs/CONTRACT.md) for the public request and response. Runtime details follow.

### JWE validation and key handling

Expand Down Expand Up @@ -212,8 +212,8 @@ The shared outcomes are `Continue`, `Block`, and `Fail`.
| Missing or invalid endpoint, authentication-mode mismatch, credential or network failure, or unknown response | `502` |
| Provider timeout | `504` |

Unknown or incomplete provider responses fail closed. Check a timed-out live request before
retrying because the provider might already have accepted it.
Unknown or incomplete provider responses fail closed. Before retrying a timeout, check whether the
provider accepted the request.

HTTP `401` and `403` are reserved for inbound SAS-to-Function authentication, authorization, or
platform access failures. HTTP `422` carries `error: "provider_blocked"` without a nonce.
Expand All @@ -228,7 +228,7 @@ Provider adapters use these safe failure labels: `provider_http_error`, `provide
## Configure environment variables

For guided deployment, inspect the [values and ownership table](docs/ONBOARDING.md#values-and-ownership).
The following settings are for local or manual deployment.
For local or custom deployment:

Start from [sample settings](docs/local.settings.sample.json). Every `Values` entry is a string.

Expand Down Expand Up @@ -353,12 +353,12 @@ Recognized success groups remain `ACCEPTED`, `PENDING`, and `DELIVERED` on succe
unknown statuses fail closed.

Set `EPP_PROVIDER_ACCOUNT_NAME` to an Infobip-approved sender/caller ID and confirm it works for
both intended channels. The adapter's existing `Verify` fallback is not proof of sender approval.
both channels. The adapter's default `Verify` value is not proof of sender approval.

For an older API-key deployment, deploy a package containing this OAuth update and rerun setup
with `-Provider infobip` to configure federation and the provider tenant/scope. Review
`EPP_PROVIDER_AUTH_MODE=oauth` and the regional base URLs. Updating settings alone does not upgrade
an older adapter; this version has no API-key fallback. Complete
an older adapter; this version supports OAuth only. Complete
[provider authorization](docs/ONBOARDING.md#complete-provider-authentication) before live use.

### Soprano
Expand Down
20 changes: 10 additions & 10 deletions docs/APPLICATION-INSIGHTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

[Documentation](README.md) | [Monitoring](MONITORING.md) | [Log fields](LOGGING.md)

Start here when telemetry is missing or incomplete. For everyday queries and alerts, use
[monitoring](MONITORING.md).
For missing or incomplete telemetry, start here. For routine queries and alerts, see
[Monitor the endpoint](MONITORING.md).

| Task | Go to |
| --- | --- |
Expand All @@ -17,7 +17,7 @@ Start here when telemetry is missing or incomplete. For everyday queries and ale
| Review privacy and sampling | [Limits](#limits) |

Function telemetry covers execution, timing, and logs. Microsoft Entra ID sign-ins and provider
delivery evidence are separate.
delivery use separate data.

<a id="how-telemetry-reaches-application-insights"></a>
## Collection
Expand All @@ -38,7 +38,7 @@ requests, dependencies, exceptions, and traces when the active pipeline exports
| [Python](../python/host.json) | Standard host Application Insights settings. Requests are excluded from sampling. | There is no Azure Monitor or OpenTelemetry exporter in requirements. Confirm structured properties and dependencies. |

These are source defaults, not guarantees. Runtime versions, packages, settings, filters, and
sampling can change the collected data.
sampling affect collected data.

Application events are logs, not guaranteed `customEvents`. Verify the
[runtime format](MONITORING.md#runtime-log-formats) before saving queries.
Expand Down Expand Up @@ -74,7 +74,7 @@ and [Functions monitoring reference](https://learn.microsoft.com/azure/azure-fun
Guided setup connects one Function App to one Application Insights resource backed by a Log
Analytics workspace.

Check the following:
Check these items:

1. **Destination:** On the Function App, confirm `APPLICATIONINSIGHTS_CONNECTION_STRING` points
to the intended resource. Do not copy it into issues or screenshots.
Expand Down Expand Up @@ -108,9 +108,9 @@ If you intentionally use a user-assigned ingestion identity, set
`ClientId=<identity-client-id>;Authorization=AAD`, attach that identity to the app, and grant it
access to the destination. Do not use the provider application ID.

Missing data can result from a wrong destination, missing role assignment, identity mismatch,
role propagation, an inactive exporter, filters, sampling, DNS, or network access. Query access is
separate from ingestion access.
Missing data can result from the wrong destination, missing roles, identity mismatch, role
propagation, an inactive exporter, filters, sampling, DNS, or network access. Query and ingestion
access are separate.

See [Functions collection configuration](https://learn.microsoft.com/azure/azure-functions/configure-monitoring)
and [Microsoft Entra-authenticated ingestion](https://learn.microsoft.com/azure/azure-monitor/app/azure-ad-authentication).
Expand Down Expand Up @@ -171,8 +171,8 @@ AppTraces
| order by Latest desc
```

An absent table, query error, or empty result is not a healthy zero. Check scope, time range,
traffic, access, filters, sampling, and ingestion. `ItemCount` is a sampling weight when supplied.
An absent table, query error, or empty result does not mean zero failures. Check scope, time range,
traffic, access, filters, sampling, and ingestion. When present, `ItemCount` is a sampling weight.
It does not recover discarded records.

<a id="sampling-privacy-and-collection-limits"></a>
Expand Down
Loading
Loading