Peek Field App — OAuth2 Settings¶
The Peek field app reads the Application Proxy host and OAuth2 parameters from a built-in defaults asset. For enterprise MDM deployments the same keys can be overridden per device at runtime.
Defaults Asset¶
File: peek_field_app/src/assets/peek_core_device/server-info-tuple-defaults.json
Shape (matches ServerInfoTuple in
peek_core_device/plugin-module/_private/tuples/server-info-tuple.ts):
{
"host": "peekfieldapp-synerty.msappproxy.net",
"useSsl": true,
"httpPort": 443,
"websocketPort": 443,
"hasConnected": true,
"oauth2AppId": "<application-client-id>",
"oauth2TenantId": "<tenant-id>",
"oauth2WebRedirectUrl": "https://peekfieldapp-synerty.msappproxy.net/.auth/login/aad/callback",
"oauth2BundleId": "com.synerty.peek"
}
The oauth2WebRedirectUrl field controls which OAuth2 scope format the
field app requests:
Omit / leave blank → scope is
api://<appId>/user_impersonation(matches anapi://identifier URI on the Entra app registration).Set to the proxy callback URL → scope is
https://<host>/user_impersonation(matches anhttps://identifier URI, which is the recommended format for Application Proxy deployments).
The recommended setup uses the Application Proxy external URL as the
identifier URI (https://peekfieldapp-synerty.msappproxy.net). In that
case set oauth2WebRedirectUrl to the proxy’s OIDC callback path:
"oauth2WebRedirectUrl": "https://peekfieldapp-synerty.msappproxy.net/.auth/login/aad/callback"
If you registered api://<appId> as the identifier URI instead, omit
oauth2WebRedirectUrl from the JSON.
Field reference:
Key |
Meaning |
|---|---|
|
External Application Proxy hostname |
|
Must be |
|
|
|
|
|
Set |
|
|
|
Entra directory (tenant) ID |
|
Omit for Capacitor builds. When present
and non-empty, shifts the OAuth2 scope from
|
|
iOS bundle ID — used to build
|
The asset is loaded once, on first launch, by
ServerInfoTuple.loadDefaultValues(). Once hasConnected flips to
true the values persist in the device’s offline tuple storage; changes
to this JSON will not be picked up until the app is reinstalled (or
offline storage is cleared).
MDM Overrides (iOS)¶
For MDM-managed fleets, push the same values as AppConfig keys. The keys
are defined in MdmAppConfigKeyEnum
(peek_core_device/plugin-module/_private/hardware-info/hardware-info.ts):
AppConfig key |
Maps to |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
MDM values are read via @capacitor-community/mdm-appconfig and take
precedence over the JSON defaults on FIELD_IOS builds only.
iOS Bundle ID and URL Scheme¶
The iOS bundle identifier in ios/App/App.xcodeproj/project.pbxproj
(PRODUCT_BUNDLE_IDENTIFIER) must match oauth2BundleId. The
Capacitor OAuth2 plugin builds the redirect URI as
msauth.<bundle-id>://auth at runtime and that exact value must be
registered as the iOS redirect URI on the Entra app registration
(see Azure Proxy — App Setup).
If you change the bundle ID:
Update
PRODUCT_BUNDLE_IDENTIFIERin Xcode.Update
oauth2BundleIdin the JSON above.Update the iOS platform redirect URI on the Entra app.
Re-register the MSAL redirect handler in
Info.plist(CFBundleURLSchemes) if it is hardcoded.
Angular Build Configuration¶
The Peek field app uses a dedicated Angular build configuration,
capacitor, which sets serviceWorkerEnabled: false via
environment.capacitor.ts. The Angular service worker must be
disabled at build time for Capacitor (iOS/Android) builds — leaving it
enabled causes the service worker to detect build-hash changes and
trigger continuous WebView reloads via clients.navigate(), which
bypasses any JavaScript-level interception.
The capacitor configuration is the default for npm run build.
For web/PWA builds use ng build --configuration=production.
Browser / PWA Build¶
When the PWA is served behind Application Proxy, authentication is
handled by the proxy’s own pre-auth flow (the user signs in once at the
proxy, the proxy sets a session cookie, and the backend receives the
X-MS-CLIENT-PRINCIPAL header). The PWA does not run its own MSAL
flow, so oauth2WebRedirectUrl is not needed on the native side.
The proxy’s pre-auth does, however, use the PeekFieldApp app registration
and sends the external URL as its redirect_uri. That external URL
must be registered under the Web platform of the app registration
(see Azure Proxy — App Setup). Registering it under Single-page
application instead forces PKCE on the proxy’s server-side token
exchange and the proxy login fails with AADSTS9002325.
Xcode Cloud Build¶
For Xcode Cloud deployments the defaults asset is not edited by hand.
Fill in app_spec.json at the repo root (including the oauth2
section) and run patch_and_tag_for_xcode_build.py — the script
writes server-info-tuple-defaults.json automatically before tagging
the build.
See app_spec.json Reference for the full field reference, the
serverConnection / oauth2 mapping table, and a worked example.
Troubleshooting¶
App shows “Connect To Server” instead of redirecting to Entra.
The defaults JSON is blank or host is null. Confirm the asset is
present in the built App.app bundle at
public/assets/peek_core_device/server-info-tuple-defaults.json.
Proxy login returns ``AADSTS9002325`` (PKCE required).
The Application Proxy external URL has been registered under the
Single-page application platform on the Entra app registration. Move
it to Web — Application Proxy pre-auth uses a server-side
(confidential-client) token exchange without PKCE, and SPA registration
forces PKCE. The iOS flow uses msauth.<bundle-id>://auth under
iOS / macOS only.
Proxy login returns ``AADSTS50011`` (redirect URI mismatch). The Application Proxy external URL is not registered on the app registration at all. Add it under the Web platform — see Azure Proxy — App Setup.
OAuth2 browser opens but returns a different redirect-URI error.
The iOS platform redirect URI is missing or mismatched. Confirm Entra
has msauth.<bundle-id>://auth under iOS / macOS with
<bundle-id> equal to oauth2BundleId.
OAuth2 succeeds but the WebSocket drops after ~85 seconds.
Application Proxy applicationServerTimeout is still Default. Set
it to Long on the Application Proxy app settings.
App reloads continuously (~450 ms cycle) immediately after launch.
The Angular service worker was enabled in the Capacitor build. Ensure
the build was produced with npm run build (which uses the
capacitor configuration) rather than a web/production configuration.
The service worker detects build-hash changes on every reinstall and
triggers clients.navigate() from the worker context, which cannot
be suppressed from JavaScript. See “Angular Build Configuration” above.
App crashes or reloads once ~400 ms after launch, then stabilises.
VortexService.setVortexUrl(null) was not called for the native
platform. The VortexService static default URL is "/vortex"; on
Capacitor it must be explicitly set to null so the service does not
attempt an HTTP connection to the Capacitor asset server at startup.
This is handled automatically by main.ts as of the current version.