Skip to content

[Windows] WebAuthenticator: add protocol callback support via app activation - #36415

Merged
kubaflo merged 1 commit into
dotnet:windows-app-activation-lifecyclefrom
IlGalvo:windows-webauthenticator-protocol-callback
Jul 14, 2026
Merged

[Windows] WebAuthenticator: add protocol callback support via app activation#36415
kubaflo merged 1 commit into
dotnet:windows-app-activation-lifecyclefrom
IlGalvo:windows-webauthenticator-protocol-callback

Conversation

@IlGalvo

@IlGalvo IlGalvo commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Note

Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!

Root Cause

WebAuthenticator is unsupported on Windows. A custom-protocol callback may launch a second app process, so Windows needs both protocol activation handling and cross-instance routing back to the process that owns the pending authentication.

Windows App SDK also cannot reliably re-register an AppInstance after UnregisterKey() (microsoft/WindowsAppSDK#4420). Releasing the route after the first authentication caused a subsequent callback process to find no route owner.

After a redirected callback completes, the existing MAUI window is not automatically restored or brought in front of the browser. The request must retain its originating window and perform a best-effort foreground activation only after a valid callback completes it.

Description of Change

Adds a Windows implementation that preserves the existing cross-platform contract: caller-provided authentication URL and callback URL in, WebAuthenticatorResult out.

  • opens the system browser with Launcher.LaunchUriAsync
  • handles protocol callbacks through OnAppInstanceActivated from [Windows] Lifecycle: Add AppInstance activated event #34883
  • registers a WebAuthenticator-specific AppInstance route for the callback scheme
  • redirects transient callback processes to the instance that owns that route
  • keeps the route registered for the lifetime of the process while keeping pending authentication state request-scoped
  • validates packaged manifest and unpackaged protocol registration
  • forwards callbacks through the existing IPlatformWebAuthenticatorCallback
  • captures the AppWindow that started each authentication so multi-window callbacks return to the correct window
  • restores minimized or hidden windows without intermediate activation, then makes one best-effort foreground request

This intentionally does not use OAuth2Manager. The caller still owns state, PKCE, provider parameters, and token exchange.

Key Technical Details

  • route keys use Microsoft.Maui.WebAuthenticator:{scheme}
  • application-owned AppInstance keys are preserved
  • transient processes use AppInstance.GetInstances() to find the route owner without registering another key
  • final callback matching still uses WebUtils.CanHandleCallback(...)
  • only one WebAuthenticator request can be pending per app instance, matching the existing platform model
  • redirect completion is awaited before the transient callback process exits
  • the route remains registered for the process lifetime to avoid the UnregisterKey() re-registration issue
  • the persistent route is routing infrastructure; the TCS and expected callback URI determine whether a callback is currently handled
  • only the callback that wins TrySetResult may restore and foreground its captured window
  • cancellation, invalid callbacks, duplicate callbacks, and late callbacks do not request foreground activation
  • minimized windows use OverlappedPresenter.Restore(false) and hidden windows use AppWindow.Show(false) so SetForegroundWindow is the only explicit activation request
  • foreground work is isolated behind best-effort exception handling and never changes the OAuth result

RedirectActivationToAsync already requests foreground permission for the route-owner process through AllowSetForegroundWindow in Windows App SDK AppInstance::QueueRequest. MAUI therefore does not duplicate that call.

The foreground path intentionally does not use AppWindow.DispatcherQueue. AppWindow and OverlappedPresenter are agile, and a dispatcher queue is not guaranteed to be available in the redirected activation context.

Packaged apps declare the callback scheme in AppxManifest.xml; unpackaged apps register it with ActivationRegistrationManager.RegisterForProtocolActivation(...).

Foreground Behavior

Windows ultimately decides whether SetForegroundWindow succeeds. Foreground activation is therefore best effort by design: failure is diagnostic only and never changes a successful authentication result.

Testing

The routing revision passed Unit, Public API, Windows build, sample build, and all 14 WebAuthenticator Windows device tests.

The foreground revision was validated with:

  • Microsoft.Maui.Essentials Windows build: 0 warnings, 0 errors
  • manual OAuth callback verification confirming that the existing MAUI window returns in front of the browser
  • runtime verification that accessing AppWindow.DispatcherQueue from the redirected activation context can fail with COMException; the final implementation does not depend on it

Additional human-interaction validation remains useful for minimized, maximized, multi-window, cancellation followed by retry, invalid callback, and consecutive-authentication scenarios.

Breaking Changes

None.

Issues Fixed

Looking forward to your feedback, thanks!

@mattleibow
@dotMorten

@IlGalvo
IlGalvo had a problem deploying to copilot-pat-pool July 6, 2026 21:03 — with GitHub Actions Failure
@IlGalvo

IlGalvo commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

@dotnet-policy-service agree

@IlGalvo
IlGalvo marked this pull request as draft July 6, 2026 21:44
@IlGalvo
IlGalvo force-pushed the windows-webauthenticator-protocol-callback branch from 9df876b to 1b105a5 Compare July 7, 2026 12:56
@IlGalvo
IlGalvo marked this pull request as ready for review July 7, 2026 13:08
@kubaflo

This comment has been minimized.

@github-actions github-actions Bot added the s/agent-review-in-progress AI review is currently running for this PR label Jul 10, 2026
@MauiBot MauiBot removed the s/agent-review-in-progress AI review is currently running for this PR label Jul 10, 2026
@IlGalvo
IlGalvo force-pushed the windows-webauthenticator-protocol-callback branch from 1b105a5 to 30fcb50 Compare July 12, 2026 20:51
@IlGalvo

IlGalvo commented Jul 12, 2026

Copy link
Copy Markdown
Contributor Author

The branch has been force-pushed with the latest revision (30fcb50a8a).

The WebAuthenticator AppInstance route now remains registered for the process lifetime, avoiding the consecutive-authentication failure related to microsoft/WindowsAppSDK#4420. Transient callback processes locate the original route owner through AppInstance.GetInstances().

Unit, Public API, Windows build, sample build, and all 14 WebAuthenticator Windows device tests passed. Human-interaction tests still require manual validation.

This PR routes callbacks to the original app instance but does not explicitly bring its window to the foreground; that should be addressed separately.

@kubaflo

@kubaflo

This comment has been minimized.

@github-actions github-actions Bot added the s/agent-review-in-progress AI review is currently running for this PR label Jul 12, 2026
@MauiBot MauiBot removed the s/agent-review-in-progress AI review is currently running for this PR label Jul 12, 2026
@IlGalvo
IlGalvo force-pushed the windows-webauthenticator-protocol-callback branch from 30fcb50 to 513b29d Compare July 14, 2026 13:15
@IlGalvo

IlGalvo commented Jul 14, 2026

Copy link
Copy Markdown
Contributor Author

Supersedes the previous update for 30fcb50a8a.

With this revision, the PR is now complete and ready for review. The Windows WebAuthenticator flow now covers protocol routing, consecutive authentications, minimized and multi-window scenarios, and best-effort foreground activation without affecting the OAuth result.

The branch has been force-pushed with the latest revision (513b29d876). In addition to the persistent request-scoped AppInstance routing, the Windows implementation now captures the AppWindow that starts each authentication and performs a best-effort foreground activation only after a valid callback wins TrySetResult.

Minimized or hidden windows are restored without intermediate activation before the single SetForegroundWindow request. Cancellation, invalid, duplicate, and late callbacks do not request foreground activation, and any foreground failure remains diagnostic only and cannot change the OAuth result.

RedirectActivationToAsync already requests foreground permission for the route-owner process through AllowSetForegroundWindow in Windows App SDK, so MAUI does not duplicate that call. The implementation also avoids AppWindow.DispatcherQueue: the relevant windowing APIs are agile, and the dispatcher getter was not reliable in the redirected activation context.

The updated Essentials Windows target builds with 0 warnings and 0 errors. Manual OAuth verification confirmed that the existing MAUI window returns in front of the browser; the remaining minimized, maximized, multi-window, cancellation/retry, invalid-callback, and consecutive-authentication cases are documented as human-interaction validation scenarios in the PR description.

@kubaflo

@kubaflo

This comment has been minimized.

@github-actions github-actions Bot added the s/agent-review-in-progress AI review is currently running for this PR label Jul 14, 2026
@MauiBot MauiBot removed the s/agent-review-in-progress AI review is currently running for this PR label Jul 14, 2026
@kubaflo
kubaflo merged commit c1554db into dotnet:windows-app-activation-lifecycle Jul 14, 2026
3 of 4 checks passed
@IlGalvo
IlGalvo deleted the windows-webauthenticator-protocol-callback branch July 14, 2026 22:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants