Skip to content

Implement Intune MDM enrollment flow with ASWebAuth continuation#1662

Draft
Copilot wants to merge 54 commits intodevfrom
copilot/add-placeholder-framework
Draft

Implement Intune MDM enrollment flow with ASWebAuth continuation#1662
Copilot wants to merge 54 commits intodevfrom
copilot/add-placeholder-framework

Conversation

Copy link
Contributor

Copilot AI commented Jan 16, 2026

Implements special URL handling for Intune device enrollment during interactive authentication. When Conditional Access requires MDM enrollment, the flow switches from embedded webview to ASWebAuthenticationSession for enrollment, then continues the token request without cancellation.

Core Changes

Flow Continuation via Response Pattern

  • Created MSIDEnrollmentCompletionResponse class following MSIDWPJResponse pattern
  • Factory creates enrollment response when ASWebAuth completes with msauth://profileComplete
  • Response flows through preserved completion handler to controller
  • Token request remains active throughout ASWebAuth session (~10-60 seconds)
  • Controller handles response and retries in broker context on iOS

Action-Based Architecture

  • All webview operations use action pattern: LoadRequest, OpenASWebAuth, CompleteWithURL, DismissWebview
  • MSIDWebviewAction enhanced with dismissalCompletion for post-dismiss sequencing
  • Webview executes actions; helper returns actions (clean separation)

Helper Pattern for Code Reuse

  • MSIDInteractiveWebviewHelper implements shared logic (ASWebAuth creation, header capture)
  • Both broker and non-broker controllers use same helper with isRunningInBrokerContext parameter
  • Eliminates duplication between controller implementations

Async Orchestration

  • processSpecialURL:completion: orchestrates BRT acquisition (async), action resolution, and broker retry (async)
  • BRT acquired once per session on first msauth:// redirect (non-broker only)
  • Broker retry triggered for profileInstalled on iOS (non-broker only)

Wiring

  • Request base class has weak webviewHandler property (no retain cycles)
  • Webview gets factory reference for response creation from callbacks

Example Flow

// 1. Embedded webview detects installProfile
[helper processSpecialURL:installProfileURL completion:^(MSIDWebviewAction *action) {
    // Returns: OpenASWebAuth action with X-Intune-AuthToken header
    [self executeViewAction:action];
}];

// 2. ASWebAuth runs until profileComplete, creates response
MSIDEnrollmentCompletionResponse *response = [factory oAuthResponseWithURL:profileCompleteURL ...];

// 3. Response flows to controller
- (void)handleWebMSAuthResponse:(MSIDWebviewResponse *)response {
    if ([response isKindOfClass:[MSIDEnrollmentCompletionResponse class]]) {
        // Retry in broker on iOS
        [self retryInBrokerContext:response.profileCompletedURL ...];
    }
}

Token request completion handler preserved throughout - flow never cancels.

Original prompt

Add placeholder framework for special URL handling in embedded WKWebView using a controller-action state machine and MSIDWebviewAction view actions.

Repository: AzureAD/microsoft-authentication-library-common-for-objc
Base branch: dev

Background / Motivation

We need a scaffolding (placeholders) for a new architecture to handle msauth:// and browser:// redirects in embedded WKWebView. This design separates:

  • Controller actions (state-machine-driven async operations such as AcquireBRTOnce, RetryInBroker)
  • View actions (MSIDWebviewAction) that the embedded webview controller executes

No production behavior changes are required in this PR; it should compile and be safe to land without enabling the new flow.

Deliverables

1) Add MSIDWebviewAction placeholder (new)

Create a minimal view-action model:

  • MSIDWebviewActionType enum (at least: Noop, LoadRequestInWebview, OpenASWebAuthenticationSession, OpenExternalBrowser, CompleteWithURL, FailWithError)
  • MSIDSystemWebviewPurpose enum including at least MSIDSystemWebviewPurposeInstallProfile and MSIDSystemWebviewPurposeUnknown
  • MSIDWebviewAction class with readonly properties: type, request, url, purpose, error
  • Convenience constructors:
    • +noopAction
    • +loadRequestAction:(NSURLRequest *)request
    • +openASWebAuthSessionAction:(NSURL *)url purpose:(MSIDSystemWebviewPurpose)purpose
    • +openExternalBrowserAction:(NSURL *)url
    • +completeWithURLAction:(NSURL *)url
    • +failWithErrorAction:(NSError *)error
  • Documentation comment: ephemeral ASWebAuthenticationSession behavior is implied by purpose (InstallProfile => ephemeral) and will be enforced by system webview handoff handler.

2) Add controller-action state machine placeholders (new)

