Authentication
How the Dispatcher's App Registration supports both delegated and client-credentials authentication, and the Microsoft Entra ID gotchas specific to the self-referencing delegated pattern.
The Dispatcher accepts two distinct OAuth 2.0 flows against the same "REFRACT Dispatcher API" App Registration. Both are validated identically once a token arrives - the difference is entirely in how the caller obtains that token.
Client Credentials (service-to-service)
Used by the Power Platform connector, ERP integrations, and any unattended script. A separate App Registration acts as the client, requests a token for api://<dispatcher-app-client-id>/.default, and authenticates with a client secret. No user is ever involved.
Full setup steps live in Power Platform Connector Setup - the same pattern applies to any other client-credentials caller, using a differently-named App Registration for the client.
Delegated (Authorization Code + PKCE)
Used for interactive testing (Postman) and by the SPFx dashboard. Unlike client credentials, this pattern reuses "REFRACT Dispatcher API" as both the client and the resource - there is no separate client app. A human signs in, so no client secret is required; the app authenticates via PKCE instead.
Because client and resource are the same app here, Microsoft Entra ID applies a few rules that don't come up in the client-credentials path. Each one below was hit and resolved while setting up Postman testing against a live Dispatcher.
Required App Registration configuration
Redirect URI under "Mobile and desktop applications"
The redirect URI used for this flow (https://oauth.pstmn.io/v1/callback for Postman; your own scheme for a native app) must be registered under the "Mobile and desktop applications" platform, not "Web". A PKCE-only public client (no secret) registered under "Web" fails token exchange with AADSTS90009 or a generic invalid_request - "Web" platform redirect URIs expect a confidential client.
Scope must be the bare GUID, not the App ID URI
<dispatcher-app-client-id>/.defaultnot
api://<dispatcher-app-client-id>/.defaultWhen client and resource are the same app, Microsoft Entra ID only supports this "requesting a token for itself" scenario when the resource is identified by its bare GUID application ID. Using the api:// App ID URI form here fails with:
AADSTS90009: Application '<appId>' is requesting a token for itself. This scenario
is supported only if resource is specified using the GUID based App Identifier.The app must request its own delegated permission
Exposing the user_impersonation scope on the API side is not enough. The app must also list that same scope as a required permission it requests for itself, under API permissions, with admin consent granted. Without this, token issuance fails with:
AADSTS650057: Invalid resource. The client has requested access to a resource which
is not listed in the requested permissions in the client's application registration.infra/deploy.ps1 automates this: it adds the self-referencing requiredResourceAccess entry and grants admin consent (with retry, since a just-created or just-updated app registration can take up to a minute to propagate to the consent endpoint). If you're working against an app registration created before this automation existed, add it manually:
Azure Portal -> App registrations -> "REFRACT Dispatcher API" -> API permissions -> Add a permission -> APIs my organization uses -> search for "REFRACT Dispatcher API" itself -> Delegated permissions -> user_impersonation -> Add permissions -> Grant admin consent.
Why SPFx never surfaced this
SharePoint's tenant-wide app-catalog deployment consents the SPFx solution's own webApiPermissionRequests entry independently at solution-deploy time. Any other delegated consumer of this same app (Postman, or a future non-SPFx client) needs the self-referencing permission requested and consented explicitly, which is what the deploy.ps1 automation above now handles.
Client-side gotcha: the OAuth relay and the browser mode
Separately from the App Registration configuration above, one client-side (Postman) setting matters: "Authorize using browser" must be checked when using a hosted relay redirect URI such as https://oauth.pstmn.io/v1/callback. That relay is built for the system-browser flow. With the checkbox unchecked, Postman's embedded webview loads the relay page directly and fails with an opaque Error: [object Object] instead of a readable Microsoft Entra ID error - the sign-in itself succeeds, but the redirect handoff back into Postman does not.
JWT Validation
Regardless of which flow produced the token, the Dispatcher validates the same three claims on every request:
| Claim | Validates | Configured via |
|---|---|---|
aud | Token was issued for this Dispatcher's App Registration | JWT_AUDIENCE app setting |
iss | Token was issued by this tenant's own Microsoft Entra ID | JWT_ISSUER app setting |
tid | Token belongs to the authorised tenant | AZURE_TENANT_ID app setting |
JWT_REQUIRED must be true in production
If JWT_REQUIRED is not set to "true", a transient failure reaching the Microsoft Entra ID JWKS endpoint could allow unauthenticated requests to proceed. Always set JWT_REQUIRED=true in production.
Next Steps
- Testing with Postman - Full step-by-step Postman OAuth 2.0 configuration using the delegated pattern above
- Power Platform Connector Setup - Client-credentials setup with a separate connector App Registration
- REFRACT Dispatcher API Overview - Endpoint list and the two auth models compared
REFRACT Dispatcher API
Overview of the customer-hosted REFRACT Dispatcher's HTTP API, its Microsoft Entra ID App Registration, and the two authentication models available to callers.
Testing with Postman
Step-by-step Postman OAuth 2.0 configuration for manually testing the Dispatcher API using the delegated Authorization Code + PKCE flow.