Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -242,4 +242,9 @@ - (void)acquireTokenWithRequest:(MSIDInteractiveTokenRequest *)request
}];

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This pull request does not update changelog.txt.

Please consider if this change would be noticeable to a partner or user and either update changelog.txt or resolve this conversation.

}

- (void)shouldSkipAcquireTokenBasedOn:(NSError *)error
{
// This method is not used in this class.
}

@end
1 change: 1 addition & 0 deletions IdentityCore/src/controllers/MSIDRequestControlling.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ NS_ASSUME_NONNULL_BEGIN
@protocol MSIDRequestControlling <NSObject>

- (void)acquireToken:(nonnull MSIDRequestCompletionBlock)completionBlock;
- (void)shouldSkipAcquireTokenBasedOn:(nonnull NSError *)error;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. can we add this flag directly to "acquireToken" method?
  2. Nit: Can we rename it to "skipAcquire..." instead of "should..."?"should" sounds like a dynamic condition to me, while here we know for sure that we want to skip.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1, methods with 'should' prefix usually indicate return type as BOOL but this does not seem to be the case here.


@end

Expand Down
19 changes: 13 additions & 6 deletions IdentityCore/src/controllers/MSIDSilentController.m
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ - (void)acquireTokenWithRequest:(MSIDSilentTokenRequest *)request
MSID_LOG_WITH_CTX(MSIDLogLevelError, nil, @"Passed nil completionBlock");
return;
}

CONDITIONAL_START_EVENT(CONDITIONAL_SHARED_INSTANCE, self.requestParameters.telemetryRequestId, MSID_TELEMETRY_EVENT_API_EVENT);
self.currentRequest = request;
[request executeRequestWithCompletion:^(MSIDTokenResult *result, NSError *error)
Expand Down Expand Up @@ -143,19 +143,26 @@ - (void)acquireTokenWithRequest:(MSIDSilentTokenRequest *)request
self.currentRequest = nil;
MSIDRequestCompletionBlock completionBlockWrapper = ^(MSIDTokenResult *fallResult, NSError *fallError)
{
// We don't have any meaningful information from fallback controller (edge case of SSO error) so we use the local controller result earlier
if (!fallResult && (fallError.code == MSIDErrorSSOExtensionUnexpectedError))
// Only return fallback when there is a valid result, otherwise, return error from main controller
// (!result && !error) is a special case when using local silent controller and to skip local refreh token (broker first flow). In this case, the main controller is the 1st fallback controller, and should return the error
if (fallResult || (!result && !error))
Copy link

Copilot AI May 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The compound condition determining when to use the fallback result versus the main controller's error could benefit from additional inline documentation. A brief explanation of why the condition prioritizes a valid fallback result or the absence of both result and error would improve maintainability.

Copilot uses AI. Check for mistakes.
{
completionBlock(result, error);
completionBlock(fallResult, fallError);
}
else
{
completionBlock(fallResult, fallError);
completionBlock(result, error);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we call fallback if we already have result?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case, the result is nil, the valid part is error only. I can send nil specifically

}
};


[self.fallbackController shouldSkipAcquireTokenBasedOn:error];
[self.fallbackController acquireToken:completionBlockWrapper];
}];
}

- (void)shouldSkipAcquireTokenBasedOn:(NSError *)error
{
// This method is not used in this class.
}

@end
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,5 @@ - (BOOL)shouldFallback:(NSError *)error
}

@end

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,11 @@ - (BOOL)hasCompletionBlock
return result;
}

- (void)shouldSkipAcquireTokenBasedOn:(NSError *)error
{
// This method is not used in this class.
}

#pragma mark - Fallback

- (void)handleFailedOpenURL:(BOOL)shouldFallbackToLocalController
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,44 @@
#import "MSIDLogger+Internal.h"
#import "MSIDXpcProviderCache.h"

@interface MSIDXpcSilentTokenRequestController ()

// shouldSkipXpcRequest is used when the fallback is not needed for non ASAuthorizationErrorDomain or MSIDErrorSSOExtensionUnexpectedError
@property (nonatomic) BOOL shouldSkipAcquireToken;
Comment on lines +33 to +34
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment says shouldSkipXpcRequest but property is named shouldSkipAcquireToken. Can you rename property to shouldSkipCallingXpc? shouldSkipAcquireToken is confusing

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this boolean would be initialized to NO by default, I would suggest naming property to 'shouldUseXpcToAcquireToken' instead of 'shouldSkip..'


@end

@implementation MSIDXpcSilentTokenRequestController