Add these new types (placeholders with documentation and minimal logic):

  • MSIDInteractiveWebviewState
    • session flags for BRT gate: brtGateEncountered, brtAttempted, brtAcquired
    • per-intercept: pendingURL, queryParams, isGateScheme, isRunningInBrokerContext
    • policy: brtFailurePolicy enum (Continue/Fail)
    • transition: transferredToBroker
  • MSIDInteractiveWebviewHandler protocol
    • -isRunningInBrokerContext
    • policy hooks:
      • -shouldAcquireBRTForSpecialURL:state:
      • -brtFailurePolicyForSpecialURL:state:
      • -shouldRetryInBrokerForSpecialURL:state:
    • action implementations:
      • -acquireBRTTokenWithCompletion:
      • -genericBrtError
      • -retryInteractiveRequestInBrokerContextForURL:completion:
      • -dismissEmbeddedWebviewIfPresent
    • view resolver hook:
      • -viewActionForSpecialURL:state:
    • telemetry:
      • -handleWebviewResponseForTelemetry:
  • MSIDInteractiveWebviewStateMachine
    • -initWithHandler:
    • -handleSpecialURL:navigationAction:completion: returning MSIDWebviewAction *
    • Implements broker-style nextControllerActionForState: selection and runUntilStable loop.
    • Must be safe and minimal: default behavior should return CompleteWithURL or Noop via handler/resolver; no wiring into production code.

3) Add controller action placeholders (new)

  • Base class or protocol for controller actions (minimal)
  • MSIDAcquireBRTOnceControllerAction
    • calls handler acquireBRTTokenWithCompletion: once; sets state flags
  • MSIDRetryInBrokerControllerAction
    • calls handler retryInteractiveRequestInBrokerContextForURL:completion:
    • on success sets state.transferredToBroker = YES and calls dismissEmbeddedWebviewIfPresent

4) Add MSIDSpecialURLViewActionResolver placeholder (new)

Add a helper that maps special URLs to MSIDWebviewAction (placeholder semantics):

  • msauth://enroll?cpurl=... -> LoadRequestInWebview (construct request from cpurl; placeholder for headers/params)
  • msauth://compliance?cpurl=... -> LoadRequestInWebview
  • msauth://installProfile?url=...&requireASWebAuthenticationSession=true -> OpenASWebAuthenticationSession with purpose InstallProfile
  • msauth://profileComplete -> CompleteWithURL (retry handled by controller action policy)
  • browser://... -> CompleteWithURL
    Include TODO comments for:
  • adding extra headers/query params for enroll/compliance
  • telemetry header parsing
  • enforcing ephemeral by purpose in system webview handoff handler

5) Safety / Non-breaking

  • Do NOT change existing behavior paths; do not wire the embedded WKWebView controller to use the new state machine by default.
  • Keep the new framework self-contained and compile-able.

6) Tests (if feasible)

If the repo has an existing unit test target, add minimal tests validating:

  • MSIDWebviewAction constructors
  • resolver mapping for installProfile URL produces OpenASWebAuthenticationSession + InstallProfile purpose

Notes

  • Keep Objective-C style consistent with repo.
  • Add header docs for intended end-to-end invocation.
  • Ensure everything builds on iOS targets.

This pull request was created from Copilot chat.


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

…tion and state machine

Co-authored-by: Veena11 <9446116+Veena11@users.noreply.github.com>
Copilot AI and others added 3 commits January 16, 2026 02:24
Co-authored-by: Veena11 <9446116+Veena11@users.noreply.github.com>
Co-authored-by: Veena11 <9446116+Veena11@users.noreply.github.com>
Co-authored-by: Veena11 <9446116+Veena11@users.noreply.github.com>
Copilot AI changed the title [WIP] Add placeholder framework for special URL handling Add placeholder framework for special URL handling in embedded WKWebView Jan 16, 2026
Copilot AI requested a review from Veena11 January 16, 2026 02:28
Copilot AI changed the title Add placeholder framework for special URL handling in embedded WKWebView No changes needed - original PR implements special URL handling pattern Jan 16, 2026
Copilot AI changed the title No changes needed - original PR implements special URL handling pattern Pass original URL to resolver helper methods and add headers support for ASWebAuthenticationSession Jan 16, 2026
Copilot AI changed the title Pass original URL to resolver helper methods and add headers support for ASWebAuthenticationSession Add placeholder framework for special URL handling in embedded WKWebView with controller-action state machine Jan 16, 2026
Copilot AI changed the title Add placeholder framework for special URL handling in embedded WKWebView with controller-action state machine Add placeholder framework for special URL handling in embedded WKWebView with state machine architecture Jan 16, 2026
Copilot AI changed the title Add special URL handling for Intune MDM enrollment with async BRT acquisition Implement Intune MDM enrollment special URL handling with helper pattern Feb 2, 2026
…nsistency + remove duplicate property

