Skip to content
5 changes: 5 additions & 0 deletions IdentityCore/src/MSIDError.h
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,9 @@ typedef NS_ENUM(NSInteger, MSIDErrorCode)

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.

// Broker Xpc internal error
MSIDErrorBrokerXpcUnexpectedError = -52001,

// Error thrown when oauth error = MSIDServerInvalidRequest and error_code = 50142 (SecureChangePasswordDueToConditionalAccess)
MSIDErrorServerInvalidRequestResetPasswordRequired = -50142,
Comment on lines +371 to +372
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

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

MSIDErrorCode values are documented as grouped by domain/range (e.g., Server errors are 514xx in MSIDOAuthErrorDomain). Adding MSIDErrorServerInvalidRequestResetPasswordRequired = -50142 breaks that established numbering scheme and places an OAuth/server error code outside the 514xx range, which can confuse diagnostics and any code that relies on these ranges. Consider assigning a -514xx value (e.g., next available after -51417) and locating this enum entry in the existing “Server errors (514xx)” section alongside the other OAuth server errors.

Copilot uses AI. Check for mistakes.
Comment on lines +371 to +372
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

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

The enum comment says “oauth error = MSIDServerInvalidRequest”, but the OAuth error value being checked is the string "invalid_request" (which maps to MSIDErrorServerInvalidRequest). Updating this comment would avoid confusion about whether this refers to an OAuth error string vs an MSIDErrorCode value.

Copilot uses AI. Check for mistakes.

};

Expand All @@ -376,6 +379,8 @@ extern MSIDErrorCode MSIDErrorCodeForOAuthError(NSString * _Nullable oauthError,

extern MSIDErrorCode MSIDErrorCodeForOAuthErrorWithSubErrorCode(NSString * _Nullable oauthError, MSIDErrorCode defaultCode, NSString * _Nullable subError);

extern MSIDErrorCode MSIDErrorCodeForOAuthErrorWithSTSErrorCodes(NSString * _Nullable oauthError, MSIDErrorCode defaultCode, NSArray<NSNumber *> * _Nullable stsErrorCodes);

extern NSDictionary<NSString *, NSArray *> * _Nonnull MSIDErrorDomainsAndCodes(void);

extern void MSIDFillAndLogError(NSError * _Nullable __autoreleasing * _Nullable error, MSIDErrorCode errorCode, NSString * _Nullable errorDescription, NSUUID * _Nullable correlationID);
Expand Down
17 changes: 17 additions & 0 deletions IdentityCore/src/MSIDError.m
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,20 @@
userInfo:additionalUserInfo];
}

MSIDErrorCode MSIDErrorCodeForOAuthErrorWithSTSErrorCodes(NSString *oauthError, MSIDErrorCode defaultCode, NSArray<NSNumber *> *stsErrorCodes)
{
if (stsErrorCodes.count == 0)
{
return MSIDErrorCodeForOAuthError(oauthError, defaultCode);
}
if (oauthError && [oauthError caseInsensitiveCompare:@"invalid_request"] == NSOrderedSame
&& [stsErrorCodes containsObject:@50142])
{
Comment on lines +84 to +86
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

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

@50142 is a hard-coded STS error code. To make this mapping easier to audit and extend (and to keep the meaning discoverable), consider introducing a named constant (e.g., MSIDSTSErrorCodeSecureChangePasswordDueToConditionalAccess) and using that in the containsObject: check (and in tests).

Copilot uses AI. Check for mistakes.
return MSIDErrorServerInvalidRequestResetPasswordRequired;
}
return MSIDErrorCodeForOAuthError(oauthError, defaultCode);
}