- (void)acquireToken:(MSIDRequestCompletionBlock)completionBlock
{
MSID_LOG_WITH_CTX(MSIDLogLevelInfo, self.requestParameters, @"Beginning silent broker xpc flow.");
MSIDRequestCompletionBlock completionBlockWrapper = ^(MSIDTokenResult *result, NSError *error)
MSID_LOG_WITH_CTX(MSIDLogLevelInfo, self.requestParameters, @"Beginning silent broker xpc flow, should use Xpc flow to acquire token: %@", @(!self.shouldSkipAcquireToken));
if (!self.shouldSkipAcquireToken)
{
MSID_LOG_WITH_CTX(MSIDLogLevelInfo, self.requestParameters, @"Silent broker xpc flow finished. Result %@, error: %ld error domain: %@, shouldFallBack: %@", _PII_NULLIFY(result), (long)error.code, error.domain, @(self.fallbackController != nil));
completionBlock(result, error);
};

__auto_type request = [self.tokenRequestProvider silentXpcTokenRequestWithParameters:self.requestParameters
forceRefresh:self.forceRefresh];
[self acquireTokenWithRequest:request completionBlock:completionBlockWrapper];
MSIDRequestCompletionBlock completionBlockWrapper = ^(MSIDTokenResult *result, NSError *error)
{
MSID_LOG_WITH_CTX(MSIDLogLevelInfo, self.requestParameters, @"Silent broker xpc flow finished. Result %@, error: %ld error domain: %@, shouldFallBack: %@", _PII_NULLIFY(result), (long)error.code, error.domain, @(self.fallbackController != nil));
completionBlock(result, error);
};

__auto_type request = [self.tokenRequestProvider silentXpcTokenRequestWithParameters:self.requestParameters
forceRefresh:self.forceRefresh];
[self acquireTokenWithRequest:request completionBlock:completionBlockWrapper];
}
else
{
// self.fallbackController cannot be nil here as it has been validated from caller
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this comment inaccurate? If we know fallbackController cannot be nil here, why do a nil check and log in the code? Please remove the comment as it isn't accurate according to the code following it

if (self.fallbackController)
{
[self.fallbackController acquireToken:completionBlock];
}
else
{
// Add handler in case
NSError *error = MSIDCreateError(MSIDErrorDomain, MSIDErrorInternal, @"Fallback controller is nil", nil, nil, nil, nil, nil, YES);
if (completionBlock) completionBlock(nil, error);
}
}
}

+ (BOOL)canPerformRequest
Expand All @@ -55,4 +79,24 @@ + (BOOL)canPerformRequest
}
}

- (void)shouldSkipAcquireTokenBasedOn:(NSError *)error
{
self.shouldSkipAcquireToken = YES;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if error is nil? This method will log incorrect info which might confuse in case of issue debugging

MSID_LOG_WITH_CTX(MSIDLogLevelInfo, self.requestParameters, @"Looking if we should fallback to Xpc controller, error: %ld error domain: %@.", (long)error.code, error.domain);
// If it is MSIDErrorDomain and Sso Extension returns unexpected error, we should fall back to local controler and unblock user
if (![error.domain isEqualToString:ASAuthorizationErrorDomain] && ![error.domain isEqualToString:MSIDErrorDomain]) {
Copy link

Copilot AI May 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The empty if-block checking the error domain may be unclear to future maintainers. Consider adding a comment or explicitly setting 'shouldSkipAcquireToken' to clarify the intended behavior when the error domain is not ASAuthorizationErrorDomain or MSIDErrorDomain.

Suggested change
if (![error.domain isEqualToString:ASAuthorizationErrorDomain] && ![error.domain isEqualToString:MSIDErrorDomain]) {
if (![error.domain isEqualToString:ASAuthorizationErrorDomain] && ![error.domain isEqualToString:MSIDErrorDomain]) {
// No action is required for error domains other than ASAuthorizationErrorDomain or MSIDErrorDomain.
// This block is intentionally left empty.

Copilot uses AI. Check for mistakes.
}
Comment on lines +87 to +88
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this supposed to do? Did you miss something?


switch (error.code)
{
case ASAuthorizationErrorNotHandled:
case ASAuthorizationErrorUnknown:
case ASAuthorizationErrorFailed:
case MSIDErrorSSOExtensionUnexpectedError:
self.shouldSkipAcquireToken = NO;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can the controller be reused for multiple requests? If it is, controller's shouldSkipAcquireToken might get set to NO in 1st request and remain NO for second request

}

MSID_LOG_WITH_CTX(MSIDLogLevelInfo, self.requestParameters, @"Xpc controller should do fallback: %@", !self.shouldSkipAcquireToken ? @"YES" : @"NO");
}

@end
Loading
Loading