- Add MSIDWebviewActionTypeDismissWebview to action enum (complete action set)
- Add dismissalCompletion property to MSIDWebviewAction (for post-dismiss operations like retry)
- Add dismissWebviewActionWithCompletion: factory method (creates dismiss action)
- Implement DismissWebview case in executeViewAction (dismisses with completion callback)
- Update processSpecialURL to return DismissWebview action (not call method directly)
- Retry in broker happens in action's dismissalCompletion block (proper sequencing)
- Remove dismissEmbeddedWebviewIfPresent method from helper (no longer needed!)
- Remove dismissEmbeddedWebviewIfPresent method from controller (no longer needed!)
- Remove embeddedWebviewController property from helper (webview dismisses itself!)
- Remove currentSystemWebview property from controller (duplicate - helper has it!)
- Remove currentSystemWebview mirroring assignment (single source of truth in helper)
- Webview now dismisses itself via action (not called from helper)
- Architectural consistency: ALL 4 webview operations via actions (Load, Open, Complete, Dismiss)
- Better separation: Helper returns action, webview executes, no direct dismissal calls
- Eliminates property duplication between controller and helper
- Code reduction: -71 lines deleted, +59 lines added = -12 lines net
- Addresses user requirements: "dismiss via action" and "remove duplicate currentSystemWebview"

Co-authored-by: Veena11 <9446116+Veena11@users.noreply.github.com>
Copilot AI changed the title Implement Intune MDM enrollment special URL handling with helper pattern Add special URL handling for Intune MDM enrollment with BRT acquisition and broker retry Feb 2, 2026
Copilot stopped work on behalf of Veena11 due to an error February 2, 2026 20:28
Copilot stopped work on behalf of Veena11 due to an error February 2, 2026 20:48
Copilot stopped work on behalf of Veena11 due to an error February 2, 2026 21:11
Copilot stopped work on behalf of Veena11 due to an error February 2, 2026 21:41
@Veena11
Copy link
Contributor

Veena11 commented Feb 2, 2026

@copilot So our requirement is
When navigating to msauth://profileInstall in embedded webview -> switch to ASWebAutenticationSession
Continue in ASWebAuthenticationSession until we get a navigation to msauth://profileComplete
Once we receive the 302 response with msauth://profileComplete, dismiss ASWebAutenticationSession, resume the flow in embedded webview. The token request should never get cancelled. The flow should be a continuation and not cancelled. Is this requirement taken care of in the implementation ?

Copilot stopped work on behalf of Veena11 due to an error February 2, 2026 22:25
Copilot stopped work on behalf of Veena11 due to an error February 2, 2026 22:38
Copilot stopped work on behalf of Veena11 due to an error February 3, 2026 00:18
Copilot AI changed the title Add special URL handling for Intune MDM enrollment with BRT acquisition and broker retry Implement special URL handling for Intune MDM enrollment in interactive auth flows Feb 3, 2026
Copilot AI changed the title Implement special URL handling for Intune MDM enrollment in interactive auth flows Add Intune MDM enrollment special URL handling with ASWebAuth support Feb 3, 2026
…oken request never cancelled

- Create MSIDEnrollmentCompletionResponse class (similar to MSIDWPJResponse pattern)
- Response indicates enrollment completion from ASWebAuth (profileInstalled/profileComplete)
- Carries profileCompletedURL and shouldRetryInBroker flag (platform-dependent)
- Update MSIDAADWebviewFactory.oAuthResponseWithURL to create enrollment response
- Detect profileInstalled/profileComplete URLs and create MSIDEnrollmentCompletionResponse
- Set shouldRetryInBroker: YES on iOS, NO on macOS (platform-specific retry logic)
- Add responseFactory property to MSIDOAuth2EmbeddedWebviewController
- Factory set during webview creation in MSIDAADWebviewFactory
- Update ASWebAuth callback handling to create response via factory
- Process callback URL (msauth://profileComplete) through factory.oAuthResponseWithURL
- Call webview completion handler with response (flow continues, never cancelled!)
- Response flows through MSIDInteractiveTokenRequest to MSIDLocalInteractiveController
- Update handleWebMSAuthResponse to check for MSIDEnrollmentCompletionResponse type
- If enrollment response with shouldRetryInBroker: call retryInBrokerContext
- If enrollment response without retry: complete in current context
- Token request never cancelled - completion handler flows through ASWebAuth to controller
- Flow continuation: embedded webview → ASWebAuth → response → controller → retry/complete
- Addresses critical requirement: "Token request should NEVER get cancelled. Flow should be continuation"
- Complete Intune enrollment flow now properly continues after ASWebAuth completes

Co-authored-by: Veena11 <9446116+Veena11@users.noreply.github.com>
Copilot AI changed the title Add Intune MDM enrollment special URL handling with ASWebAuth support Add Intune MDM enrollment special URL handling with flow continuation Feb 3, 2026
Copilot AI and others added 2 commits February 3, 2026 02:03
Co-authored-by: Veena11 <9446116+Veena11@users.noreply.github.com>
Moved MSIDEnrollmentCompletionResponse PBXFileReference entries from
PBXBuildFile section to proper PBXFileReference section to maintain
correct Xcode project structure.
Copilot AI changed the title Add Intune MDM enrollment special URL handling with flow continuation Implement Intune MDM enrollment flow with ASWebAuth continuation Feb 3, 2026
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.

2 participants