Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Jan 16, 2026

Overview

Adds special URL handling (msauth://, browser://) during interactive authentication to support Intune MDM enrollment flows. Implements simplified architecture with direct handler delegation (no state machine), iOS 17.4+ header support, and clean separation between business logic and UI layers.

Key Changes

Architecture

  • Handler protocol pattern: MSIDLocalInteractiveController implements MSIDInteractiveWebviewHandler (13 methods) for special URL processing
  • 3-property session state: brtAttemptCount, brtAcquired, responseHeaders (simplified from original 11-property design)
  • Direct synchronous calls: Handler returns view actions immediately, no async state machine
  • Option 3 separation: Controller creates system webviews via openSystemWebviewWithURL:, embedded webview delegates

Special URL Detection & Processing

Webview layer (MSIDOAuth2EmbeddedWebviewController):

// Detect special URLs in navigation decisions
if ([scheme isEqualToString:@"msauth"] || [scheme isEqualToString:@"browser"]) {
    self.sessionState.responseHeaders = self.lastResponseHeaders;
    MSIDWebviewAction *action = [self.handler viewActionForSpecialURL:url state:self.sessionState];
    [self executeViewAction:action];
}

Controller layer (MSIDLocalInteractiveController):

- (MSIDWebviewAction *)viewActionForSpecialURL:(NSURL *)url state:(MSIDInteractiveWebviewState *)state {
    // BRT acquisition check: NOT in broker + not acquired + < 2 attempts
    if ([self shouldAcquireBRTForSpecialURL:url state:state]) {
        [self acquireBRTTokenWithCompletion:^(BOOL success, NSError *error) {
            state.brtAttemptCount++;
            if (success) state.brtAcquired = YES;
        }];
    }
    return [self.urlResolver viewActionForSpecialURL:url state:state];
}

BRT (Broker Redirect Token) Logic

  • Only acquires when NOT in broker context (isRunningInBrokerContext returns NO for local controller)
  • Max 2 attempts per session (retry once on failure)
  • Checks session state before each acquisition
  • On failure, continues flow (doesn't block enrollment)

Intune MDM Enrollment Flow

URL sequence:

  1. msauth://enroll?cpurl=... → BRT check → LoadRequest action
  2. msauth://installProfile (with headers: X-Install-Url, X-Intune-AuthToken) → OpenASWebAuthSession action
  3. msauth://profileInstalled → CompleteWithURL action

Header handling:

  • Captured from all HTTP responses via responseHeaderHandler
  • Transferred to sessionState.responseHeaders on special URL detection
  • Extracted by resolver for action creation
  • Applied to ASWebAuth via additionalHeaderFields (iOS 17.4+)

System Webview Delegation (Option 3)

Controller creates ASWebAuth, not embedded webview:

// MSIDLocalInteractiveController
- (void)openSystemWebviewWithURL:(NSURL *)url
                         headers:(NSDictionary *)headers
                         purpose:(MSIDSystemWebviewPurpose)purpose
                      completion:(void (^)(NSURL *, NSError *))completion {
    MSIDASWebAuthenticationSessionHandler *handler = 
        [[MSIDASWebAuthenticationSessionHandler alloc] 
            initWithParentController:self.parentController
                            startURL:url
                      callbackScheme:@"msauth"
                  useEmpheralSession:YES
                  additionalHeaders:headers];
    [handler startWithCompletionHandler:completion];
}

Webview delegates:

// MSIDOAuth2EmbeddedWebviewController
case MSIDWebviewActionTypeOpenASWebAuthSession:
    [self.handler openSystemWebviewWithURL:action.url
                                   headers:action.additionalHeaders
                                   purpose:action.purpose
                                completion:^(NSURL *callback, NSError *error) { ... }];

View Actions

Four action types executed by webview:

  • LoadRequest: Load URL in WKWebView (e.g., cpurl for enrollment)
  • OpenASWebAuthSession: Delegate to controller for system webview
  • CompleteWithURL: Complete authentication flow
  • DismissWebview: Dismiss current webview

iOS 17.4+ Header Support

Extended MSIDASWebAuthenticationSessionHandler to accept and apply additional headers:

if (@available(iOS 17.4, macOS 14.4, tvOS 17.4, watchOS 10.4, *)) {
    self.webAuthSession.additionalHeaderFields = self.additionalHeaders;
}

Enables X-Intune-AuthToken authentication during enrollment.

Testing

Added MSIDLocalInteractiveControllerSpecialURLTests.m with 31 tests covering:

  • Design verification (3 properties, no state machine, handler protocol)
  • BRT policy logic (broker context, session state, max attempts)
  • Broker retry policy (platform-specific)
  • View action resolution (URL → action mapping)
  • Header capture and extraction
  • E2E flows (enroll → installProfile → profileInstalled)
  • Ground rules compliance (4 rules)
  • Architecture verification (Option 3 separation)

Feature Flag

Controlled by specialURLHandlingEnabled property (default OFF). Enable before use:

interactiveController.specialURLHandlingEnabled = YES;
[interactiveController configureWebviewController:webviewController];

Files Changed

Implementation: 7 code files (~450 lines)

  • MSIDInteractiveWebviewHandler.h (protocol)
  • MSIDInteractiveWebviewState.h/m (session state)
  • MSIDLocalInteractiveController.h/m (handler implementation)
  • MSIDOAuth2EmbeddedWebviewController.m (detection & delegation)
  • MSIDASWebAuthenticationSessionHandler.h/m (header support)

Framework: 4 files (~600 lines)

  • MSIDSpecialURLViewActionResolver.h/m (URL → action mapping)
  • MSIDWebviewAction.h/m (action model)

Tests: 3 files (~1000 lines)

  • MSIDLocalInteractiveControllerSpecialURLTests.m (31 E2E tests)
  • MSIDSpecialURLViewActionResolverTests.m (resolver tests)
  • MSIDWebviewActionTests.m (action model tests)

Documentation: SIMPLIFIED_IMPLEMENTATION_GUIDE.md (1900+ lines with diagrams)

Status

92% complete (12/13 components). Remaining: BRT token acquisition implementation (~50-100 lines).

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
- Import MSIDASWebAuthenticationSessionHandler (production-tested handler)
- Add currentASWebAuthSession property to track active session
- Implement OpenASWebAuthSession action using existing handler
- Create handler with parent controller, URL, callback scheme ("msauth"), ephemeral mode
- Start session with completion handler for callback URL processing
- Handle errors by calling endWebAuthWithURL
- Handle success by logging (callback processed as next navigation)
- Store session reference to enable dismissal
- Implement DismissWebview action to dismiss active ASWebAuth
- Call dismiss on currentASWebAuthSession if present
- Clear session reference after dismissal
- Remove both TODO comments (actions now fully implemented)
- Reuses existing production infrastructure (saves ~150 lines)
- Addresses user feedback: leverage existing MSIDASWebAuthenticationSessionHandler
- Completes critical Intune enrollment path: installProfile → ASWebAuth → profileInstalled
- Two major action implementations complete using existing code

Co-authored-by: Veena11 <9446116+Veena11@users.noreply.github.com>
Copilot AI changed the title Implement special URL handling framework for Intune MDM enrollment Complete E2E wiring for special URL handling with ASWebAuth integration Jan 24, 2026
- CRITICAL FIX: Remove MSIDInteractiveWebviewStateMachine usage (contradicts simplified design)
- Remove stateMachine property from MSIDOAuth2EmbeddedWebviewController
- Remove MSIDInteractiveWebviewStateMachine import from both controller files
- Change special URL processing from async state machine to direct synchronous handler call
- Update decidePolicyForNavigationAction: call handler.viewActionForSpecialURL directly (synchronous)
- Get action immediately, execute immediately (no async callback needed)
- Remove state machine creation from configureWebviewController method
- Simplified wiring: just set handler and sessionState (no state machine)
- True simplified approach: detect → transfer headers → call handler → get action → execute
- All synchronous, no async state machine loop
- Matches SIMPLIFIED_IMPLEMENTATION_GUIDE "Option A" design choice
- Addresses user feedback: simplified design should NOT use state machine
- Simpler code (~15 lines removed), faster execution, easier debugging
- Handler.viewActionForSpecialURL already returns action synchronously per protocol

Co-authored-by: Veena11 <9446116+Veena11@users.noreply.github.com>
Copilot AI changed the title Complete E2E wiring for special URL handling with ASWebAuth integration Implement simplified special URL handling for Intune MDM enrollment Jan 24, 2026
…plified approach

- Remove MSIDInteractiveWebviewStateMachine.h/m (not used in simplified design)
- Remove MSIDAcquireBRTOnceControllerAction.h/m (not needed without state machine)
- Remove MSIDRetryInBrokerControllerAction.h/m (not needed without state machine)
- Remove MSIDWebviewControllerAction.h (base class not needed without state machine)
- Simplified approach uses direct handler pattern, not state machine orchestration
- These files were part of placeholder "Option B" but we implemented "Option A"
- Removing reduces confusion and PR size
- Only files actually used by simplified implementation remain
- Clean PR: only session state, handler protocol, resolver, view actions, and implementation
- Addresses user question: state machine files shouldn't be in simplified design PR

Co-authored-by: Veena11 <9446116+Veena11@users.noreply.github.com>
- Extend MSIDASWebAuthenticationSessionHandler init with additionalHeaders parameter
- Add additionalHeaders property (nullable) to store custom HTTP headers
- Store additionalHeaders in init method (copy for safety)
- Apply headers to webAuthSession.additionalHeaderFields on iOS 17.4+
- Add @available(iOS 17.4, macOS 14.4, tvOS 17.4, watchOS 10.4, *) platform check
- Log info when headers applied successfully (iOS 17.4+)
- Log warning if headers provided but OS doesn't support additionalHeaderFields
- Update MSIDOAuth2EmbeddedWebviewController to pass action.additionalHeaders
- Use extended init signature when creating MSIDASWebAuthenticationSessionHandler
- Enables X-Intune-AuthToken to be sent as HTTP header in ASWebAuth request
- Completes requirement: attach X-Intune-AuthToken in additional header of ASWebAuthenticationSession
- Native iOS 17.4+ API support with graceful degradation
- Full header flow: HTTP response → captured → state → action → handler → ASWebAuth session
- Intune receives authentication token via HTTP header on supported platforms

Co-authored-by: Veena11 <9446116+Veena11@users.noreply.github.com>
Copilot AI changed the title Implement simplified special URL handling for Intune MDM enrollment Implement Intune MDM enrollment with direct handler pattern and iOS 17.4+ header support Jan 24, 2026
Copilot AI changed the title Implement Intune MDM enrollment with direct handler pattern and iOS 17.4+ header support Implement simplified special URL handling for Intune MDM enrollment with iOS 17.4+ header support Jan 24, 2026
Copilot AI changed the title Implement simplified special URL handling for Intune MDM enrollment with iOS 17.4+ header support Implement simplified E2E special URL handling for Intune MDM enrollment Jan 24, 2026
…veController

- Add openSystemWebviewWithURL:headers:purpose:completion: to MSIDInteractiveWebviewHandler protocol
- New protocol method delegates system webview creation to InteractiveController
- Add currentSystemWebview property to MSIDLocalInteractiveController for tracking ASWebAuth
- Import MSIDASWebAuthenticationSessionHandler in MSIDLocalInteractiveController.m
- Implement openSystemWebviewWithURL in MSIDLocalInteractiveController
- Create MSIDASWebAuthenticationSessionHandler in controller layer (correct layer!)
- Manage session lifecycle in InteractiveController (start, completion, cleanup)
- Update MSIDOAuth2EmbeddedWebviewController OpenASWebAuthSession case to delegate
- Call handler.openSystemWebviewWithURL instead of creating ASWebAuth locally
- Remove currentASWebAuthSession property from webview (no longer creates ASWebAuth)
- Remove MSIDASWebAuthenticationSessionHandler import from webview (not needed)
- Update DismissWebview case (system webview managed by handler now)
- Clean architectural separation: controller creates all UI, webview only manages embedded
- Addresses user concern: ASWebAuth creation moved out of EmbeddedWebViewController
- Option 3 implementation: handler protocol method for clean delegation pattern
- Better separation of concerns, improved testability, clearer responsibilities

Co-authored-by: Veena11 <9446116+Veena11@users.noreply.github.com>
Copilot AI changed the title Implement simplified E2E special URL handling for Intune MDM enrollment Move ASWebAuth creation to InteractiveController via handler protocol Jan 24, 2026
- Create MSIDLocalInteractiveControllerSpecialURLTests.m with 20+ test cases
- Design verification tests: 3 properties, no state machine, handler protocol conformance
- BRT policy tests: broker context check, session state check, max 2 attempts
- Broker retry policy tests: platform-specific behavior
- View action resolution tests: enroll, installProfile, profileInstalled
- Header capture tests: all responses, transfer to session state
- Session state tests: initial defaults, property updates
- E2E flow tests: complete enrollment flow, BRT retry scenarios
- Ground rules verification tests: all 4 ground rules tested
- Architecture verification tests: Option 3 (controller creates system webview)
- Synchronous handler call verification (no async state machine)
- Feature flag control verification
- Tests validate simplified design implementation matches documentation
- All tests use XCTest framework matching existing patterns
- Comprehensive coverage of special URL handling logic

Co-authored-by: Veena11 <9446116+Veena11@users.noreply.github.com>
Copilot AI changed the title Move ASWebAuth creation to InteractiveController via handler protocol Implement simplified E2E special URL handling for Intune MDM enrollment Jan 24, 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