MSIDErrorCode MSIDErrorCodeForOAuthError(NSString *oauthError, MSIDErrorCode defaultCode)
{
if (oauthError && [oauthError caseInsensitiveCompare:@"invalid_request"] == NSOrderedSame)
Expand Down Expand Up @@ -228,6 +242,7 @@ MSIDErrorCode MSIDErrorCodeForOAuthErrorWithSubErrorCode(NSString *oauthError, M
@(MSIDErrorServerProtectionPoliciesRequired),
@(MSIDErrorAuthorizationFailed),
@(MSIDErrorServerError),
@(MSIDErrorServerInvalidRequestResetPasswordRequired),
],
MSIDHttpErrorCodeDomain : @[
@(MSIDErrorServerUnhandledResponse),
Expand Down Expand Up @@ -307,6 +322,8 @@ void MSIDFillAndLogError(NSError **error, MSIDErrorCode errorCode, NSString *err
return @"MSIDErrorServerProtectionPoliciesRequired";
case MSIDErrorAuthorizationFailed:
return @"MSIDErrorAuthorizationFailed";
case MSIDErrorServerInvalidRequestResetPasswordRequired:
return @"MSIDErrorServerInvalidRequestResetPasswordRequired";
// HTTP errors
case MSIDErrorServerUnhandledResponse:
return @"MSIDErrorServerUnhandledResponse";
Expand Down
1 change: 1 addition & 0 deletions IdentityCore/src/oauth2/MSIDOauth2Factory.m
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
#import "MSIDV1IdToken.h"
#import "MSIDClaimsRequest.h"
#import "MSIDAuthenticationScheme.h"
#import "MSIDError.h"

@implementation MSIDOauth2Factory

Expand Down
2 changes: 1 addition & 1 deletion IdentityCore/src/oauth2/MSIDTokenResponse.m
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ - (MSIDAccountType)accountType

- (MSIDErrorCode)oauthErrorCode
{
return MSIDErrorCodeForOAuthError(self.error, MSIDErrorServerOauth);
return MSIDErrorCodeForOAuthErrorWithSTSErrorCodes(self.error, MSIDErrorServerOauth, self.stsErrorCodes);
}

+ (MSIDProviderType)providerType
Expand Down
32 changes: 32 additions & 0 deletions IdentityCore/tests/MSIDErrorTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -195,4 +195,36 @@ - (void)testMSIDErrorWithInvalidGrantAndSubErrorTestSubErrorShouldReturnInvalidG
XCTAssertEqual(MSIDErrorCodeForOAuthErrorWithSubErrorCode(errorWithInvalidGrantWithOutTransferTokenExpired.userInfo[MSIDOAuthErrorKey], MSIDErrorUserCancel,errorWithInvalidGrantWithOutTransferTokenExpired.userInfo[MSIDOAuthSubErrorKey]), MSIDErrorServerInvalidGrant);
}

- (void)testMSIDErrorWithInvalidRequestAndSTS50142ShouldReturnResetPasswordRequired
{
MSIDErrorCode result = MSIDErrorCodeForOAuthErrorWithSTSErrorCodes(@"invalid_request",
MSIDErrorServerOauth,
@[@50142]);
XCTAssertEqual(result, MSIDErrorServerInvalidRequestResetPasswordRequired);
}

- (void)testMSIDErrorWithInvalidRequestAndDifferentSTSCodeShouldReturnInvalidRequest
{
MSIDErrorCode result = MSIDErrorCodeForOAuthErrorWithSTSErrorCodes(@"invalid_request",
MSIDErrorServerOauth,
@[@99999]);
XCTAssertEqual(result, MSIDErrorServerInvalidRequest);
}

- (void)testMSIDErrorWithNilSTSCodesShouldFallbackToBaseFunction
{
MSIDErrorCode result = MSIDErrorCodeForOAuthErrorWithSTSErrorCodes(@"invalid_request",
MSIDErrorServerOauth,
nil);
XCTAssertEqual(result, MSIDErrorServerInvalidRequest);
}

- (void)testMSIDErrorWithEmptySTSCodesShouldFallbackToBaseFunction
{
MSIDErrorCode result = MSIDErrorCodeForOAuthErrorWithSTSErrorCodes(@"invalid_request",
MSIDErrorServerOauth,
@[]);
XCTAssertEqual(result, MSIDErrorServerInvalidRequest);
}

@end
Loading