diff --git a/lib/native/MSALNativeCredManagment/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/lib/native/MSALNativeCredManagment/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000000..94b2795e22
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,4 @@
+
+
+
diff --git a/lib/native/MSALNativeCredManagment/CMSAL_Private/include/module.modulemap b/lib/native/MSALNativeCredManagment/CMSAL_Private/include/module.modulemap
new file mode 100644
index 0000000000..81720a0f0a
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/CMSAL_Private/include/module.modulemap
@@ -0,0 +1,21 @@
+// Minimal MSAL_Private module for credential management network layer.
+// Contains only IdentityCore types needed by Swift network code.
+module MSAL_Private {
+ header "/Users/antrix1989/workspace/apple/azure-activedirectory-tokenbroker-for-objc/sedemche/ciam-cred-managment/ADAuthenticationBroker/Frameworks/microsoft-authentication-library-for-objc/MSAL/IdentityCore/IdentityCore/src/network/MSIDHttpRequest.h"
+ header "/Users/antrix1989/workspace/apple/azure-activedirectory-tokenbroker-for-objc/sedemche/ciam-cred-managment/ADAuthenticationBroker/Frameworks/microsoft-authentication-library-for-objc/MSAL/IdentityCore/IdentityCore/src/network/MSIDHttpRequestInterceptorProtocol.h"
+ header "/Users/antrix1989/workspace/apple/azure-activedirectory-tokenbroker-for-objc/sedemche/ciam-cred-managment/ADAuthenticationBroker/Frameworks/microsoft-authentication-library-for-objc/MSAL/IdentityCore/IdentityCore/src/network/request_server_telemetry/MSIDHttpRequestServerTelemetryHandling.h"
+ header "/Users/antrix1989/workspace/apple/azure-activedirectory-tokenbroker-for-objc/sedemche/ciam-cred-managment/ADAuthenticationBroker/Frameworks/microsoft-authentication-library-for-objc/MSAL/IdentityCore/IdentityCore/src/network/request_serializer/MSIDRequestSerialization.h"
+ header "/Users/antrix1989/workspace/apple/azure-activedirectory-tokenbroker-for-objc/sedemche/ciam-cred-managment/ADAuthenticationBroker/Frameworks/microsoft-authentication-library-for-objc/MSAL/IdentityCore/IdentityCore/src/network/request_configurator/MSIDHttpRequestConfiguratorProtocol.h"
+ header "/Users/antrix1989/workspace/apple/azure-activedirectory-tokenbroker-for-objc/sedemche/ciam-cred-managment/ADAuthenticationBroker/Frameworks/microsoft-authentication-library-for-objc/MSAL/IdentityCore/IdentityCore/src/network/response_serializer/MSIDResponseSerialization.h"
+ header "/Users/antrix1989/workspace/apple/azure-activedirectory-tokenbroker-for-objc/sedemche/ciam-cred-managment/ADAuthenticationBroker/Frameworks/microsoft-authentication-library-for-objc/MSAL/IdentityCore/IdentityCore/src/network/error_handler/MSIDHttpRequestErrorHandling.h"
+ header "/Users/antrix1989/workspace/apple/azure-activedirectory-tokenbroker-for-objc/sedemche/ciam-cred-managment/ADAuthenticationBroker/Frameworks/microsoft-authentication-library-for-objc/MSAL/IdentityCore/IdentityCore/src/MSIDBasicContext.h"
+ header "/Users/antrix1989/workspace/apple/azure-activedirectory-tokenbroker-for-objc/sedemche/ciam-cred-managment/ADAuthenticationBroker/Frameworks/microsoft-authentication-library-for-objc/MSAL/IdentityCore/IdentityCore/src/logger/MSIDLogger.h"
+ header "/Users/antrix1989/workspace/apple/azure-activedirectory-tokenbroker-for-objc/sedemche/ciam-cred-managment/ADAuthenticationBroker/Frameworks/microsoft-authentication-library-for-objc/MSAL/IdentityCore/IdentityCore/src/logger/MSIDLogger+Internal.h"
+ header "/Users/antrix1989/workspace/apple/azure-activedirectory-tokenbroker-for-objc/sedemche/ciam-cred-managment/ADAuthenticationBroker/Frameworks/microsoft-authentication-library-for-objc/MSAL/IdentityCore/IdentityCore/src/logger/MSIDMaskedHashableLogParameter.h"
+ header "/Users/antrix1989/workspace/apple/azure-activedirectory-tokenbroker-for-objc/sedemche/ciam-cred-managment/ADAuthenticationBroker/Frameworks/microsoft-authentication-library-for-objc/MSAL/IdentityCore/IdentityCore/src/logger/MSIDMaskedLogParameter.h"
+ header "/Users/antrix1989/workspace/apple/azure-activedirectory-tokenbroker-for-objc/sedemche/ciam-cred-managment/ADAuthenticationBroker/Frameworks/microsoft-authentication-library-for-objc/MSAL/IdentityCore/IdentityCore/src/logger/MSIDMaskedUsernameLogParameter.h"
+ header "/Users/antrix1989/workspace/apple/azure-activedirectory-tokenbroker-for-objc/sedemche/ciam-cred-managment/ADAuthenticationBroker/Frameworks/microsoft-authentication-library-for-objc/MSAL/IdentityCore/IdentityCore/src/MSIDError.h"
+ header "/Users/antrix1989/workspace/apple/azure-activedirectory-tokenbroker-for-objc/sedemche/ciam-cred-managment/ADAuthenticationBroker/Frameworks/microsoft-authentication-library-for-objc/MSAL/IdentityCore/IdentityCore/src/oauth2/MSIDExternalSSOContext.h"
+ header "/Users/antrix1989/workspace/apple/azure-activedirectory-tokenbroker-for-objc/sedemche/ciam-cred-managment/ADAuthenticationBroker/Frameworks/microsoft-authentication-library-for-objc/MSAL/IdentityCore/IdentityCore/src/parameters/MSIDRequestParameters.h"
+ export *
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment.xcodeproj/project.pbxproj b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment.xcodeproj/project.pbxproj
new file mode 100644
index 0000000000..edc68ac48b
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment.xcodeproj/project.pbxproj
@@ -0,0 +1,969 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 77;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 2394A84C2FC5208100B9FF0C /* MSALNativeCredManagment.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2394A8412FC5208100B9FF0C /* MSALNativeCredManagment.framework */; };
+ 2394A88B2FC7C14100B9FF0C /* MSAL in Frameworks */ = {isa = PBXBuildFile; productRef = 2394A88A2FC7C14100B9FF0C /* MSAL */; };
+ 2394A8E02FCA000100B9FF0C /* MSALNativeCredManagment.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2394A8412FC5208100B9FF0C /* MSALNativeCredManagment.framework */; };
+ 2394A8E12FCA000100B9FF0C /* MSALNativeCredManagment.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 2394A8412FC5208100B9FF0C /* MSALNativeCredManagment.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+ 2394A8E52FCA000200B9FF0C /* MSAL in Frameworks */ = {isa = PBXBuildFile; productRef = 2394A8E62FCA000200B9FF0C /* MSAL */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ 2394A84D2FC5208100B9FF0C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 2394A8382FC5208100B9FF0C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 2394A8402FC5208100B9FF0C;
+ remoteInfo = MSALNativeCredManagment;
+ };
+ 2394A8B32FC7FE7400B9FF0C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 2394A8382FC5208100B9FF0C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 2394A8A12FC7FE7200B9FF0C;
+ remoteInfo = MSALNativeCredManagmentSampleApp;
+ };
+ 2394A8BD2FC7FE7400B9FF0C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 2394A8382FC5208100B9FF0C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 2394A8A12FC7FE7200B9FF0C;
+ remoteInfo = MSALNativeCredManagmentSampleApp;
+ };
+ 2394A8E22FCA000100B9FF0C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 2394A8382FC5208100B9FF0C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 2394A8402FC5208100B9FF0C;
+ remoteInfo = MSALNativeCredManagment;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ 2394A8E32FCA000100B9FF0C /* Embed Frameworks */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = "";
+ dstSubfolderSpec = 10;
+ files = (
+ 2394A8E12FCA000100B9FF0C /* MSALNativeCredManagment.framework in Embed Frameworks */,
+ );
+ name = "Embed Frameworks";
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 2394A8412FC5208100B9FF0C /* MSALNativeCredManagment.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MSALNativeCredManagment.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 2394A84B2FC5208100B9FF0C /* MSALNativeCredManagmentTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MSALNativeCredManagmentTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ 2394A8A22FC7FE7200B9FF0C /* MSALNativeCredManagmentSampleApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MSALNativeCredManagmentSampleApp.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 2394A8B22FC7FE7400B9FF0C /* MSALNativeCredManagmentSampleAppTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MSALNativeCredManagmentSampleAppTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ 2394A8BC2FC7FE7400B9FF0C /* MSALNativeCredManagmentSampleAppUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MSALNativeCredManagmentSampleAppUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+/* End PBXFileReference section */
+
+/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
+ 2394A8532FC5208100B9FF0C /* Exceptions for "MSALNativeCredManagment" folder in "MSALNativeCredManagment" target */ = {
+ isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
+ publicHeaders = (
+ MSALNativeCredManagment.h,
+ );
+ target = 2394A8402FC5208100B9FF0C /* MSALNativeCredManagment */;
+ };
+/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
+
+/* Begin PBXFileSystemSynchronizedRootGroup section */
+ 2394A8432FC5208100B9FF0C /* MSALNativeCredManagment */ = {
+ isa = PBXFileSystemSynchronizedRootGroup;
+ exceptions = (
+ 2394A8532FC5208100B9FF0C /* Exceptions for "MSALNativeCredManagment" folder in "MSALNativeCredManagment" target */,
+ );
+ path = MSALNativeCredManagment;
+ sourceTree = "";
+ };
+ 2394A84F2FC5208100B9FF0C /* MSALNativeCredManagmentTests */ = {
+ isa = PBXFileSystemSynchronizedRootGroup;
+ path = MSALNativeCredManagmentTests;
+ sourceTree = "";
+ };
+ 2394A8A32FC7FE7200B9FF0C /* MSALNativeCredManagmentSampleApp */ = {
+ isa = PBXFileSystemSynchronizedRootGroup;
+ path = MSALNativeCredManagmentSampleApp;
+ sourceTree = "";
+ };
+ 2394A8B52FC7FE7400B9FF0C /* MSALNativeCredManagmentSampleAppTests */ = {
+ isa = PBXFileSystemSynchronizedRootGroup;
+ path = MSALNativeCredManagmentSampleAppTests;
+ sourceTree = "";
+ };
+ 2394A8BF2FC7FE7400B9FF0C /* MSALNativeCredManagmentSampleAppUITests */ = {
+ isa = PBXFileSystemSynchronizedRootGroup;
+ path = MSALNativeCredManagmentSampleAppUITests;
+ sourceTree = "";
+ };
+/* End PBXFileSystemSynchronizedRootGroup section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 2394A83E2FC5208100B9FF0C /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 2394A88B2FC7C14100B9FF0C /* MSAL in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 2394A8482FC5208100B9FF0C /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 2394A84C2FC5208100B9FF0C /* MSALNativeCredManagment.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 2394A89F2FC7FE7200B9FF0C /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 2394A8E52FCA000200B9FF0C /* MSAL in Frameworks */,
+ 2394A8E02FCA000100B9FF0C /* MSALNativeCredManagment.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 2394A8AF2FC7FE7400B9FF0C /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 2394A8B92FC7FE7400B9FF0C /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 2394A8372FC5208100B9FF0C = {
+ isa = PBXGroup;
+ children = (
+ 2394A8432FC5208100B9FF0C /* MSALNativeCredManagment */,
+ 2394A84F2FC5208100B9FF0C /* MSALNativeCredManagmentTests */,
+ 2394A8A32FC7FE7200B9FF0C /* MSALNativeCredManagmentSampleApp */,
+ 2394A8B52FC7FE7400B9FF0C /* MSALNativeCredManagmentSampleAppTests */,
+ 2394A8BF2FC7FE7400B9FF0C /* MSALNativeCredManagmentSampleAppUITests */,
+ 2394A8422FC5208100B9FF0C /* Products */,
+ );
+ sourceTree = "";
+ };
+ 2394A8422FC5208100B9FF0C /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 2394A8412FC5208100B9FF0C /* MSALNativeCredManagment.framework */,
+ 2394A84B2FC5208100B9FF0C /* MSALNativeCredManagmentTests.xctest */,
+ 2394A8A22FC7FE7200B9FF0C /* MSALNativeCredManagmentSampleApp.app */,
+ 2394A8B22FC7FE7400B9FF0C /* MSALNativeCredManagmentSampleAppTests.xctest */,
+ 2394A8BC2FC7FE7400B9FF0C /* MSALNativeCredManagmentSampleAppUITests.xctest */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ 2394A83C2FC5208100B9FF0C /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+ 2394A8402FC5208100B9FF0C /* MSALNativeCredManagment */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 2394A8542FC5208100B9FF0C /* Build configuration list for PBXNativeTarget "MSALNativeCredManagment" */;
+ buildPhases = (
+ 2394A83C2FC5208100B9FF0C /* Headers */,
+ 2394A83D2FC5208100B9FF0C /* Sources */,
+ 2394A83E2FC5208100B9FF0C /* Frameworks */,
+ 2394A83F2FC5208100B9FF0C /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ fileSystemSynchronizedGroups = (
+ 2394A8432FC5208100B9FF0C /* MSALNativeCredManagment */,
+ );
+ name = MSALNativeCredManagment;
+ packageProductDependencies = (
+ 2394A88A2FC7C14100B9FF0C /* MSAL */,
+ );
+ productName = MSALNativeCredManagment;
+ productReference = 2394A8412FC5208100B9FF0C /* MSALNativeCredManagment.framework */;
+ productType = "com.apple.product-type.framework";
+ };
+ 2394A84A2FC5208100B9FF0C /* MSALNativeCredManagmentTests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 2394A8592FC5208100B9FF0C /* Build configuration list for PBXNativeTarget "MSALNativeCredManagmentTests" */;
+ buildPhases = (
+ 2394A8472FC5208100B9FF0C /* Sources */,
+ 2394A8482FC5208100B9FF0C /* Frameworks */,
+ 2394A8492FC5208100B9FF0C /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 2394A84E2FC5208100B9FF0C /* PBXTargetDependency */,
+ );
+ fileSystemSynchronizedGroups = (
+ 2394A84F2FC5208100B9FF0C /* MSALNativeCredManagmentTests */,
+ );
+ name = MSALNativeCredManagmentTests;
+ packageProductDependencies = (
+ );
+ productName = MSALNativeCredManagmentTests;
+ productReference = 2394A84B2FC5208100B9FF0C /* MSALNativeCredManagmentTests.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
+ 2394A8A12FC7FE7200B9FF0C /* MSALNativeCredManagmentSampleApp */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 2394A8C42FC7FE7400B9FF0C /* Build configuration list for PBXNativeTarget "MSALNativeCredManagmentSampleApp" */;
+ buildPhases = (
+ 2394A89E2FC7FE7200B9FF0C /* Sources */,
+ 2394A89F2FC7FE7200B9FF0C /* Frameworks */,
+ 2394A8A02FC7FE7200B9FF0C /* Resources */,
+ 2394A8E32FCA000100B9FF0C /* Embed Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 2394A8E42FCA000100B9FF0C /* PBXTargetDependency */,
+ );
+ fileSystemSynchronizedGroups = (
+ 2394A8A32FC7FE7200B9FF0C /* MSALNativeCredManagmentSampleApp */,
+ );
+ name = MSALNativeCredManagmentSampleApp;
+ packageProductDependencies = (
+ 2394A8E62FCA000200B9FF0C /* MSAL */,
+ );
+ productName = MSALNativeCredManagmentSampleApp;
+ productReference = 2394A8A22FC7FE7200B9FF0C /* MSALNativeCredManagmentSampleApp.app */;
+ productType = "com.apple.product-type.application";
+ };
+ 2394A8B12FC7FE7400B9FF0C /* MSALNativeCredManagmentSampleAppTests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 2394A8C72FC7FE7400B9FF0C /* Build configuration list for PBXNativeTarget "MSALNativeCredManagmentSampleAppTests" */;
+ buildPhases = (
+ 2394A8AE2FC7FE7400B9FF0C /* Sources */,
+ 2394A8AF2FC7FE7400B9FF0C /* Frameworks */,
+ 2394A8B02FC7FE7400B9FF0C /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 2394A8B42FC7FE7400B9FF0C /* PBXTargetDependency */,
+ );
+ fileSystemSynchronizedGroups = (
+ 2394A8B52FC7FE7400B9FF0C /* MSALNativeCredManagmentSampleAppTests */,
+ );
+ name = MSALNativeCredManagmentSampleAppTests;
+ packageProductDependencies = (
+ );
+ productName = MSALNativeCredManagmentSampleAppTests;
+ productReference = 2394A8B22FC7FE7400B9FF0C /* MSALNativeCredManagmentSampleAppTests.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
+ 2394A8BB2FC7FE7400B9FF0C /* MSALNativeCredManagmentSampleAppUITests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 2394A8CA2FC7FE7400B9FF0C /* Build configuration list for PBXNativeTarget "MSALNativeCredManagmentSampleAppUITests" */;
+ buildPhases = (
+ 2394A8B82FC7FE7400B9FF0C /* Sources */,
+ 2394A8B92FC7FE7400B9FF0C /* Frameworks */,
+ 2394A8BA2FC7FE7400B9FF0C /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 2394A8BE2FC7FE7400B9FF0C /* PBXTargetDependency */,
+ );
+ fileSystemSynchronizedGroups = (
+ 2394A8BF2FC7FE7400B9FF0C /* MSALNativeCredManagmentSampleAppUITests */,
+ );
+ name = MSALNativeCredManagmentSampleAppUITests;
+ packageProductDependencies = (
+ );
+ productName = MSALNativeCredManagmentSampleAppUITests;
+ productReference = 2394A8BC2FC7FE7400B9FF0C /* MSALNativeCredManagmentSampleAppUITests.xctest */;
+ productType = "com.apple.product-type.bundle.ui-testing";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 2394A8382FC5208100B9FF0C /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ BuildIndependentTargetsInParallel = 1;
+ LastSwiftUpdateCheck = 1620;
+ LastUpgradeCheck = 1620;
+ TargetAttributes = {
+ 2394A8402FC5208100B9FF0C = {
+ CreatedOnToolsVersion = 16.2;
+ };
+ 2394A84A2FC5208100B9FF0C = {
+ CreatedOnToolsVersion = 16.2;
+ };
+ 2394A8A12FC7FE7200B9FF0C = {
+ CreatedOnToolsVersion = 16.2;
+ };
+ 2394A8B12FC7FE7400B9FF0C = {
+ CreatedOnToolsVersion = 16.2;
+ TestTargetID = 2394A8A12FC7FE7200B9FF0C;
+ };
+ 2394A8BB2FC7FE7400B9FF0C = {
+ CreatedOnToolsVersion = 16.2;
+ TestTargetID = 2394A8A12FC7FE7200B9FF0C;
+ };
+ };
+ };
+ buildConfigurationList = 2394A83B2FC5208100B9FF0C /* Build configuration list for PBXProject "MSALNativeCredManagment" */;
+ developmentRegion = en;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = 2394A8372FC5208100B9FF0C;
+ minimizedProjectReferenceProxies = 1;
+ packageReferences = (
+ 2394A8892FC7C14100B9FF0C /* XCLocalSwiftPackageReference "../../../../microsoft-authentication-library-for-objc" */,
+ 2394A8D52FC8032400B9FF0C /* XCLocalSwiftPackageReference "../MSALNativeCredManagment" */,
+ );
+ preferredProjectObjectVersion = 77;
+ productRefGroup = 2394A8422FC5208100B9FF0C /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 2394A8402FC5208100B9FF0C /* MSALNativeCredManagment */,
+ 2394A84A2FC5208100B9FF0C /* MSALNativeCredManagmentTests */,
+ 2394A8A12FC7FE7200B9FF0C /* MSALNativeCredManagmentSampleApp */,
+ 2394A8B12FC7FE7400B9FF0C /* MSALNativeCredManagmentSampleAppTests */,
+ 2394A8BB2FC7FE7400B9FF0C /* MSALNativeCredManagmentSampleAppUITests */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 2394A83F2FC5208100B9FF0C /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 2394A8492FC5208100B9FF0C /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 2394A8A02FC7FE7200B9FF0C /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 2394A8B02FC7FE7400B9FF0C /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 2394A8BA2FC7FE7400B9FF0C /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 2394A83D2FC5208100B9FF0C /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 2394A8472FC5208100B9FF0C /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 2394A89E2FC7FE7200B9FF0C /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 2394A8AE2FC7FE7400B9FF0C /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 2394A8B82FC7FE7400B9FF0C /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ 2394A84E2FC5208100B9FF0C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 2394A8402FC5208100B9FF0C /* MSALNativeCredManagment */;
+ targetProxy = 2394A84D2FC5208100B9FF0C /* PBXContainerItemProxy */;
+ };
+ 2394A8B42FC7FE7400B9FF0C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 2394A8A12FC7FE7200B9FF0C /* MSALNativeCredManagmentSampleApp */;
+ targetProxy = 2394A8B32FC7FE7400B9FF0C /* PBXContainerItemProxy */;
+ };
+ 2394A8BE2FC7FE7400B9FF0C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 2394A8A12FC7FE7200B9FF0C /* MSALNativeCredManagmentSampleApp */;
+ targetProxy = 2394A8BD2FC7FE7400B9FF0C /* PBXContainerItemProxy */;
+ };
+ 2394A8E42FCA000100B9FF0C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 2394A8402FC5208100B9FF0C /* MSALNativeCredManagment */;
+ targetProxy = 2394A8E22FCA000100B9FF0C /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ 2394A8552FC5208100B9FF0C /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES;
+ BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEFINES_MODULE = YES;
+ DEVELOPMENT_TEAM = UBF8T346G9;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ DYLIB_INSTALL_NAME_BASE = "@rpath";
+ ENABLE_MODULE_VERIFIER = YES;
+ GENERATE_INFOPLIST_FILE = YES;
+ HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../MSAL/IdentityCore/IdentityCore/src/**";
+ INFOPLIST_KEY_NSHumanReadableCopyright = "";
+ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+ IPHONEOS_DEPLOYMENT_TARGET = 18.2;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "@executable_path/Frameworks",
+ "@loader_path/Frameworks",
+ );
+ "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = (
+ "@executable_path/../Frameworks",
+ "@loader_path/Frameworks",
+ );
+ MACOSX_DEPLOYMENT_TARGET = 15.2;
+ MARKETING_VERSION = 1.0;
+ MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
+ MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
+ PRODUCT_BUNDLE_IDENTIFIER = com.microsoft.MSALNativeCredManagment.MSALNativeCredManagment;
+ PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
+ SDKROOT = auto;
+ SKIP_INSTALL = YES;
+ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx xros xrsimulator";
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_INCLUDE_PATHS = "$(SRCROOT)/CMSAL_Private/include";
+ SWIFT_INSTALL_OBJC_HEADER = NO;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2,7";
+ XROS_DEPLOYMENT_TARGET = 2.2;
+ };
+ name = Debug;
+ };
+ 2394A8562FC5208100B9FF0C /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES;
+ BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEFINES_MODULE = YES;
+ DEVELOPMENT_TEAM = UBF8T346G9;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ DYLIB_INSTALL_NAME_BASE = "@rpath";
+ ENABLE_MODULE_VERIFIER = YES;
+ GENERATE_INFOPLIST_FILE = YES;
+ HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../MSAL/IdentityCore/IdentityCore/src/**";
+ INFOPLIST_KEY_NSHumanReadableCopyright = "";
+ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+ IPHONEOS_DEPLOYMENT_TARGET = 18.2;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "@executable_path/Frameworks",
+ "@loader_path/Frameworks",
+ );
+ "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = (
+ "@executable_path/../Frameworks",
+ "@loader_path/Frameworks",
+ );
+ MACOSX_DEPLOYMENT_TARGET = 15.2;
+ MARKETING_VERSION = 1.0;
+ MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
+ MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
+ PRODUCT_BUNDLE_IDENTIFIER = com.microsoft.MSALNativeCredManagment.MSALNativeCredManagment;
+ PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
+ SDKROOT = auto;
+ SKIP_INSTALL = YES;
+ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx xros xrsimulator";
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_INCLUDE_PATHS = "$(SRCROOT)/CMSAL_Private/include";
+ SWIFT_INSTALL_OBJC_HEADER = NO;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2,7";
+ XROS_DEPLOYMENT_TARGET = 2.2;
+ };
+ name = Release;
+ };
+ 2394A8572FC5208100B9FF0C /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COPY_PHASE_STRIP = NO;
+ CURRENT_PROJECT_VERSION = 1;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+ MTL_FAST_MATH = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ VERSIONING_SYSTEM = "apple-generic";
+ VERSION_INFO_PREFIX = "";
+ };
+ name = Debug;
+ };
+ 2394A8582FC5208100B9FF0C /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COPY_PHASE_STRIP = NO;
+ CURRENT_PROJECT_VERSION = 1;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ MTL_FAST_MATH = YES;
+ SWIFT_COMPILATION_MODE = wholemodule;
+ VERSIONING_SYSTEM = "apple-generic";
+ VERSION_INFO_PREFIX = "";
+ };
+ name = Release;
+ };
+ 2394A85A2FC5208100B9FF0C /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES;
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_TEAM = UBF8T346G9;
+ GENERATE_INFOPLIST_FILE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 18.2;
+ MACOSX_DEPLOYMENT_TARGET = 15.2;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = com.microsoft.MSALNativeCredManagment.MSALNativeCredManagmentTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = auto;
+ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx xros xrsimulator";
+ SWIFT_EMIT_LOC_STRINGS = NO;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2,7";
+ XROS_DEPLOYMENT_TARGET = 2.2;
+ };
+ name = Debug;
+ };
+ 2394A85B2FC5208100B9FF0C /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES;
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_TEAM = UBF8T346G9;
+ GENERATE_INFOPLIST_FILE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 18.2;
+ MACOSX_DEPLOYMENT_TARGET = 15.2;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = com.microsoft.MSALNativeCredManagment.MSALNativeCredManagmentTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = auto;
+ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx xros xrsimulator";
+ SWIFT_EMIT_LOC_STRINGS = NO;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2,7";
+ XROS_DEPLOYMENT_TARGET = 2.2;
+ };
+ name = Release;
+ };
+ 2394A8C52FC7FE7400B9FF0C /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ CODE_SIGN_ENTITLEMENTS = MSALNativeCredManagmentSampleApp/MSALNativeCredManagmentSampleApp.entitlements;
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_ASSET_PATHS = "\"MSALNativeCredManagmentSampleApp/Preview Content\"";
+ DEVELOPMENT_TEAM = UBF8T346G9;
+ ENABLE_HARDENED_RUNTIME = YES;
+ ENABLE_PREVIEWS = YES;
+ GENERATE_INFOPLIST_FILE = YES;
+ "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
+ "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
+ "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES;
+ "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphonesimulator*]" = YES;
+ "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphoneos*]" = YES;
+ "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphonesimulator*]" = YES;
+ "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphoneos*]" = UIStatusBarStyleDefault;
+ "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault;
+ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
+ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
+ IPHONEOS_DEPLOYMENT_TARGET = 18.2;
+ LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
+ "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
+ MACOSX_DEPLOYMENT_TARGET = 15.2;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = com.microsoft.azureauthenticator;
+ "PRODUCT_BUNDLE_IDENTIFIER[sdk=macosx*]" = com.microsoft.CompanyPortalMac;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = auto;
+ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx xros xrsimulator";
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2,7";
+ XROS_DEPLOYMENT_TARGET = 2.2;
+ };
+ name = Debug;
+ };
+ 2394A8C62FC7FE7400B9FF0C /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ CODE_SIGN_ENTITLEMENTS = MSALNativeCredManagmentSampleApp/MSALNativeCredManagmentSampleApp.entitlements;
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_ASSET_PATHS = "\"MSALNativeCredManagmentSampleApp/Preview Content\"";
+ DEVELOPMENT_TEAM = UBF8T346G9;
+ ENABLE_HARDENED_RUNTIME = YES;
+ ENABLE_PREVIEWS = YES;
+ GENERATE_INFOPLIST_FILE = YES;
+ "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
+ "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
+ "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES;
+ "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphonesimulator*]" = YES;
+ "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphoneos*]" = YES;
+ "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphonesimulator*]" = YES;
+ "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphoneos*]" = UIStatusBarStyleDefault;
+ "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault;
+ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
+ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
+ IPHONEOS_DEPLOYMENT_TARGET = 18.2;
+ LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
+ "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
+ MACOSX_DEPLOYMENT_TARGET = 15.2;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = com.microsoft.azureauthenticator;
+ "PRODUCT_BUNDLE_IDENTIFIER[sdk=macosx*]" = com.microsoft.CompanyPortalMac;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = auto;
+ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx xros xrsimulator";
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2,7";
+ XROS_DEPLOYMENT_TARGET = 2.2;
+ };
+ name = Release;
+ };
+ 2394A8C82FC7FE7400B9FF0C /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_TEAM = UBF8T346G9;
+ GENERATE_INFOPLIST_FILE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 18.2;
+ MACOSX_DEPLOYMENT_TARGET = 15.2;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = com.microsoft.MSALNativeCredManagment.MSALNativeCredManagmentSampleAppTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = auto;
+ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx xros xrsimulator";
+ SWIFT_EMIT_LOC_STRINGS = NO;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2,7";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/MSALNativeCredManagmentSampleApp.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/MSALNativeCredManagmentSampleApp";
+ XROS_DEPLOYMENT_TARGET = 2.2;
+ };
+ name = Debug;
+ };
+ 2394A8C92FC7FE7400B9FF0C /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_TEAM = UBF8T346G9;
+ GENERATE_INFOPLIST_FILE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 18.2;
+ MACOSX_DEPLOYMENT_TARGET = 15.2;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = com.microsoft.MSALNativeCredManagment.MSALNativeCredManagmentSampleAppTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = auto;
+ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx xros xrsimulator";
+ SWIFT_EMIT_LOC_STRINGS = NO;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2,7";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/MSALNativeCredManagmentSampleApp.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/MSALNativeCredManagmentSampleApp";
+ XROS_DEPLOYMENT_TARGET = 2.2;
+ };
+ name = Release;
+ };
+ 2394A8CB2FC7FE7400B9FF0C /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_TEAM = UBF8T346G9;
+ GENERATE_INFOPLIST_FILE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 18.2;
+ MACOSX_DEPLOYMENT_TARGET = 15.2;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = com.microsoft.MSALNativeCredManagment.MSALNativeCredManagmentSampleAppUITests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = auto;
+ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx xros xrsimulator";
+ SWIFT_EMIT_LOC_STRINGS = NO;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2,7";
+ TEST_TARGET_NAME = MSALNativeCredManagmentSampleApp;
+ XROS_DEPLOYMENT_TARGET = 2.2;
+ };
+ name = Debug;
+ };
+ 2394A8CC2FC7FE7400B9FF0C /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_TEAM = UBF8T346G9;
+ GENERATE_INFOPLIST_FILE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 18.2;
+ MACOSX_DEPLOYMENT_TARGET = 15.2;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = com.microsoft.MSALNativeCredManagment.MSALNativeCredManagmentSampleAppUITests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = auto;
+ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx xros xrsimulator";
+ SWIFT_EMIT_LOC_STRINGS = NO;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2,7";
+ TEST_TARGET_NAME = MSALNativeCredManagmentSampleApp;
+ XROS_DEPLOYMENT_TARGET = 2.2;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 2394A83B2FC5208100B9FF0C /* Build configuration list for PBXProject "MSALNativeCredManagment" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 2394A8572FC5208100B9FF0C /* Debug */,
+ 2394A8582FC5208100B9FF0C /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 2394A8542FC5208100B9FF0C /* Build configuration list for PBXNativeTarget "MSALNativeCredManagment" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 2394A8552FC5208100B9FF0C /* Debug */,
+ 2394A8562FC5208100B9FF0C /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 2394A8592FC5208100B9FF0C /* Build configuration list for PBXNativeTarget "MSALNativeCredManagmentTests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 2394A85A2FC5208100B9FF0C /* Debug */,
+ 2394A85B2FC5208100B9FF0C /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 2394A8C42FC7FE7400B9FF0C /* Build configuration list for PBXNativeTarget "MSALNativeCredManagmentSampleApp" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 2394A8C52FC7FE7400B9FF0C /* Debug */,
+ 2394A8C62FC7FE7400B9FF0C /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 2394A8C72FC7FE7400B9FF0C /* Build configuration list for PBXNativeTarget "MSALNativeCredManagmentSampleAppTests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 2394A8C82FC7FE7400B9FF0C /* Debug */,
+ 2394A8C92FC7FE7400B9FF0C /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 2394A8CA2FC7FE7400B9FF0C /* Build configuration list for PBXNativeTarget "MSALNativeCredManagmentSampleAppUITests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 2394A8CB2FC7FE7400B9FF0C /* Debug */,
+ 2394A8CC2FC7FE7400B9FF0C /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+
+/* Begin XCLocalSwiftPackageReference section */
+ 2394A8892FC7C14100B9FF0C /* XCLocalSwiftPackageReference "../../../../microsoft-authentication-library-for-objc" */ = {
+ isa = XCLocalSwiftPackageReference;
+ relativePath = "../../../../microsoft-authentication-library-for-objc";
+ };
+ 2394A8D52FC8032400B9FF0C /* XCLocalSwiftPackageReference "../MSALNativeCredManagment" */ = {
+ isa = XCLocalSwiftPackageReference;
+ relativePath = ../MSALNativeCredManagment;
+ };
+/* End XCLocalSwiftPackageReference section */
+
+/* Begin XCSwiftPackageProductDependency section */
+ 2394A88A2FC7C14100B9FF0C /* MSAL */ = {
+ isa = XCSwiftPackageProductDependency;
+ productName = MSAL;
+ };
+ 2394A8E62FCA000200B9FF0C /* MSAL */ = {
+ isa = XCSwiftPackageProductDependency;
+ productName = MSAL;
+ };
+/* End XCSwiftPackageProductDependency section */
+ };
+ rootObject = 2394A8382FC5208100B9FF0C /* Project object */;
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000000..919434a625
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/MSALNativeCredManagment.docc/MSALNativeCredManagment.md b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/MSALNativeCredManagment.docc/MSALNativeCredManagment.md
new file mode 100644
index 0000000000..769c241024
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/MSALNativeCredManagment.docc/MSALNativeCredManagment.md
@@ -0,0 +1,13 @@
+# ``MSALNativeCredManagment``
+
+Summary
+
+## Overview
+
+Text
+
+## Topics
+
+### Group
+
+- ``Symbol``
\ No newline at end of file
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/MSALNativeCredManagment.h b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/MSALNativeCredManagment.h
new file mode 100644
index 0000000000..408f37adb6
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/MSALNativeCredManagment.h
@@ -0,0 +1,18 @@
+//
+// MSALNativeCredManagment.h
+// MSALNativeCredManagment
+//
+// Created by Serhii Demchenko on 2026-05-25.
+//
+
+#import
+
+//! Project version number for MSALNativeCredManagment.
+FOUNDATION_EXPORT double MSALNativeCredManagmentVersionNumber;
+
+//! Project version string for MSALNativeCredManagment.
+FOUNDATION_EXPORT const unsigned char MSALNativeCredManagmentVersionString[];
+
+// In this header, you should import all the public headers of your framework using statements like #import
+
+
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/MSALNativeCredentialMethodsClient+Internal.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/MSALNativeCredentialMethodsClient+Internal.swift
new file mode 100644
index 0000000000..8b4e20b152
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/MSALNativeCredentialMethodsClient+Internal.swift
@@ -0,0 +1,290 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+import MSAL
+
+extension MSALNativeCredentialMethodsClient
+{
+ // MARK: - Token Acquisition
+
+ internal func acquireToken(
+ correlationId: UUID,
+ completion: @escaping (String?, Error?) -> Void
+ )
+ {
+ guard let tokenProvider = config.tokenProvider else
+ {
+ let error = MSALNativeCredentialManagementError(
+ type: .invalidConfiguration,
+ message: "Token provider is not configured.",
+ correlationId: correlationId
+ )
+ completion(nil, error)
+ return
+ }
+
+ let scopes = ["https://graph.microsoft.com/.default"]
+
+ tokenProvider.getAccessToken(scopes: scopes)
+ { accessToken, error in
+ completion(accessToken, error)
+ }
+ }
+
+ /// Async wrapper around the callback-based token acquisition.
+ internal func acquireTokenAsync(
+ correlationId: UUID
+ ) async -> Result
+ {
+ return await withCheckedContinuation
+ { continuation in
+ self.acquireToken(correlationId: correlationId)
+ { accessToken, tokenError in
+ if let tokenError = tokenError
+ {
+ let credError = MSALNativeCredentialManagementError(
+ type: .unauthorized,
+ message: "Failed to acquire access token.",
+ correlationId: correlationId,
+ underlyingError: tokenError
+ )
+ continuation.resume(returning: .failure(credError))
+ return
+ }
+
+ guard let accessToken = accessToken else
+ {
+ let credError = MSALNativeCredentialManagementError(
+ type: .unauthorized,
+ message: "Token provider returned nil access token.",
+ correlationId: correlationId
+ )
+ continuation.resume(returning: .failure(credError))
+ return
+ }
+
+ continuation.resume(returning: .success(accessToken))
+ }
+ }
+ }
+
+ // MARK: - API Client Access
+
+ /// Returns or creates the internal API client for server communication.
+ ///
+ /// Client selection priority:
+ /// 1. Mock API client — when `UserDefaults` key
+ /// `com.microsoft.identity.credentialmanagement.useMockAPI` is `true`.
+ /// 2. Default (`CredentialManagementServerNetworkClient`) — MSIDHttpRequest-backed URLSession transport.
+ ///
+ /// The mock switch is evaluated on every call so toggling UserDefaults at runtime
+ /// takes effect on the next API call (the cached client is invalidated when the
+ /// environment changes).
+ internal func getAPIClient() -> Result
+ {
+ let useMock = CredentialManagementEnvironment.isMockAPIEnabled
+
+ // Invalidate cached client if mock state changed
+ if let existing = apiClient
+ {
+ let cachedIsMock = existing is CredentialManagementMockNetworkClient
+ if cachedIsMock == useMock
+ {
+ return .success(existing)
+ }
+ // Mock state flipped — discard cached client
+ self.apiClient = nil
+ }
+
+ // Mock API takes precedence — no config validation needed
+ if useMock
+ {
+ let mockClient = CredentialManagementMockNetworkClient()
+ self.apiClient = mockClient
+ return .success(mockClient)
+ }
+
+ guard let tenantSubdomain = config.tenantSubdomain,
+ let baseURL = URL(string: "https://\(tenantSubdomain).ciamlogin.com") else
+ {
+ return .failure(MSALNativeCredentialManagementError(
+ type: .invalidConfiguration,
+ message: "tenantSubdomain must be set on MSALNativeCredentialManagementConfig."
+ ))
+ }
+
+ let requestSerializer = CredentialManagementRequestSerializer(
+ urlResolver: CredentialManagementURLResolver(baseURL: baseURL)
+ )
+
+ let client = CredentialManagementServerNetworkClient(
+ requestSerializer: requestSerializer,
+ requestInterceptor: config.requestInterceptor
+ )
+
+ self.apiClient = client
+ return .success(client)
+ }
+
+ // MARK: - Challenge Handling
+
+ internal func submitRegistrationChallenge(
+ code: String,
+ continuationToken: String,
+ correlationId: UUID
+ ) async -> Result
+ {
+ guard !code.isEmpty else
+ {
+ return .failure(MSALNativeCredentialManagementError(
+ type: .invalidInput,
+ message: "Verification code cannot be empty.",
+ correlationId: correlationId
+ ))
+ }
+
+ // Acquire a fresh token for the activation call
+ let tokenResult = await acquireTokenAsync(correlationId: correlationId)
+ guard case .success(let accessToken) = tokenResult else
+ {
+ return .failure({ if case .failure(let e) = tokenResult { return e }; fatalError("Unreachable") }())
+ }
+
+ let clientResult = getAPIClient()
+ guard case .success(let apiClientInstance) = clientResult else
+ {
+ if case .failure(let error) = clientResult { return .failure(error) }
+ fatalError("Unreachable")
+ }
+
+ let result = await apiClientInstance.activateEnrollment(
+ params: OTPActivationParams(continuationToken: continuationToken, code: code),
+ accessToken: accessToken,
+ correlationId: correlationId
+ )
+
+ switch result
+ {
+ case .success(let method):
+ self.pendingEnrollmentType = nil
+ return .success(method)
+ case .failure(let error):
+ return .failure(error)
+ }
+ }
+
+ internal func resendRegistrationChallenge(
+ continuationToken: String,
+ correlationId: UUID
+ ) async -> Result
+ {
+ // Acquire token for the re-send call
+ let tokenResult = await acquireTokenAsync(correlationId: correlationId)
+ guard case .success(let accessToken) = tokenResult else
+ {
+ return .failure({ if case .failure(let e) = tokenResult { return e }; fatalError("Unreachable") }())
+ }
+
+ let clientResult = getAPIClient()
+ guard case .success(let apiClientInstance) = clientResult else
+ {
+ if case .failure(let error) = clientResult { return .failure(error) }
+ fatalError("Unreachable")
+ }
+
+ // Re-enroll to get a new challenge (server re-sends OOB code)
+ guard let pendingType = pendingEnrollmentType else
+ {
+ return .failure(MSALNativeCredentialManagementError(
+ type: .generalError,
+ message: "No pending enrollment type found for resend.",
+ correlationId: correlationId
+ ))
+ }
+
+ // For resend, we use the same enrollment type but the server uses
+ // the continuationToken to identify the pending session
+ let enrollmentParams: EnrollmentParams
+ switch pendingType
+ {
+ case .phone:
+ enrollmentParams = PhoneEnrollmentParams(phoneNumber: "")
+ case .password:
+ enrollmentParams = PasswordEnrollmentParams(password: "")
+ default:
+ return .failure(MSALNativeCredentialManagementError(
+ type: .generalError,
+ message: "Resend not supported for type: \(pendingType.rawValue)",
+ correlationId: correlationId
+ ))
+ }
+
+ let result = await apiClientInstance.beginEnrollment(
+ params: enrollmentParams,
+ accessToken: accessToken,
+ correlationId: correlationId
+ )
+
+ switch result
+ {
+ case .success(let response):
+ switch response
+ {
+ case .challengeRequired(let challengeInfo):
+ let newState = MSALCredentialMethodChallengeState(
+ sentTo: challengeInfo.sentTo,
+ channelType: challengeInfo.channelType,
+ codeLength: challengeInfo.codeLength,
+ continuationToken: challengeInfo.continuationToken,
+ client: self,
+ correlationId: correlationId
+ )
+ return .success(newState)
+
+ case .completed(_):
+ // Unlikely on resend, but handle gracefully
+ let state = MSALCredentialMethodChallengeState(
+ sentTo: nil,
+ channelType: nil,
+ codeLength: nil,
+ continuationToken: continuationToken,
+ client: self,
+ correlationId: correlationId
+ )
+ return .success(state)
+
+ case .passkeyCreationRequired:
+ return .failure(MSALNativeCredentialManagementError(
+ type: .generalError,
+ message: "Unexpected passkey creation response on resend.",
+ correlationId: correlationId
+ ))
+ }
+
+ case .failure(let error):
+ return .failure(error)
+ }
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/MSIDLogger+CredentialManagement.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/MSIDLogger+CredentialManagement.swift
new file mode 100644
index 0000000000..2f8435c46c
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/MSIDLogger+CredentialManagement.swift
@@ -0,0 +1,105 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+import MSAL
+@_implementationOnly import MSAL_Private
+
+/// Convenience extension for logging in the credential management module.
+///
+/// Provides a simple `log(level:correlationId:message:)` API that delegates to
+/// `MSIDLogger` from IdentityCore. MSAL is the base module — we use its
+/// logging infrastructure directly, no wrappers.
+///
+/// **Privacy:** This extension NEVER logs tokens, phone numbers, email addresses,
+/// credential IDs, continuation tokens, or full HAL payloads.
+extension MSIDLogger
+{
+ /// Log a non-PII message using `MSALLogLevel` (public SDK enum).
+ func log(
+ level: MSALLogLevel,
+ correlationId: UUID? = nil,
+ message: String,
+ filename: String = #fileID,
+ lineNumber: Int = #line,
+ function: String = #function
+ )
+ {
+ self.log(
+ with: msidLogLevel(from: level),
+ context: nil,
+ correlationId: correlationId,
+ containsPII: false,
+ filename: filename,
+ lineNumber: UInt(lineNumber),
+ function: function,
+ format: "[CredMgmt] %@",
+ formatArgs: getVaList([message])
+ )
+ }
+
+ /// Log a PII message (only delivered when masking allows it).
+ func logPII(
+ level: MSALLogLevel,
+ correlationId: UUID? = nil,
+ message: String,
+ filename: String = #fileID,
+ lineNumber: Int = #line,
+ function: String = #function
+ )
+ {
+ self.log(
+ with: msidLogLevel(from: level),
+ context: nil,
+ correlationId: correlationId,
+ containsPII: true,
+ filename: filename,
+ lineNumber: UInt(lineNumber),
+ function: function,
+ format: "[CredMgmt] %@",
+ formatArgs: getVaList([message])
+ )
+ }
+
+ private func msidLogLevel(from msalLevel: MSALLogLevel) -> MSIDLogLevel
+ {
+ switch msalLevel
+ {
+ case .error:
+ return .error
+ case .warning:
+ return .warning
+ case .info:
+ return .info
+ case .verbose:
+ return .verbose
+ case .last:
+ return .last
+ case .nothing:
+ return .nothing
+ @unknown default:
+ return .info
+ }
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/credential_method/MSALCredentialMethod.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/credential_method/MSALCredentialMethod.swift
new file mode 100644
index 0000000000..1c74e79aea
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/credential_method/MSALCredentialMethod.swift
@@ -0,0 +1,73 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+/// Internal abstract base class for all credential methods.
+///
+/// Each credential type (passkey, phone, password, etc.) is represented
+/// by a concrete subclass. New credential types can be added by subclassing
+/// without modifying existing classes (Open/Closed Principle).
+///
+/// **Do not instantiate `MSALCredentialMethod` directly** — use a concrete subclass
+/// such as `MSALPasskeyCredentialMethod`, `MSALPhoneCredentialMethod`, or
+/// `MSALPasswordCredentialMethod`.
+@objcMembers
+public class MSALCredentialMethod: NSObject, MSALCredentialMethodProtocol {
+
+ /// Unique identifier of the credential method (set by the server).
+ public internal(set) var id: String
+
+ /// The type identifier (e.g., `.passkey`, `.phone`, `.password`).
+ public let credentialType: MSALCredentialType
+
+ /// Display-friendly name or hint (e.g., masked phone "+1 ***-***-1234").
+ public internal(set) var displayName: String?
+
+ /// Timestamp of when this method was registered (set by the server).
+ public internal(set) var createdAt: Date?
+
+ /// Internal initializer — prevents external consumers from creating
+ /// `MSALCredentialMethod` directly. Only subclasses within this module
+ /// can call this via `super.init(...)`.
+ ///
+ /// - Parameters:
+ /// - id: Unique identifier from the server.
+ /// - credentialType: The type for this credential.
+ /// - displayName: A user-facing display name or hint.
+ /// - createdAt: The creation timestamp.
+ internal init(
+ id: String,
+ credentialType: MSALCredentialType,
+ displayName: String?,
+ createdAt: Date?
+ )
+ {
+ self.id = id
+ self.credentialType = credentialType
+ self.displayName = displayName
+ self.createdAt = createdAt
+ super.init()
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/credential_method/passkey/MSALNativeCredentialMethodsClient+RegisterPasskey.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/credential_method/passkey/MSALNativeCredentialMethodsClient+RegisterPasskey.swift
new file mode 100644
index 0000000000..be34a70c05
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/credential_method/passkey/MSALNativeCredentialMethodsClient+RegisterPasskey.swift
@@ -0,0 +1,189 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+import MSAL
+import AuthenticationServices
+@_implementationOnly import MSAL_Private
+
+extension MSALNativeCredentialMethodsClient
+{
+ /// Performs the full passkey registration flow:
+ /// 1. Acquires an access token.
+ /// 2. Calls beginEnrollment to get WebAuthn creation options from the server.
+ /// 3. Invokes the platform authenticator via ASAuthorization.
+ /// 4. Calls activateEnrollment with the attestation.
+ /// 5. Returns the registered credential method.
+ internal func performRegisterPasskey(
+ params: MSALRegisterPasskeyParams
+ ) async -> Result
+ {
+ let correlationId = params.correlationId ?? UUID()
+
+ MSIDLogger.shared().log(level: .info, correlationId: correlationId, message: "performRegisterPasskey: starting")
+
+ // Step 1: Acquire access token
+ let tokenResult = await acquireTokenAsync(correlationId: correlationId)
+ guard case .success(let accessToken) = tokenResult else
+ {
+ return .failure({ if case .failure(let e) = tokenResult { return e }; fatalError("Unreachable") }())
+ }
+
+ // Step 2: Begin enrollment to get creation options from server
+ switch getAPIClient()
+ {
+ case .failure(let error):
+ return .failure(error)
+ case .success(let client):
+ let enrollResult = await client.beginEnrollment(
+ params: PasskeyEnrollmentParams(),
+ accessToken: accessToken,
+ correlationId: correlationId
+ )
+
+ guard case .success(let response) = enrollResult else
+ {
+ if case .failure(let resultError) = enrollResult { return .failure(resultError) }
+ fatalError("Unreachable")
+ }
+
+ // Expect passkey creation options from the server
+ guard case .passkeyCreationRequired(let passkeyInfo) = response else
+ {
+ if case .completed(let method) = response
+ {
+ return .success(.completed(method))
+ }
+ return .failure(MSALNativeCredentialManagementError(
+ type: .generalError,
+ message: "Server did not return passkey creation options.",
+ correlationId: correlationId
+ ))
+ }
+
+ // Parse creation options from server response
+ let creationOptions = parseCreationOptions(from: passkeyInfo.publicKey)
+
+ // Step 3: Invoke platform authenticator
+ let handler = MSALPasskeyAuthorizationHandler(anchor: params.presentationAnchor)
+ let attestation: MSALPasskeyAttestation
+ do
+ {
+ attestation = try await handler.performRegistration(options: creationOptions)
+ }
+ catch
+ {
+ let credError = MSALNativeCredentialManagementError(
+ type: .generalError,
+ message: "Passkey creation was cancelled or failed.",
+ correlationId: correlationId,
+ underlyingError: error
+ )
+ return .failure(credError)
+ }
+
+ // Step 4: Submit attestation to server via activate
+ let activateResult = await client.activateEnrollment(
+ params: PasskeyActivationParams(
+ continuationToken: passkeyInfo.continuationToken,
+ displayName: params.displayName ?? "Passkey",
+ credentialId: attestation.credentialId,
+ attestationObject: attestation.rawAttestationObject,
+ clientDataJSON: attestation.rawClientDataJSON
+ ),
+ accessToken: accessToken,
+ correlationId: correlationId
+ )
+
+ switch activateResult
+ {
+ case .success(let method):
+ MSIDLogger.shared().log(level: .info, correlationId: correlationId, message: "performRegisterPasskey: completed")
+ return .success(.completed(method))
+ case .failure(let error):
+ return .failure(error)
+ }
+ }
+ }
+
+ // MARK: - Private Helpers
+
+ /// Parses the server-provided publicKey object into local creation options.
+ private func parseCreationOptions(from publicKeyDict: [String: Any]) -> MSALPasskeyCreationOptions
+ {
+ let challenge: Data
+ if let challengeString = publicKeyDict["challenge"] as? String,
+ let decoded = Data(base64Encoded: challengeString)
+ {
+ challenge = decoded
+ }
+ else
+ {
+ var bytes = [UInt8](repeating: 0, count: 32)
+ _ = SecRandomCopyBytes(kSecRandomDefault, bytes.count, &bytes)
+ challenge = Data(bytes)
+ }
+
+ let userId: Data
+ if let userDict = publicKeyDict["user"] as? [String: Any],
+ let idString = userDict["id"] as? String,
+ let decoded = Data(base64Encoded: idString)
+ {
+ userId = decoded
+ }
+ else
+ {
+ userId = Data(UUID().uuidString.utf8)
+ }
+
+ let userName: String
+ if let userDict = publicKeyDict["user"] as? [String: Any],
+ let name = userDict["name"] as? String
+ {
+ userName = name
+ }
+ else
+ {
+ userName = "user"
+ }
+
+ let rpId: String
+ if let rpDict = publicKeyDict["rp"] as? [String: Any],
+ let id = rpDict["id"] as? String
+ {
+ rpId = id
+ }
+ else
+ {
+ rpId = "login.microsoft.com"
+ }
+
+ return MSALPasskeyCreationOptions(
+ challenge: challenge,
+ userId: userId,
+ userName: userName,
+ relyingPartyIdentifier: rpId
+ )
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/credential_method/passkey/MSALPasskeyAuthorizationHandler.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/credential_method/passkey/MSALPasskeyAuthorizationHandler.swift
new file mode 100644
index 0000000000..a1fdf519fe
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/credential_method/passkey/MSALPasskeyAuthorizationHandler.swift
@@ -0,0 +1,145 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+import AuthenticationServices
+#if os(macOS)
+import AppKit
+#else
+import UIKit
+#endif
+
+// MARK: - Internal Types
+
+/// WebAuthn creation options returned by the server for passkey registration.
+internal struct MSALPasskeyCreationOptions
+{
+ let challenge: Data
+ let userId: Data
+ let userName: String
+ let relyingPartyIdentifier: String
+}
+
+/// Attestation data from the platform authenticator after passkey creation.
+internal struct MSALPasskeyAttestation
+{
+ let credentialId: Data
+ let rawAttestationObject: Data
+ let rawClientDataJSON: Data
+}
+
+// MARK: - Internal Authorization Handler
+
+/// Handles the ASAuthorization flow for passkey creation.
+///
+/// This class encapsulates all platform authenticator interactions so that
+/// developers never need to work with `ASAuthorizationController` directly.
+internal class MSALPasskeyAuthorizationHandler: NSObject,
+ ASAuthorizationControllerDelegate,
+ ASAuthorizationControllerPresentationContextProviding
+{
+ private let anchor: ASPresentationAnchor
+ private var continuation: CheckedContinuation?
+
+ init(anchor: ASPresentationAnchor)
+ {
+ self.anchor = anchor
+ super.init()
+ }
+
+ /// Performs the platform passkey creation and returns the attestation.
+ func performRegistration(
+ options: MSALPasskeyCreationOptions
+ ) async throws -> MSALPasskeyAttestation
+ {
+ return try await withCheckedThrowingContinuation
+ { continuation in
+ self.continuation = continuation
+
+ let provider = ASAuthorizationPlatformPublicKeyCredentialProvider(
+ relyingPartyIdentifier: options.relyingPartyIdentifier
+ )
+
+ let request = provider.createCredentialRegistrationRequest(
+ challenge: options.challenge,
+ name: options.userName,
+ userID: options.userId
+ )
+
+ let controller = ASAuthorizationController(authorizationRequests: [request])
+ controller.delegate = self
+ controller.presentationContextProvider = self
+ DispatchQueue.main.async
+ {
+ controller.performRequests()
+ }
+ }
+ }
+
+ // MARK: - ASAuthorizationControllerPresentationContextProviding
+
+ func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor
+ {
+ return anchor
+ }
+
+ // MARK: - ASAuthorizationControllerDelegate
+
+ func authorizationController(
+ controller: ASAuthorizationController,
+ didCompleteWithAuthorization authorization: ASAuthorization
+ )
+ {
+ guard let credential = authorization.credential
+ as? ASAuthorizationPlatformPublicKeyCredentialRegistration
+ else
+ {
+ let error = NSError(
+ domain: "MSALPasskeyError",
+ code: -1,
+ userInfo: [NSLocalizedDescriptionKey: "Unexpected credential type returned."]
+ )
+ continuation?.resume(throwing: error)
+ continuation = nil
+ return
+ }
+
+ let attestation = MSALPasskeyAttestation(
+ credentialId: credential.credentialID,
+ rawAttestationObject: credential.rawAttestationObject ?? Data(),
+ rawClientDataJSON: credential.rawClientDataJSON
+ )
+ continuation?.resume(returning: attestation)
+ continuation = nil
+ }
+
+ func authorizationController(
+ controller: ASAuthorizationController,
+ didCompleteWithError error: Error
+ )
+ {
+ continuation?.resume(throwing: error)
+ continuation = nil
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/credential_method/password/MSALNativeCredentialMethodsClient+RegisterPassword.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/credential_method/password/MSALNativeCredentialMethodsClient+RegisterPassword.swift
new file mode 100644
index 0000000000..9171850073
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/credential_method/password/MSALNativeCredentialMethodsClient+RegisterPassword.swift
@@ -0,0 +1,92 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+import MSAL
+@_implementationOnly import MSAL_Private
+extension MSALNativeCredentialMethodsClient
+{
+ internal func performRegisterPassword(
+ params: MSALRegisterPasswordParams
+ ) async -> Result
+ {
+ let correlationId = params.correlationId ?? UUID()
+
+ MSIDLogger.shared().log(level: .info, correlationId: correlationId, message: "performRegisterPassword: starting")
+
+ // Acquire access token
+ let tokenResult = await acquireTokenAsync(correlationId: correlationId)
+ guard case .success(let accessToken) = tokenResult else
+ {
+ return .failure({ if case .failure(let e) = tokenResult { return e }; fatalError("Unreachable") }())
+ }
+
+ switch getAPIClient()
+ {
+ case .failure(let error):
+ return .failure(error)
+ case .success(let client):
+ let enrollResult = await client.beginEnrollment(
+ params: PasswordEnrollmentParams(password: params.password),
+ accessToken: accessToken,
+ correlationId: correlationId
+ )
+
+ switch enrollResult
+ {
+ case .success(let response):
+ switch response
+ {
+ case .completed(let method):
+ MSIDLogger.shared().log(level: .info, correlationId: correlationId, message: "performRegisterPassword: completed")
+ return .success(.completed(method))
+
+ case .challengeRequired(let challengeInfo):
+ // Unlikely for password but handle gracefully
+ self.pendingEnrollmentType = .password
+
+ let challengeState = MSALCredentialMethodChallengeState(
+ sentTo: challengeInfo.sentTo,
+ channelType: challengeInfo.channelType,
+ codeLength: challengeInfo.codeLength,
+ continuationToken: challengeInfo.continuationToken,
+ client: self,
+ correlationId: correlationId
+ )
+ return .success(.challengeRequired(challengeState))
+
+ case .passkeyCreationRequired:
+ return .failure(MSALNativeCredentialManagementError(
+ type: .generalError,
+ message: "Unexpected passkey creation response for password enrollment.",
+ correlationId: correlationId
+ ))
+ }
+
+ case .failure(let error):
+ return .failure(error)
+ }
+ }
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/credential_method/phone/MSALNativeCredentialMethodsClient+RegisterPhone.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/credential_method/phone/MSALNativeCredentialMethodsClient+RegisterPhone.swift
new file mode 100644
index 0000000000..0e12551fcf
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/credential_method/phone/MSALNativeCredentialMethodsClient+RegisterPhone.swift
@@ -0,0 +1,97 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+import MSAL
+@_implementationOnly import MSAL_Private
+extension MSALNativeCredentialMethodsClient
+{
+ internal func performRegisterPhoneNumber(
+ params: MSALRegisterPhoneNumberParams
+ ) async -> Result
+ {
+ let correlationId = params.correlationId ?? UUID()
+
+ MSIDLogger.shared().log(level: .info, correlationId: correlationId, message: "performRegisterPhoneNumber: starting")
+
+ // Acquire access token
+ let tokenResult = await acquireTokenAsync(correlationId: correlationId)
+ guard case .success(let accessToken) = tokenResult else
+ {
+ return .failure({ if case .failure(let e) = tokenResult { return e }; fatalError("Unreachable") }())
+ }
+
+ switch getAPIClient()
+ {
+ case .failure(let error):
+ return .failure(error)
+ case .success(let client):
+ let enrollResult = await client.beginEnrollment(
+ params: PhoneEnrollmentParams(phoneNumber: params.phoneNumber),
+ accessToken: accessToken,
+ correlationId: correlationId
+ )
+
+ switch enrollResult
+ {
+ case .success(let response):
+ switch response
+ {
+ case .completed(let method):
+ MSIDLogger.shared().log(level: .info, correlationId: correlationId, message: "performRegisterPhoneNumber: completed immediately")
+ return .success(.completed(method))
+
+ case .challengeRequired(let challengeInfo):
+ self.pendingEnrollmentType = .phone
+
+ let challengeState = MSALCredentialMethodChallengeState(
+ sentTo: challengeInfo.sentTo ?? params.phoneNumber,
+ channelType: challengeInfo.channelType ?? "sms",
+ codeLength: challengeInfo.codeLength ?? 6,
+ continuationToken: challengeInfo.continuationToken,
+ client: self,
+ correlationId: correlationId
+ )
+
+ MSIDLogger.shared().log(
+ level: .info,
+ correlationId: correlationId,
+ message: "performRegisterPhoneNumber: challenge sent"
+ )
+ return .success(.challengeRequired(challengeState))
+
+ case .passkeyCreationRequired:
+ return .failure(MSALNativeCredentialManagementError(
+ type: .generalError,
+ message: "Unexpected passkey creation response for phone enrollment.",
+ correlationId: correlationId
+ ))
+ }
+
+ case .failure(let error):
+ return .failure(error)
+ }
+ }
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/CredentialManagementNetworkClientProtocol.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/CredentialManagementNetworkClientProtocol.swift
new file mode 100644
index 0000000000..32c089a4b5
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/CredentialManagementNetworkClientProtocol.swift
@@ -0,0 +1,71 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+import MSAL
+
+// MARK: - Protocol
+
+/// Internal protocol that unifies the server-backed client and the mock client
+/// behind a single HAL-free interface.
+///
+/// Implementations own the transport details (HAL parsing, link tracking, serialization, etc.)
+/// and expose only typed domain models to callers.
+internal protocol CredentialManagementNetworkClientProtocol
+{
+ /// List all credential methods for the authenticated user.
+ func listMethods(
+ accessToken: String,
+ correlationId: UUID
+ ) async -> Result<[any MSALCredentialMethodProtocol], MSALNativeCredentialManagementError>
+
+ /// Begin enrollment of a new credential method.
+ ///
+ /// Returns a typed `EnrollmentBeginResponse` that tells the caller whether
+ /// enrollment completed, a challenge is required, or passkey creation options are available.
+ func beginEnrollment(
+ params: EnrollmentParams,
+ accessToken: String,
+ correlationId: UUID
+ ) async -> Result
+
+ /// Activate (complete) an enrollment that required a second step.
+ ///
+ /// The `continuationToken` identifies the pending enrollment. The implementation
+ /// resolves any internal resource context (e.g., HAL links) from its in-memory store.
+ func activateEnrollment(
+ params: ActivationParams,
+ accessToken: String,
+ correlationId: UUID
+ ) async -> Result
+
+ /// Delete a credential method.
+ func deleteMethod(
+ type: MSALCredentialType,
+ methodId: String,
+ accessToken: String,
+ correlationId: UUID
+ ) async -> Result
+}
+
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/mock/CredentialManagementEnvironment.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/mock/CredentialManagementEnvironment.swift
new file mode 100644
index 0000000000..507960dc4b
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/mock/CredentialManagementEnvironment.swift
@@ -0,0 +1,70 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+/// Internal environment switch for credential management.
+///
+/// Reads UserDefaults to determine whether to route API calls to the real server
+/// or return mock responses. This mechanism is entirely internal and is NOT exposed
+/// in any public API.
+///
+/// ## UserDefaults Keys
+///
+/// - `com.microsoft.identity.credentialmanagement.useMockAPI` (Bool):
+/// When `true`, all credential management API calls will be routed to the mock client.
+/// Default is `false` (real server).
+///
+/// - `com.microsoft.identity.credentialmanagement.mockDelaySeconds` (Double):
+/// Simulated network delay in seconds when using mock API. Default is 0.5.
+///
+/// ## Usage (for internal testing / debug builds only)
+///
+/// ```swift
+/// // Enable mock API (e.g., in a debug settings screen or launch argument):
+/// UserDefaults.standard.set(true, forKey: "com.microsoft.identity.credentialmanagement.useMockAPI")
+///
+/// // Optionally configure simulated delay:
+/// UserDefaults.standard.set(1.0, forKey: "com.microsoft.identity.credentialmanagement.mockDelaySeconds")
+///
+/// // Disable mock API (back to real server):
+/// UserDefaults.standard.set(false, forKey: "com.microsoft.identity.credentialmanagement.useMockAPI")
+/// ```
+///
+/// ## Launch Arguments
+///
+/// You can also pass the flag as a launch argument in Xcode:
+/// `-com.microsoft.identity.credentialmanagement.useMockAPI YES`
+///
+internal enum CredentialManagementEnvironment
+{
+ /// UserDefaults key that controls mock/server routing.
+ static let useMockAPIKey = "com.microsoft.identity.credentialmanagement.useMockAPI"
+
+ /// Returns `true` when mock API mode is enabled via UserDefaults.
+ static var isMockAPIEnabled: Bool
+ {
+ return UserDefaults.standard.bool(forKey: useMockAPIKey)
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/mock/CredentialManagementMockNetworkClient.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/mock/CredentialManagementMockNetworkClient.swift
new file mode 100644
index 0000000000..e72109f08b
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/mock/CredentialManagementMockNetworkClient.swift
@@ -0,0 +1,277 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+import MSAL
+@_implementationOnly import MSAL_Private
+
+/// In-memory mock implementation of `CredentialManagementNetworkClientProtocol`.
+///
+/// Operates entirely on real typed model objects — no HAL logic.
+/// Stores methods in a dictionary keyed by ID for O(1) lookup/delete.
+///
+/// Activated via UserDefaults key `com.microsoft.identity.credentialmanagement.useMockAPI`.
+internal final class CredentialManagementMockNetworkClient: CredentialManagementNetworkClientProtocol
+{
+ /// In-memory store of credential methods keyed by `id`.
+ private var methodStore: [String: any MSALCredentialMethodProtocol]
+
+ /// Tracks pending enrollments by continuationToken for activate step.
+ private var pendingEnrollments: [String: PendingEnrollment]
+
+ private struct PendingEnrollment
+ {
+ let type: MSALCredentialType
+ let phoneNumber: String?
+ }
+
+ private var simulatedDelay: TimeInterval
+ {
+ let delay = UserDefaults.standard.double(
+ forKey: "com.microsoft.identity.credentialmanagement.mockDelaySeconds"
+ )
+ return delay > 0 ? delay : 0.5
+ }
+
+ init()
+ {
+ self.methodStore = [:]
+ self.pendingEnrollments = [:]
+ Self.seedMethods().forEach { self.methodStore[$0.id] = $0 }
+
+ MSIDLogger.shared().log(
+ level: .warning,
+ correlationId: UUID(),
+ message: "⚠️ Mock network client is active. All credential management calls will return simulated data."
+ )
+ }
+
+ // MARK: - List Methods
+
+ func listMethods(
+ accessToken: String,
+ correlationId: UUID
+ ) async -> Result<[any MSALCredentialMethodProtocol], MSALNativeCredentialManagementError>
+ {
+ await simulateNetworkDelay()
+
+ MSIDLogger.shared().log(
+ level: .info,
+ correlationId: correlationId,
+ message: "[Mock] listMethods — returning \(methodStore.count) methods"
+ )
+
+ return .success(Array(methodStore.values))
+ }
+
+ // MARK: - Begin Enrollment
+
+ func beginEnrollment(
+ params: EnrollmentParams,
+ accessToken: String,
+ correlationId: UUID
+ ) async -> Result
+ {
+ await simulateNetworkDelay()
+
+ MSIDLogger.shared().log(
+ level: .info,
+ correlationId: correlationId,
+ message: "[Mock] beginEnrollment for params=\(params)"
+ )
+
+ switch params
+ {
+ case let phoneParams as PhoneEnrollmentParams:
+ let token = "mock-ct-\(UUID().uuidString.prefix(8))"
+ pendingEnrollments[token] = PendingEnrollment(type: .phone, phoneNumber: phoneParams.phoneNumber)
+
+ let maskedPhone = maskPhone(phoneParams.phoneNumber)
+ let challengeInfo = EnrollmentChallengeInfo(
+ sentTo: maskedPhone,
+ channelType: "sms",
+ codeLength: 6,
+ continuationToken: token
+ )
+ return .success(.challengeRequired(challengeInfo))
+
+ case is PasswordEnrollmentParams:
+ // Password completes immediately
+ let newId = "mock-\(UUID().uuidString.prefix(8))"
+ let method = MSALPasswordCredentialMethod(id: newId, createdAt: Date())
+ methodStore[newId] = method
+ return .success(.completed(method))
+
+ case is PasskeyEnrollmentParams:
+ // Passkey — return creation options
+ let token = "mock-ct-\(UUID().uuidString.prefix(8))"
+ pendingEnrollments[token] = PendingEnrollment(type: .passkey, phoneNumber: nil)
+
+ let publicKey: [String: Any] = [
+ "challenge": Data("mock-challenge-\(UUID().uuidString)".utf8).base64EncodedString(),
+ "rp": ["id": "login.microsoft.com", "name": "Microsoft"],
+ "user": [
+ "id": Data("mock-user-id".utf8).base64EncodedString(),
+ "name": "user@contoso.com",
+ "displayName": "Mock User"
+ ]
+ ]
+
+ let creationInfo = PasskeyCreationInfo(
+ publicKey: publicKey,
+ continuationToken: token
+ )
+ return .success(.passkeyCreationRequired(creationInfo))
+
+ default:
+ return .failure(MSALNativeCredentialManagementError(
+ type: .generalError,
+ message: "Unsupported enrollment params type.",
+ correlationId: correlationId
+ ))
+ }
+ }
+
+ // MARK: - Activate Enrollment
+
+ func activateEnrollment(
+ params: ActivationParams,
+ accessToken: String,
+ correlationId: UUID
+ ) async -> Result
+ {
+ await simulateNetworkDelay()
+
+ MSIDLogger.shared().log(
+ level: .info,
+ correlationId: correlationId,
+ message: "[Mock] activateEnrollment"
+ )
+
+ guard let pending = pendingEnrollments.removeValue(forKey: params.continuationToken) else
+ {
+ return .failure(MSALNativeCredentialManagementError(
+ type: .generalError,
+ message: "No pending enrollment found for the given continuation token.",
+ correlationId: correlationId
+ ))
+ }
+
+ let newId = "mock-\(UUID().uuidString.prefix(8))"
+
+ let method: any MSALCredentialMethodProtocol
+ switch pending.type
+ {
+ case .phone:
+ method = MSALPhoneCredentialMethod(
+ id: newId,
+ createdAt: Date(),
+ phoneNumber: pending.phoneNumber ?? "+1 (555) 000-0000"
+ )
+ default:
+ let displayName: String
+ if let passkeyParams = params as? PasskeyActivationParams
+ {
+ displayName = passkeyParams.displayName
+ }
+ else
+ {
+ displayName = "Passkey"
+ }
+ method = MSALPasskeyCredentialMethod(
+ id: newId,
+ displayName: displayName,
+ createdAt: Date(),
+ credentialID: "mock-cred-\(UUID().uuidString.prefix(8))",
+ aaguid: nil
+ )
+ }
+
+ methodStore[newId] = method
+ return .success(method)
+ }
+
+ // MARK: - Delete Method
+
+ func deleteMethod(
+ type: MSALCredentialType,
+ methodId: String,
+ accessToken: String,
+ correlationId: UUID
+ ) async -> Result
+ {
+ await simulateNetworkDelay()
+
+ MSIDLogger.shared().log(
+ level: .info,
+ correlationId: correlationId,
+ message: "[Mock] deleteMethod id=\(methodId)"
+ )
+
+ methodStore.removeValue(forKey: methodId)
+ return .success(())
+ }
+
+ // MARK: - Private
+
+ private static func seedMethods() -> [any MSALCredentialMethodProtocol]
+ {
+ [
+ MSALPasskeyCredentialMethod(
+ id: "mock-passkey-001",
+ displayName: "Mock Passkey",
+ createdAt: nil,
+ credentialID: "mock-credential-id-abc",
+ aaguid: "00000000-0000-0000-0000-000000000001"
+ ),
+ MSALPhoneCredentialMethod(
+ id: "mock-phone-001",
+ createdAt: nil,
+ phoneNumber: "+1 (555) 123-4567"
+ ),
+ MSALPasswordCredentialMethod(
+ id: "mock-password-001",
+ createdAt: nil
+ )
+ ]
+ }
+
+ private func maskPhone(_ phone: String?) -> String
+ {
+ guard let phone = phone, phone.count > 4 else
+ {
+ return phone ?? "+1 (555) ***-0000"
+ }
+ return "••• \(String(phone.suffix(4)))"
+ }
+
+ private func simulateNetworkDelay() async
+ {
+ let delay = simulatedDelay
+ if delay > 0
+ {
+ try? await Task.sleep(nanoseconds: UInt64(delay * 1_000_000_000))
+ }
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/CredentialManagementErrorHandler.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/CredentialManagementErrorHandler.swift
new file mode 100644
index 0000000000..899d8ac4a3
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/CredentialManagementErrorHandler.swift
@@ -0,0 +1,123 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+@_implementationOnly import MSAL_Private
+
+/// Implements `MSIDHttpRequestErrorHandling` for credential management API errors.
+///
+/// Maps HTTP error status codes to `MSALNativeCredentialManagementError` instances
+/// and invokes the completion block with the appropriate typed error.
+internal final class CredentialManagementErrorHandler: NSObject, MSIDHttpRequestErrorHandling
+{
+ private let correlationId: UUID
+
+ init(correlationId: UUID)
+ {
+ self.correlationId = correlationId
+ }
+
+ func handleError(
+ _ error: Error?,
+ httpResponse: HTTPURLResponse?,
+ data: Data?,
+ httpRequest: MSIDHttpRequestProtocol?,
+ responseSerializer: MSIDResponseSerialization?,
+ externalSSOContext ssoContext: MSIDExternalSSOContext?,
+ context: MSIDRequestContext?,
+ completionBlock: MSIDHttpRequestDidCompleteBlock?
+ )
+ {
+ let statusCode = httpResponse?.statusCode ?? 0
+ let mappedError: MSALNativeCredentialManagementError
+
+ switch statusCode
+ {
+ case 401:
+ mappedError = MSALNativeCredentialManagementError(
+ type: .unauthorized,
+ message: "Server returned 401 Unauthorized. The access token may be expired or invalid.",
+ correlationId: correlationId
+ )
+
+ case 403:
+ mappedError = MSALNativeCredentialManagementError(
+ type: .forbidden,
+ message: "Server returned 403 Forbidden. The user may lack the required permissions or recent MFA.",
+ correlationId: correlationId
+ )
+
+ case 404:
+ mappedError = MSALNativeCredentialManagementError(
+ type: .notFound,
+ message: "Server returned 404 Not Found. The credential method does not exist.",
+ correlationId: correlationId
+ )
+
+ case 409:
+ mappedError = MSALNativeCredentialManagementError(
+ type: .conflict,
+ message: "Server returned 409 Conflict. The credential method may already be registered.",
+ correlationId: correlationId
+ )
+
+ case 429:
+ mappedError = MSALNativeCredentialManagementError(
+ type: .networkError,
+ message: "Server returned 429 Too Many Requests. Please try again later.",
+ correlationId: correlationId
+ )
+
+ default:
+ if let error = error
+ {
+ mappedError = MSALNativeCredentialManagementError(
+ type: .networkError,
+ message: "Network request failed.",
+ correlationId: correlationId,
+ underlyingError: error
+ )
+ }
+ else
+ {
+ let message: String
+ if (500...599).contains(statusCode)
+ {
+ message = "Server returned \(statusCode). A server-side error occurred."
+ }
+ else
+ {
+ message = "Server returned unexpected status code \(statusCode)."
+ }
+ mappedError = MSALNativeCredentialManagementError(
+ type: .generalError,
+ message: message,
+ correlationId: correlationId
+ )
+ }
+ }
+
+ completionBlock?(nil, mappedError)
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/CredentialManagementInterceptorBridge.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/CredentialManagementInterceptorBridge.swift
new file mode 100644
index 0000000000..4710af3d25
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/CredentialManagementInterceptorBridge.swift
@@ -0,0 +1,49 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+import MSAL
+@_implementationOnly import MSAL_Private
+
+/// Bridges `MSALNativeAuthRequestInterceptor` (Swift protocol from MSAL public API) to
+/// `MSIDHttpRequestInterceptorProtocol` (ObjC protocol used by MSIDHttpRequest in IdentityCore).
+internal final class CredentialManagementInterceptorBridge: NSObject, MSIDHttpRequestInterceptorProtocol
+{
+ private let interceptor: MSALNativeAuthRequestInterceptor
+
+ init(interceptor: MSALNativeAuthRequestInterceptor)
+ {
+ self.interceptor = interceptor
+ }
+
+ func addAdditionalHeaderFields(
+ for requestUrl: URL?,
+ with completionBlock: @escaping MSIDHttpRequestInterceptorAddHeaderCompletionBlock
+ )
+ {
+ interceptor.addAdditionalHeaderFields(requestUrl) { additionalHeaders in
+ completionBlock(additionalHeaders)
+ }
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/CredentialManagementRequestConfigurator.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/CredentialManagementRequestConfigurator.swift
new file mode 100644
index 0000000000..93fe589350
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/CredentialManagementRequestConfigurator.swift
@@ -0,0 +1,89 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+import MSAL
+@_implementationOnly import MSAL_Private
+
+/// Configures an `MSIDHttpRequest` with the credential management serializers,
+/// error handler, and optional interceptor.
+///
+/// Follows the IdentityCore `MSIDHttpRequestConfiguratorProtocol` pattern:
+/// the configurator wires all cross-cutting concerns onto a request before sending.
+internal final class CredentialManagementRequestConfigurator
+{
+ private let requestSerializer: CredentialManagementRequestSerializing
+ private let correlationId: UUID
+ private let requestInterceptor: MSALNativeAuthRequestInterceptor?
+
+ init(
+ requestSerializer: CredentialManagementRequestSerializing,
+ correlationId: UUID,
+ requestInterceptor: MSALNativeAuthRequestInterceptor?
+ )
+ {
+ self.requestSerializer = requestSerializer
+ self.correlationId = correlationId
+ self.requestInterceptor = requestInterceptor
+ }
+
+ /// Configures an `MSIDHttpRequest` from a typed request.
+ /// Returns the configured request or an error if URL validation fails.
+ func configure(
+ _ typedRequest: CredentialManagementRequestProtocol
+ ) -> Result
+ {
+ guard let urlRequest = requestSerializer.serialize(typedRequest) else
+ {
+ return .failure(MSALNativeCredentialManagementError(
+ type: .generalError,
+ message: "URL validation failed: '\(typedRequest.path)' does not belong to the trusted service.",
+ correlationId: typedRequest.correlationId
+ ))
+ }
+
+ let request = MSIDHttpRequest()
+ request.urlRequest = urlRequest
+
+ // Serializers
+ request.responseSerializer = MSIDResponseSerializerAdapter()
+ request.errorResponseSerializer = MSIDResponseSerializerAdapter()
+
+ // Error handler
+ request.errorHandler = CredentialManagementErrorHandler(correlationId: correlationId)
+
+ // Context
+ let context = MSIDBasicContext()
+ context.correlationId = correlationId
+ request.context = context
+
+ // Interceptor
+ if let interceptor = requestInterceptor
+ {
+ request.requestInterceptor = CredentialManagementInterceptorBridge(interceptor: interceptor)
+ }
+
+ return .success(request)
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/CredentialManagementServerNetworkClient.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/CredentialManagementServerNetworkClient.swift
new file mode 100644
index 0000000000..d905db7b0d
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/CredentialManagementServerNetworkClient.swift
@@ -0,0 +1,405 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+import MSAL
+@_implementationOnly import MSAL_Private
+
+/// Server-backed implementation of `CredentialManagementNetworkClientProtocol`.
+///
+/// This layer:
+/// 1. Sends requests through the MSIDHttpRequest pipeline.
+/// 2. Parses HAL responses internally.
+/// 3. Maintains an in-memory relation store that maps `continuationToken` → HAL link context.
+/// 4. Exposes only typed domain models to callers.
+///
+/// HAL concepts (links, embedded resources) never escape this layer.
+internal final class CredentialManagementServerNetworkClient: CredentialManagementNetworkClientProtocol
+{
+ private let requestSerializer: CredentialManagementRequestSerializing
+ private let requestInterceptor: MSALNativeAuthRequestInterceptor?
+
+ /// In-memory relation store: maps continuationToken → activate href.
+ /// This keeps HAL link context hidden from callers.
+ private var activateHrefStore: [String: String] = [:]
+
+ init(requestSerializer: CredentialManagementRequestSerializing, requestInterceptor: MSALNativeAuthRequestInterceptor?)
+ {
+ self.requestSerializer = requestSerializer
+ self.requestInterceptor = requestInterceptor
+ }
+
+ // MARK: - List Methods
+
+ func listMethods(
+ accessToken: String,
+ correlationId: UUID
+ ) async -> Result<[any MSALCredentialMethodProtocol], MSALNativeCredentialManagementError>
+ {
+ let typedRequest = ListMethodsRequest(accessToken: accessToken, correlationId: correlationId)
+
+ MSIDLogger.shared().log(level: .info, correlationId: correlationId, message: "Credential management: listing methods")
+
+ let sendResult = await send(typedRequest)
+
+ switch sendResult
+ {
+ case .failure(let e):
+ return .failure(e)
+ case .success(let response):
+ let mapResult = ListMethodsResponseMapper.map(response, correlationId: correlationId)
+ if case .success(let methods) = mapResult
+ {
+ MSIDLogger.shared().log(level: .info, correlationId: correlationId, message: "Credential management: listed \(methods.count) method(s)")
+ }
+ return mapResult
+ }
+ }
+
+ // MARK: - Begin Enrollment
+
+ func beginEnrollment(
+ params: EnrollmentParams,
+ accessToken: String,
+ correlationId: UUID
+ ) async -> Result
+ {
+ let body: Data?
+
+ switch params
+ {
+ case let phoneParams as PhoneEnrollmentParams:
+ body = try? JSONSerialization.data(withJSONObject: ["phoneNumber": phoneParams.phoneNumber])
+ case let passwordParams as PasswordEnrollmentParams:
+ body = try? JSONSerialization.data(withJSONObject: ["password": passwordParams.password])
+ default:
+ body = nil
+ }
+
+ let typedRequest = BeginEnrollmentRequest(
+ type: params.type,
+ accessToken: accessToken,
+ body: body,
+ correlationId: correlationId
+ )
+
+ MSIDLogger.shared().log(
+ level: .info,
+ correlationId: correlationId,
+ message: "Credential management: beginning enrollment for type '\(CredentialMethodMapper.serverType(from: params.type))'"
+ )
+
+ let sendResult = await send(typedRequest)
+
+ switch sendResult
+ {
+ case .failure(let e):
+ return .failure(e)
+ case .success(let response):
+ return mapEnrollmentResponse(response, type: params.type, correlationId: correlationId)
+ }
+ }
+
+ // MARK: - Activate Enrollment
+
+ func activateEnrollment(
+ params: ActivationParams,
+ accessToken: String,
+ correlationId: UUID
+ ) async -> Result
+ {
+ let body: Data
+
+ switch params
+ {
+ case let otpParams as OTPActivationParams:
+ let bodyDict: [String: Any] = [
+ "continuationToken": otpParams.continuationToken,
+ "oob": otpParams.code
+ ]
+ guard let encoded = try? JSONSerialization.data(withJSONObject: bodyDict) else
+ {
+ return .failure(MSALNativeCredentialManagementError(
+ type: .generalError,
+ message: "Failed to encode OTP activation body.",
+ correlationId: correlationId
+ ))
+ }
+ body = encoded
+
+ case let passkeyParams as PasskeyActivationParams:
+ let bodyDict: [String: Any] = [
+ "continuationToken": passkeyParams.continuationToken,
+ "displayName": passkeyParams.displayName,
+ "publicKeyCredential": [
+ "id": passkeyParams.credentialId.base64EncodedString(),
+ "response": [
+ "attestationObject": passkeyParams.attestationObject.base64EncodedString(),
+ "clientDataJSON": passkeyParams.clientDataJSON.base64EncodedString()
+ ]
+ ]
+ ]
+ guard let encoded = try? JSONSerialization.data(withJSONObject: bodyDict) else
+ {
+ return .failure(MSALNativeCredentialManagementError(
+ type: .generalError,
+ message: "Failed to encode passkey activation body.",
+ correlationId: correlationId
+ ))
+ }
+ body = encoded
+
+ default:
+ return .failure(MSALNativeCredentialManagementError(
+ type: .generalError,
+ message: "Unsupported activation params type.",
+ correlationId: correlationId
+ ))
+ }
+
+ // Resolve the activate href from our internal relation store
+ guard let activateHref = activateHrefStore.removeValue(forKey: params.continuationToken) else
+ {
+ return .failure(MSALNativeCredentialManagementError(
+ type: .generalError,
+ message: "No activate link found for the given continuation token.",
+ correlationId: correlationId
+ ))
+ }
+
+ let typedRequest = ActivateEnrollmentRequest(
+ activateHref: activateHref,
+ accessToken: accessToken,
+ body: body,
+ correlationId: correlationId
+ )
+
+ MSIDLogger.shared().log(level: .info, correlationId: correlationId, message: "Credential management: activating enrollment")
+
+ let sendResult = await send(typedRequest)
+
+ switch sendResult
+ {
+ case .failure(let e):
+ return .failure(e)
+ case .success(let response):
+ return mapActivationResponse(response, correlationId: correlationId)
+ }
+ }
+
+ // MARK: - Delete Method
+
+ func deleteMethod(
+ type: MSALCredentialType,
+ methodId: String,
+ accessToken: String,
+ correlationId: UUID
+ ) async -> Result
+ {
+ let typedRequest = DeleteMethodRequest(
+ type: type,
+ methodId: methodId,
+ accessToken: accessToken,
+ correlationId: correlationId
+ )
+
+ MSIDLogger.shared().log(
+ level: .info,
+ correlationId: correlationId,
+ message: "Credential management: deleting method of type '\(CredentialMethodMapper.serverType(from: type))'"
+ )
+
+ let sendResult = await send(typedRequest)
+
+ switch sendResult
+ {
+ case .failure(let e):
+ return .failure(e)
+ case .success:
+ MSIDLogger.shared().log(level: .info, correlationId: correlationId, message: "Credential management: method deleted successfully")
+ return .success(())
+ }
+ }
+
+ // MARK: - Private: Response Mapping
+
+ /// Maps a raw enrollment response into a typed `EnrollmentBeginResponse`.
+ /// Stores any HAL activate link in the internal relation store.
+ private func mapEnrollmentResponse(
+ _ response: CredentialManagementResponse,
+ type: MSALCredentialType,
+ correlationId: UUID
+ ) -> Result
+ {
+ guard let json = response.jsonBody else
+ {
+ return .failure(MSALNativeCredentialManagementError(
+ type: .generalError,
+ message: "Response body is empty or not valid JSON.",
+ correlationId: correlationId
+ ))
+ }
+
+ let halResource = HALResource(json: json)
+
+ // Check if enrollment completed in one step
+ let state = halResource.string(forKey: "state")
+ if state == "completed" || halResource.link(rel: "activate") == nil
+ {
+ if let method = CredentialMethodMapper.parseMethod(from: halResource.properties)
+ {
+ return .success(.completed(method))
+ }
+ // Fallback for password
+ if type == .password
+ {
+ let method = MSALPasswordCredentialMethod(
+ id: halResource.string(forKey: "id") ?? UUID().uuidString,
+ createdAt: Date()
+ )
+ return .success(.completed(method))
+ }
+ }
+
+ // Multi-step: extract continuation token and store activate link
+ guard let continuationToken = halResource.string(forKey: "continuationToken") else
+ {
+ return .failure(MSALNativeCredentialManagementError(
+ type: .generalError,
+ message: "Server did not return continuationToken.",
+ correlationId: correlationId
+ ))
+ }
+
+ if let activateLink = halResource.link(rel: "activate")
+ {
+ activateHrefStore[continuationToken] = activateLink.href
+ }
+
+ // Passkey: return creation options
+ if let publicKeyDict = halResource.properties["publicKey"] as? [String: Any]
+ {
+ let info = PasskeyCreationInfo(
+ publicKey: publicKeyDict,
+ continuationToken: continuationToken
+ )
+ return .success(.passkeyCreationRequired(info))
+ }
+
+ // Phone/other: return challenge info
+ let challengeInfo = EnrollmentChallengeInfo(
+ sentTo: halResource.string(forKey: "sentTo"),
+ channelType: halResource.string(forKey: "channelType"),
+ codeLength: halResource.properties["codeLength"] as? Int,
+ continuationToken: continuationToken
+ )
+ return .success(.challengeRequired(challengeInfo))
+ }
+
+ /// Maps an activation response into a typed credential method.
+ private func mapActivationResponse(
+ _ response: CredentialManagementResponse,
+ correlationId: UUID
+ ) -> Result
+ {
+ guard let json = response.jsonBody else
+ {
+ return .failure(MSALNativeCredentialManagementError(
+ type: .generalError,
+ message: "Activation response body is empty or not valid JSON.",
+ correlationId: correlationId
+ ))
+ }
+
+ let halResource = HALResource(json: json)
+
+ guard let method = CredentialMethodMapper.parseMethod(from: halResource.properties) else
+ {
+ return .failure(MSALNativeCredentialManagementError(
+ type: .generalError,
+ message: "Failed to parse registered method from activation response.",
+ correlationId: correlationId
+ ))
+ }
+
+ return .success(method)
+ }
+
+ // MARK: - Private: Send Pipeline
+
+ private func send(
+ _ typedRequest: CredentialManagementRequestProtocol
+ ) async -> Result
+ {
+ let configurator = CredentialManagementRequestConfigurator(
+ requestSerializer: requestSerializer,
+ correlationId: typedRequest.correlationId,
+ requestInterceptor: requestInterceptor
+ )
+
+ let configResult = configurator.configure(typedRequest)
+
+ let msidRequest: MSIDHttpRequest
+ switch configResult
+ {
+ case .success(let r): msidRequest = r
+ case .failure(let e): return .failure(e)
+ }
+
+ return await withCheckedContinuation
+ { continuation in
+ msidRequest.send
+ { result, error in
+ if let error = error
+ {
+ if let credError = error as? MSALNativeCredentialManagementError
+ {
+ continuation.resume(returning: .failure(credError))
+ }
+ else
+ {
+ continuation.resume(returning: .failure(MSALNativeCredentialManagementError(
+ type: .networkError,
+ message: "Network request failed.",
+ correlationId: typedRequest.correlationId,
+ underlyingError: error
+ )))
+ }
+ }
+ else if let response = result as? CredentialManagementResponse
+ {
+ continuation.resume(returning: .success(response))
+ }
+ else
+ {
+ continuation.resume(returning: .failure(MSALNativeCredentialManagementError(
+ type: .generalError,
+ message: "Unexpected response type from network layer.",
+ correlationId: typedRequest.correlationId
+ )))
+ }
+ }
+ }
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/CredentialManagementURLResolver.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/CredentialManagementURLResolver.swift
new file mode 100644
index 0000000000..add04a1e6d
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/CredentialManagementURLResolver.swift
@@ -0,0 +1,70 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+/// Centralized URL resolution and validation for the credential management service.
+/// Used by both the MSIDHttpRequest-based transport and the custom network provider transport.
+internal struct CredentialManagementURLResolver
+{
+ private let baseURL: URL
+
+ init(baseURL: URL)
+ {
+ self.baseURL = baseURL
+ }
+
+ /// Resolves a path (absolute or relative) against the base URL.
+ /// Returns nil if the resolved URL does not pass security validation.
+ ///
+ /// Validation rules:
+ /// - Scheme must be HTTPS
+ /// - Host must match the trusted base URL host
+ func resolve(path: String) -> URL?
+ {
+ let resolvedURL: URL
+
+ if path.hasPrefix("http://") || path.hasPrefix("https://")
+ {
+ guard let url = URL(string: path) else { return nil }
+ resolvedURL = url
+ }
+ else
+ {
+ guard let url = URL(string: path, relativeTo: baseURL)?.absoluteURL else { return nil }
+ resolvedURL = url
+ }
+
+ guard resolvedURL.scheme == "https" else { return nil }
+ guard resolvedURL.host == baseURL.host else { return nil }
+
+ return resolvedURL
+ }
+}
+
+/// Shared endpoint path constants.
+internal enum CredentialManagementEndpoints
+{
+ static let methodsPath = "/api/v1.0/me/methods"
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/CredentialMethodMapper.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/CredentialMethodMapper.swift
new file mode 100644
index 0000000000..f82c69bd23
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/CredentialMethodMapper.swift
@@ -0,0 +1,112 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+/// Maps server method types to SDK `MSALCredentialType` values.
+///
+/// The server uses different type identifiers (e.g., "fido") than the SDK
+/// (e.g., `.passkey`). This mapper handles the bidirectional translation.
+internal struct CredentialMethodMapper
+{
+ // MARK: - Server type → SDK type mapping
+
+ /// Maps a server `type` string to an `MSALCredentialType`.
+ static func credentialType(fromServerType serverType: String) -> MSALCredentialType?
+ {
+ switch serverType
+ {
+ case "fido":
+ return .passkey
+ case "phone", "sms":
+ return .phone
+ case "password":
+ return .password
+ default:
+ return nil
+ }
+ }
+
+ /// Maps an `MSALCredentialType` to the server's `type` string for API paths.
+ static func serverType(from credentialType: MSALCredentialType) -> String
+ {
+ return credentialType.rawValue
+ }
+
+ // MARK: - HAL JSON → Credential Method
+
+ /// Parses a single credential method from a HAL-embedded method JSON object.
+ ///
+ /// - Parameter json: The method JSON from `_embedded.methods[]`.
+ /// - Returns: A concrete `MSALCredentialMethodProtocol` instance, or nil for unknown types.
+ static func parseMethod(from json: [String: Any]) -> (any MSALCredentialMethodProtocol)?
+ {
+ guard let serverType = json["type"] as? String,
+ let id = json["id"] as? String else
+ {
+ return nil
+ }
+
+ let displayName = json["displayName"] as? String
+
+ switch serverType
+ {
+ case "fido":
+ return MSALPasskeyCredentialMethod(
+ id: id,
+ displayName: displayName,
+ createdAt: nil,
+ credentialID: nil,
+ aaguid: json["aaGuid"] as? String
+ )
+
+ case "phone", "sms":
+ return MSALPhoneCredentialMethod(
+ id: id,
+ createdAt: nil,
+ phoneNumber: displayName
+ )
+
+ case "password":
+ return MSALPasswordCredentialMethod(
+ id: id,
+ createdAt: nil
+ )
+
+ default:
+ // Unknown method type — skip for forward compatibility
+ return nil
+ }
+ }
+
+ /// Parses the list of credential methods from a `GET /me/methods` HAL response.
+ ///
+ /// - Parameter halResource: The parsed HAL resource.
+ /// - Returns: Array of credential method instances.
+ static func parseMethods(from halResource: HALResource) -> [any MSALCredentialMethodProtocol]
+ {
+ let methodsJson = halResource.embeddedResources(rel: "methods")
+ return methodsJson.compactMap { parseMethod(from: $0) }
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/HALResource.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/HALResource.swift
new file mode 100644
index 0000000000..e08a48a9d7
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/HALResource.swift
@@ -0,0 +1,146 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+/// Represents a HAL Link Object as defined by the JSON-HAL specification.
+///
+/// See: https://www.ietf.org/archive/id/draft-kelly-json-hal-11.html
+internal struct HALLink
+{
+ /// The URI of the linked resource.
+ let href: String
+
+ /// Secondary key distinguishing links within the same relation.
+ let name: String?
+
+ /// Whether `href` is a URI Template (RFC 6570).
+ let templated: Bool
+
+ init(href: String, name: String? = nil, templated: Bool = false)
+ {
+ self.href = href
+ self.name = name
+ self.templated = templated
+ }
+
+ /// Parses a HAL Link Object from a JSON dictionary.
+ init?(json: [String: Any])
+ {
+ guard let href = json["href"] as? String else { return nil }
+ self.href = href
+ self.name = json["name"] as? String
+ self.templated = json["templated"] as? Bool ?? false
+ }
+}
+
+/// Generic parser for HAL+JSON documents.
+///
+/// Handles extraction of `_links` and `_embedded` sections,
+/// and provides typed accessors for common HAL patterns.
+internal struct HALResource
+{
+ /// The raw JSON properties (excluding `_links` and `_embedded`).
+ let properties: [String: Any]
+
+ /// All links keyed by relation type.
+ let links: [String: [HALLink]]
+
+ /// All embedded resources keyed by relation type.
+ let embedded: [String: [[String: Any]]]
+
+ /// Parses a HAL resource from a JSON dictionary.
+ init(json: [String: Any])
+ {
+ var props = json
+ var parsedLinks: [String: [HALLink]] = [:]
+ var parsedEmbedded: [String: [[String: Any]]] = [:]
+
+ // Parse _links
+ if let linksJson = json["_links"] as? [String: Any]
+ {
+ for (rel, value) in linksJson
+ {
+ if rel == "curies" { continue }
+
+ if let linkDict = value as? [String: Any], let link = HALLink(json: linkDict)
+ {
+ parsedLinks[rel] = [link]
+ }
+ else if let linkArray = value as? [[String: Any]]
+ {
+ parsedLinks[rel] = linkArray.compactMap { HALLink(json: $0) }
+ }
+ }
+ props.removeValue(forKey: "_links")
+ }
+
+ // Parse _embedded
+ if let embeddedJson = json["_embedded"] as? [String: Any]
+ {
+ for (rel, value) in embeddedJson
+ {
+ if let array = value as? [[String: Any]]
+ {
+ parsedEmbedded[rel] = array
+ }
+ else if let single = value as? [String: Any]
+ {
+ parsedEmbedded[rel] = [single]
+ }
+ }
+ props.removeValue(forKey: "_embedded")
+ }
+
+ self.properties = props
+ self.links = parsedLinks
+ self.embedded = parsedEmbedded
+ }
+
+ // MARK: - Accessors
+
+ /// Returns a single link for the given relation, or nil if not present.
+ func link(rel: String) -> HALLink?
+ {
+ return links[rel]?.first
+ }
+
+ /// Returns all links for the given relation.
+ func allLinks(rel: String) -> [HALLink]
+ {
+ return links[rel] ?? []
+ }
+
+ /// Returns embedded resources for the given relation.
+ func embeddedResources(rel: String) -> [[String: Any]]
+ {
+ return embedded[rel] ?? []
+ }
+
+ /// Returns a string property value.
+ func string(forKey key: String) -> String?
+ {
+ return properties[key] as? String
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/request/ActivateEnrollmentRequest.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/request/ActivateEnrollmentRequest.swift
new file mode 100644
index 0000000000..dd6b7fd814
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/request/ActivateEnrollmentRequest.swift
@@ -0,0 +1,44 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+/// Request to activate a pending enrollment.
+/// POST {activateHref} (absolute or relative URL provided by the service)
+internal struct ActivateEnrollmentRequest: CredentialManagementRequestProtocol
+{
+ let httpMethod = "POST"
+ let path: String
+ let accessToken: String
+ let correlationId: UUID
+ let body: Data?
+
+ init(activateHref: String, accessToken: String, body: Data, correlationId: UUID)
+ {
+ self.path = activateHref
+ self.accessToken = accessToken
+ self.body = body
+ self.correlationId = correlationId
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/request/BeginEnrollmentRequest.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/request/BeginEnrollmentRequest.swift
new file mode 100644
index 0000000000..3f52d24c8a
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/request/BeginEnrollmentRequest.swift
@@ -0,0 +1,46 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+import MSAL
+
+/// Request to begin enrollment of a new credential method.
+/// POST /api/v1.0/me/methods/{type}
+internal struct BeginEnrollmentRequest: CredentialManagementRequestProtocol
+{
+ let httpMethod = "POST"
+ let path: String
+ let accessToken: String
+ let correlationId: UUID
+ let body: Data?
+
+ init(type: MSALCredentialType, accessToken: String, body: Data?, correlationId: UUID)
+ {
+ let serverType = CredentialMethodMapper.serverType(from: type)
+ self.path = "\(CredentialManagementEndpoints.methodsPath)/\(serverType)"
+ self.accessToken = accessToken
+ self.body = body
+ self.correlationId = correlationId
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/request/CredentialManagementRequest.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/request/CredentialManagementRequest.swift
new file mode 100644
index 0000000000..28d62a3f17
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/request/CredentialManagementRequest.swift
@@ -0,0 +1,46 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+/// Base protocol for all credential management network requests.
+/// Each endpoint defines a concrete type conforming to this protocol.
+internal protocol CredentialManagementRequestProtocol
+{
+ /// HTTP method (GET, POST, DELETE, etc.)
+ var httpMethod: String { get }
+
+ /// The path or absolute URL for the endpoint.
+ /// Relative paths are resolved against the base URL.
+ var path: String { get }
+
+ /// The access token for the Bearer authorization header.
+ var accessToken: String { get }
+
+ /// Correlation ID for request tracing.
+ var correlationId: UUID { get }
+
+ /// Optional request body (JSON-encoded).
+ var body: Data? { get }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/request/DeleteMethodRequest.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/request/DeleteMethodRequest.swift
new file mode 100644
index 0000000000..73c04f91be
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/request/DeleteMethodRequest.swift
@@ -0,0 +1,45 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+import MSAL
+
+/// Request to delete a credential method.
+/// DELETE /api/v1.0/me/methods/{type}/{methodId}
+internal struct DeleteMethodRequest: CredentialManagementRequestProtocol
+{
+ let httpMethod = "DELETE"
+ let path: String
+ let accessToken: String
+ let correlationId: UUID
+ let body: Data? = nil
+
+ init(type: MSALCredentialType, methodId: String, accessToken: String, correlationId: UUID)
+ {
+ let serverType = CredentialMethodMapper.serverType(from: type)
+ self.path = "\(CredentialManagementEndpoints.methodsPath)/\(serverType)/\(methodId)"
+ self.accessToken = accessToken
+ self.correlationId = correlationId
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/request/ListMethodsRequest.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/request/ListMethodsRequest.swift
new file mode 100644
index 0000000000..f08a927922
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/request/ListMethodsRequest.swift
@@ -0,0 +1,43 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+/// Request to list all credential methods for the current user.
+/// GET /api/v1.0/me/methods
+internal struct ListMethodsRequest: CredentialManagementRequestProtocol
+{
+ let httpMethod = "GET"
+ let path: String
+ let accessToken: String
+ let correlationId: UUID
+ let body: Data? = nil
+
+ init(accessToken: String, correlationId: UUID)
+ {
+ self.path = CredentialManagementEndpoints.methodsPath
+ self.accessToken = accessToken
+ self.correlationId = correlationId
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/request_serializer/CredentialManagementRequestSerializer.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/request_serializer/CredentialManagementRequestSerializer.swift
new file mode 100644
index 0000000000..d4feaf5ef0
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/request_serializer/CredentialManagementRequestSerializer.swift
@@ -0,0 +1,68 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+/// Concrete request serializer that transforms typed credential management requests
+/// into `URLRequest` instances with appropriate headers.
+///
+/// Applies:
+/// - Authorization: Bearer {token}
+/// - Accept: application/hal+json
+/// - client-request-id: {correlationId}
+/// - Content-Type: application/json (when body present)
+internal final class CredentialManagementRequestSerializer: CredentialManagementRequestSerializing
+{
+ private let urlResolver: CredentialManagementURLResolver
+
+ init(urlResolver: CredentialManagementURLResolver)
+ {
+ self.urlResolver = urlResolver
+ }
+
+ func serialize(_ request: CredentialManagementRequestProtocol) -> URLRequest?
+ {
+ guard let url = urlResolver.resolve(path: request.path) else
+ {
+ return nil
+ }
+
+ var urlRequest = URLRequest(url: url)
+ urlRequest.httpMethod = request.httpMethod
+
+ // Standard headers
+ urlRequest.setValue("Bearer \(request.accessToken)", forHTTPHeaderField: "Authorization")
+ urlRequest.setValue("application/hal+json", forHTTPHeaderField: "Accept")
+ urlRequest.setValue(request.correlationId.uuidString, forHTTPHeaderField: "client-request-id")
+
+ // Body
+ if let body = request.body
+ {
+ urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
+ urlRequest.httpBody = body
+ }
+
+ return urlRequest
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/request_serializer/CredentialManagementRequestSerializing.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/request_serializer/CredentialManagementRequestSerializing.swift
new file mode 100644
index 0000000000..d4b10f5c0a
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/request_serializer/CredentialManagementRequestSerializing.swift
@@ -0,0 +1,33 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+/// Protocol for serializing typed credential management requests into URLRequests.
+internal protocol CredentialManagementRequestSerializing
+{
+ /// Transforms a typed request into a fully configured URLRequest.
+ /// Returns nil if the request cannot be serialized (e.g., URL validation failure).
+ func serialize(_ request: CredentialManagementRequestProtocol) -> URLRequest?
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/response/CredentialManagementResponse.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/response/CredentialManagementResponse.swift
new file mode 100644
index 0000000000..a5402eb8b4
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/response/CredentialManagementResponse.swift
@@ -0,0 +1,41 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+/// Typed response model for credential management HTTP responses.
+/// Contains the parsed status code, headers, and optional JSON body.
+internal struct CredentialManagementResponse
+{
+ let statusCode: Int
+ let headers: [String: String]
+ let jsonBody: [String: Any]?
+ let rawData: Data?
+
+ /// Whether the response indicates success (2xx).
+ var isSuccess: Bool
+ {
+ return (200...299).contains(statusCode)
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/response_mapper/EnrollmentResponseMapper.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/response_mapper/EnrollmentResponseMapper.swift
new file mode 100644
index 0000000000..a2db91a166
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/response_mapper/EnrollmentResponseMapper.swift
@@ -0,0 +1,48 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+import MSAL
+
+/// Maps a successful credential management response into a `HALResource`.
+/// Used for enrollment (begin and activate) responses.
+internal enum EnrollmentResponseMapper
+{
+ static func map(
+ _ response: CredentialManagementResponse,
+ correlationId: UUID
+ ) -> Result
+ {
+ guard let json = response.jsonBody else
+ {
+ return .failure(MSALNativeCredentialManagementError(
+ type: .generalError,
+ message: "Response body is empty or not valid JSON.",
+ correlationId: correlationId
+ ))
+ }
+
+ return .success(HALResource(json: json))
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/response_mapper/ListMethodsResponseMapper.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/response_mapper/ListMethodsResponseMapper.swift
new file mode 100644
index 0000000000..c1489d441b
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/response_mapper/ListMethodsResponseMapper.swift
@@ -0,0 +1,50 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+import MSAL
+
+/// Maps a successful credential management response containing a methods list
+/// into an array of `MSALCredentialMethodProtocol` objects.
+internal enum ListMethodsResponseMapper
+{
+ static func map(
+ _ response: CredentialManagementResponse,
+ correlationId: UUID
+ ) -> Result<[any MSALCredentialMethodProtocol], MSALNativeCredentialManagementError>
+ {
+ guard let json = response.jsonBody else
+ {
+ return .failure(MSALNativeCredentialManagementError(
+ type: .generalError,
+ message: "Response body is empty or not valid JSON.",
+ correlationId: correlationId
+ ))
+ }
+
+ let halResource = HALResource(json: json)
+ let methods = CredentialMethodMapper.parseMethods(from: halResource)
+ return .success(methods)
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/response_serializer/CredentialManagementHALResponseSerializer.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/response_serializer/CredentialManagementHALResponseSerializer.swift
new file mode 100644
index 0000000000..05c9aa4fbf
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/response_serializer/CredentialManagementHALResponseSerializer.swift
@@ -0,0 +1,72 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+/// Concrete response serializer that parses raw HTTP into `CredentialManagementResponse`.
+/// Handles HAL+JSON content by parsing the body as JSON.
+internal final class CredentialManagementHALResponseSerializer: CredentialManagementResponseSerializing
+{
+ func serialize(httpResponse: HTTPURLResponse?, data: Data?) -> CredentialManagementResponse?
+ {
+ guard let httpResponse = httpResponse else
+ {
+ return nil
+ }
+
+ let statusCode = httpResponse.statusCode
+ let headers = httpResponse.allHeaderFields.reduce(into: [String: String]())
+ { result, pair in
+ if let key = pair.key as? String, let value = pair.value as? String
+ {
+ result[key] = value
+ }
+ }
+
+ // For 204 No Content or empty body, return response without JSON
+ if statusCode == 204 || data == nil || data?.isEmpty == true
+ {
+ return CredentialManagementResponse(
+ statusCode: statusCode,
+ headers: headers,
+ jsonBody: nil,
+ rawData: data
+ )
+ }
+
+ // Parse JSON body
+ var jsonBody: [String: Any]?
+ if let data = data
+ {
+ jsonBody = (try? JSONSerialization.jsonObject(with: data)) as? [String: Any]
+ }
+
+ return CredentialManagementResponse(
+ statusCode: statusCode,
+ headers: headers,
+ jsonBody: jsonBody,
+ rawData: data
+ )
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/response_serializer/CredentialManagementResponseSerializing.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/response_serializer/CredentialManagementResponseSerializing.swift
new file mode 100644
index 0000000000..e4fca1af7e
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/response_serializer/CredentialManagementResponseSerializing.swift
@@ -0,0 +1,32 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+/// Protocol for deserializing raw HTTP responses into typed response objects.
+internal protocol CredentialManagementResponseSerializing
+{
+ /// Parses a raw HTTP response into a typed `CredentialManagementResponse`.
+ func serialize(httpResponse: HTTPURLResponse?, data: Data?) -> CredentialManagementResponse?
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/response_serializer/MSIDResponseSerializerAdapter.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/response_serializer/MSIDResponseSerializerAdapter.swift
new file mode 100644
index 0000000000..bcc0720734
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/providers/server/response_serializer/MSIDResponseSerializerAdapter.swift
@@ -0,0 +1,68 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+@_implementationOnly import MSAL_Private
+
+/// Adapter that bridges the pure-Swift `CredentialManagementHALResponseSerializer`
+/// to IdentityCore's `MSIDResponseSerialization` protocol.
+///
+/// This is installed on `MSIDHttpRequest.responseSerializer` to integrate with
+/// the IdentityCore transport pipeline while keeping parsing logic in pure Swift.
+internal final class MSIDResponseSerializerAdapter: NSObject, MSIDResponseSerialization
+{
+ private let halSerializer = CredentialManagementHALResponseSerializer()
+
+ func responseObject(for httpResponse: HTTPURLResponse?, data: Data?, context: MSIDRequestContext?) throws -> Any
+ {
+ guard let response = halSerializer.serialize(httpResponse: httpResponse, data: data) else
+ {
+ throw NSError(
+ domain: "CredentialManagementErrorDomain",
+ code: -1,
+ userInfo: [NSLocalizedDescriptionKey: "No HTTP response received."]
+ )
+ }
+
+ // For error status codes, throw so the error handler takes over
+ guard response.isSuccess else
+ {
+ var userInfo: [String: Any] = [
+ "statusCode": response.statusCode,
+ "responseHeaders": response.headers
+ ]
+ if let data = data
+ {
+ userInfo["responseData"] = data
+ }
+ throw NSError(
+ domain: "CredentialManagementErrorDomain",
+ code: response.statusCode,
+ userInfo: userInfo
+ )
+ }
+
+ return response
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/request_params/activation_params/ActivationParams.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/request_params/activation_params/ActivationParams.swift
new file mode 100644
index 0000000000..9317ddf479
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/request_params/activation_params/ActivationParams.swift
@@ -0,0 +1,37 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+/// Base class for activation (enrollment completion) parameters.
+/// Subclass to add new activation flows without modifying existing code (Open/Closed Principle).
+internal class ActivationParams
+{
+ let continuationToken: String
+
+ init(continuationToken: String)
+ {
+ self.continuationToken = continuationToken
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/request_params/activation_params/OTPActivationParams.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/request_params/activation_params/OTPActivationParams.swift
new file mode 100644
index 0000000000..316aa1e34f
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/request_params/activation_params/OTPActivationParams.swift
@@ -0,0 +1,37 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+/// OTP-based activation parameters (phone verification).
+internal final class OTPActivationParams: ActivationParams
+{
+ let code: String
+
+ init(continuationToken: String, code: String)
+ {
+ self.code = code
+ super.init(continuationToken: continuationToken)
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/request_params/activation_params/PasskeyActivationParams.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/request_params/activation_params/PasskeyActivationParams.swift
new file mode 100644
index 0000000000..3d75636f8c
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/request_params/activation_params/PasskeyActivationParams.swift
@@ -0,0 +1,49 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+/// Passkey attestation-based activation parameters.
+internal final class PasskeyActivationParams: ActivationParams
+{
+ let displayName: String
+ let credentialId: Data
+ let attestationObject: Data
+ let clientDataJSON: Data
+
+ init(
+ continuationToken: String,
+ displayName: String,
+ credentialId: Data,
+ attestationObject: Data,
+ clientDataJSON: Data
+ )
+ {
+ self.displayName = displayName
+ self.credentialId = credentialId
+ self.attestationObject = attestationObject
+ self.clientDataJSON = clientDataJSON
+ super.init(continuationToken: continuationToken)
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/request_params/enrollment_params/EnrollmentParams.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/request_params/enrollment_params/EnrollmentParams.swift
new file mode 100644
index 0000000000..2937b7d899
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/request_params/enrollment_params/EnrollmentParams.swift
@@ -0,0 +1,37 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+/// Base class for enrollment parameters.
+/// Subclass to add new credential types without modifying existing code (Open/Closed Principle).
+internal class EnrollmentParams
+{
+ let type: MSALCredentialType
+
+ init(type: MSALCredentialType)
+ {
+ self.type = type
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/request_params/enrollment_params/PasskeyEnrollmentParams.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/request_params/enrollment_params/PasskeyEnrollmentParams.swift
new file mode 100644
index 0000000000..768fe12997
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/request_params/enrollment_params/PasskeyEnrollmentParams.swift
@@ -0,0 +1,34 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+/// Parameters for enrolling a passkey credential.
+internal final class PasskeyEnrollmentParams: EnrollmentParams
+{
+ init()
+ {
+ super.init(type: .passkey)
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/request_params/enrollment_params/PasswordEnrollmentParams.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/request_params/enrollment_params/PasswordEnrollmentParams.swift
new file mode 100644
index 0000000000..218a8ca13c
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/request_params/enrollment_params/PasswordEnrollmentParams.swift
@@ -0,0 +1,37 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+/// Parameters for enrolling a password credential.
+internal final class PasswordEnrollmentParams: EnrollmentParams
+{
+ let password: String
+
+ init(password: String)
+ {
+ self.password = password
+ super.init(type: .password)
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/request_params/enrollment_params/PhoneEnrollmentParams.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/request_params/enrollment_params/PhoneEnrollmentParams.swift
new file mode 100644
index 0000000000..423aeb9182
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/request_params/enrollment_params/PhoneEnrollmentParams.swift
@@ -0,0 +1,37 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+/// Parameters for enrolling a phone number credential.
+internal final class PhoneEnrollmentParams: EnrollmentParams
+{
+ let phoneNumber: String
+
+ init(phoneNumber: String)
+ {
+ self.phoneNumber = phoneNumber
+ super.init(type: .phone)
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/response/EnrollmentBeginResponse.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/response/EnrollmentBeginResponse.swift
new file mode 100644
index 0000000000..53158a6bfe
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/internal/network/response/EnrollmentBeginResponse.swift
@@ -0,0 +1,57 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+/// HAL-free result of a `beginEnrollment` call.
+///
+/// Callers use this typed response instead of parsing raw HAL resources.
+/// The HAL-specific link/resource context is managed internally by the server layer.
+internal enum EnrollmentBeginResponse
+{
+ /// Enrollment completed in one step (e.g., password).
+ case completed(any MSALCredentialMethodProtocol)
+
+ /// A verification challenge was sent (e.g., OTP to phone).
+ case challengeRequired(EnrollmentChallengeInfo)
+
+ /// Server returned WebAuthn creation options for passkey registration.
+ case passkeyCreationRequired(PasskeyCreationInfo)
+}
+
+/// Information about a verification challenge sent during enrollment.
+internal struct EnrollmentChallengeInfo
+{
+ let sentTo: String?
+ let channelType: String?
+ let codeLength: Int?
+ let continuationToken: String
+}
+
+/// Information needed to invoke the platform authenticator for passkey creation.
+internal struct PasskeyCreationInfo
+{
+ let publicKey: [String: Any]
+ let continuationToken: String
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/MSALCredentialMethodRegistrationResult.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/MSALCredentialMethodRegistrationResult.swift
new file mode 100644
index 0000000000..a53cff380f
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/MSALCredentialMethodRegistrationResult.swift
@@ -0,0 +1,120 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+/// The result of a credential method registration attempt.
+///
+/// Registration may complete immediately or require a verification challenge (e.g., OOB code).
+public enum MSALCredentialMethodRegistrationResult
+{
+ /// Registration completed successfully.
+ case completed(any MSALCredentialMethodProtocol)
+
+ /// A verification challenge is required to complete registration.
+ /// Use the provided `MSALCredentialMethodChallengeState` to submit the code or resend.
+ case challengeRequired(MSALCredentialMethodChallengeState)
+}
+
+/// Represents the state of a pending challenge during credential registration.
+///
+/// Use `submitChallenge(code:)` to verify or `resendChallenge()` to request a new code.
+public class MSALCredentialMethodChallengeState
+{
+ /// The channel the code was sent to (e.g., email address or phone number hint).
+ public let sentTo: String?
+
+ /// The channel type (e.g., "email", "phone").
+ public let channelType: String?
+
+ /// The number of digits in the expected code.
+ public let codeLength: Int?
+
+ // MARK: - Internal
+
+ private let continuationToken: String
+ private weak var client: MSALNativeCredentialMethodsClient?
+ private let correlationId: UUID
+
+ internal init(
+ sentTo: String?,
+ channelType: String?,
+ codeLength: Int?,
+ continuationToken: String,
+ client: MSALNativeCredentialMethodsClient,
+ correlationId: UUID
+ )
+ {
+ self.sentTo = sentTo
+ self.channelType = channelType
+ self.codeLength = codeLength
+ self.continuationToken = continuationToken
+ self.client = client
+ self.correlationId = correlationId
+ }
+
+ /// Submit the verification code to complete registration.
+ ///
+ /// - Parameter code: The verification code received by the user.
+ /// - Returns: A `Result` containing the registered credential method or an error.
+ public func submitChallenge(code: String) async -> Result
+ {
+ guard let client = client else
+ {
+ let error = MSALNativeCredentialManagementError(
+ type: .generalError,
+ message: "Client was deallocated.",
+ correlationId: correlationId
+ )
+ return .failure(error)
+ }
+
+ return await client.submitRegistrationChallenge(
+ code: code,
+ continuationToken: continuationToken,
+ correlationId: correlationId
+ )
+ }
+
+ /// Request a new verification code.
+ ///
+ /// - Returns: A new `MSALCredentialMethodChallengeState` with updated delivery info, or an error.
+ public func resendChallenge() async -> Result
+ {
+ guard let client = client else
+ {
+ let error = MSALNativeCredentialManagementError(
+ type: .generalError,
+ message: "Client was deallocated.",
+ correlationId: correlationId
+ )
+ return .failure(error)
+ }
+
+ return await client.resendRegistrationChallenge(
+ continuationToken: continuationToken,
+ correlationId: correlationId
+ )
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/MSALNativeCredentialManagementConfig.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/MSALNativeCredentialManagementConfig.swift
new file mode 100644
index 0000000000..191bd0b212
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/MSALNativeCredentialManagementConfig.swift
@@ -0,0 +1,65 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+import MSAL
+
+/// Configuration for the credential management client.
+///
+/// Use this class to configure the `MSALNativeCredentialMethodsClient` with a token provider,
+/// optional request interceptor (shared with MSAL), and tenant subdomain.
+///
+/// Example:
+/// ```swift
+/// let credConfig = MSALNativeCredentialManagementConfig()
+/// credConfig.requestInterceptor = sharedRequestInterceptor
+/// credConfig.tokenProvider = MyCustomTokenProvider()
+/// credConfig.tenantSubdomain = "contoso"
+/// let credClient = try MSALNativeCredentialMethodsClient(config: credConfig)
+/// ```
+@objcMembers
+public class MSALNativeCredentialManagementConfig: NSObject {
+
+ /// An optional interceptor for injecting custom HTTP headers into credential management requests.
+ ///
+ /// Can be shared with `MSALNativeAuthPublicClientApplicationConfig.requestInterceptor`
+ /// for consistent header injection across both MSAL and credential management calls.
+ public var requestInterceptor: MSALNativeAuthRequestInterceptor?
+
+ /// The token provider used to obtain access tokens for credential management API calls.
+ ///
+ /// - P0: Assign a custom implementation conforming to `MSALNativeCredentialManagementTokenProvider`.
+ /// - P1: Assign `MSALNativeAuthTokenProvider(userAccountResult:)` for automatic MSAL-based token retrieval.
+ public var tokenProvider: MSALNativeCredentialManagementTokenProvider?
+
+ /// The tenant subdomain for the CIAM tenant (e.g., "contoso" for contoso.ciamlogin.com).
+ ///
+ /// The credential management API base URL is derived from this value.
+ public var tenantSubdomain: String?
+
+ public override init()
+ {
+ super.init()
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/MSALNativeCredentialManagementError.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/MSALNativeCredentialManagementError.swift
new file mode 100644
index 0000000000..349e46b4ad
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/MSALNativeCredentialManagementError.swift
@@ -0,0 +1,101 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+/// Error domain for credential management operations.
+public let MSALNativeCredentialManagementErrorDomain = "MSALNativeCredentialManagementErrorDomain"
+
+/// Error types for credential management operations.
+@objc public enum MSALNativeCredentialManagementErrorType: Int {
+ /// A general, unclassified error occurred.
+ case generalError = 0
+ /// A network error occurred (timeout, connectivity, etc.).
+ case networkError = 1
+ /// The access token is invalid or expired.
+ case unauthorized = 2
+ /// The user lacks permission for this operation.
+ case forbidden = 3
+ /// The specified credential method was not found.
+ case notFound = 4
+ /// A conflict occurred (e.g., method already registered).
+ case conflict = 5
+ /// Challenge verification failed.
+ case challengeFailed = 6
+ /// The token provider reports no valid session.
+ case sessionExpired = 7
+ /// The client configuration is invalid.
+ case invalidConfiguration = 8
+ /// The input provided is invalid.
+ case invalidInput = 9
+}
+
+/// Error class for credential management operations.
+///
+/// Contains a typed error code, human-readable message, and optional correlation ID
+/// for diagnostics.
+@objcMembers
+public class MSALNativeCredentialManagementError: NSObject, Error {
+
+ /// The type of error that occurred.
+ public let type: MSALNativeCredentialManagementErrorType
+
+ /// A human-readable error message describing what went wrong.
+ public let message: String?
+
+ /// The correlation ID associated with this error for diagnostic purposes.
+ public let correlationId: UUID?
+
+ /// The underlying error, if any.
+ public let underlyingError: Error?
+
+ internal init(
+ type: MSALNativeCredentialManagementErrorType,
+ message: String? = nil,
+ correlationId: UUID? = nil,
+ underlyingError: Error? = nil
+ )
+ {
+ self.type = type
+ self.message = message
+ self.correlationId = correlationId
+ self.underlyingError = underlyingError
+ super.init()
+ }
+
+ public override var description: String
+ {
+ var desc = "MSALNativeCredentialManagementError(type: \(type)"
+ if let message = message
+ {
+ desc += ", message: \(message)"
+ }
+ if let correlationId = correlationId
+ {
+ desc += ", correlationId: \(correlationId)"
+ }
+ desc += ")"
+ return desc
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/MSALNativeCredentialMethodsClient.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/MSALNativeCredentialMethodsClient.swift
new file mode 100644
index 0000000000..7d9f2c4cfb
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/MSALNativeCredentialMethodsClient.swift
@@ -0,0 +1,172 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+import MSAL
+@_implementationOnly import MSAL_Private
+/// Client for managing credential methods of an authenticated CIAM user.
+///
+/// This client provides APIs to list, register, and delete credential methods
+/// (e.g., phone, passkey, password) for the currently signed-in user.
+///
+/// Example:
+/// ```swift
+/// let credConfig = MSALNativeCredentialManagementConfig()
+/// credConfig.requestInterceptor = sharedRequestInterceptor
+/// credConfig.tokenProvider = myTokenProvider
+/// let credClient = try MSALNativeCredentialMethodsClient(config: credConfig)
+/// ```
+@objcMembers
+public class MSALNativeCredentialMethodsClient: NSObject {
+
+ // MARK: - Public: Initialization
+
+ /// Initialize the credential methods client.
+ ///
+ /// - Parameter config: Configuration including token provider and optional interceptor.
+ /// - Throws: `MSALNativeCredentialManagementError` if the configuration is invalid (e.g., no token provider set).
+ public init(config: MSALNativeCredentialManagementConfig) throws
+ {
+ guard config.tokenProvider != nil else
+ {
+ throw MSALNativeCredentialManagementError(
+ type: .invalidConfiguration,
+ message: "A token provider must be set on MSALNativeCredentialManagementConfig before initializing the client."
+ )
+ }
+ guard config.tenantSubdomain != nil else
+ {
+ throw MSALNativeCredentialManagementError(
+ type: .invalidConfiguration,
+ message: "A tenantSubdomain must be set on MSALNativeCredentialManagementConfig before initializing the client."
+ )
+ }
+ self.config = config
+ self.operationQueue = DispatchQueue(
+ label: "com.microsoft.identity.credentialmanagement",
+ qos: .userInitiated
+ )
+
+ self.apiClient = nil
+ self.pendingEnrollmentType = nil
+
+ super.init()
+ }
+
+ // MARK: - Public: List Credential Methods
+
+ /// Retrieve the list of credential methods registered for the current user.
+ ///
+ /// - Parameter correlationId: Optional correlation ID for request tracing. A new UUID is generated if nil.
+ /// - Returns: A `Result` containing the array of credential methods or an error.
+ public func listCredentialMethods(
+ correlationId: UUID? = nil
+ ) async -> Result<[any MSALCredentialMethodProtocol], MSALNativeCredentialManagementError>
+ {
+ let correlationId = correlationId ?? UUID()
+
+ MSIDLogger.shared().log(level: .info, correlationId: correlationId, message: "listCredentialMethods: starting")
+
+ let tokenResult = await acquireTokenAsync(correlationId: correlationId)
+ guard case .success(let accessToken) = tokenResult else
+ {
+ return .failure({ if case .failure(let e) = tokenResult { return e }; fatalError("Unreachable") }())
+ }
+
+ switch getAPIClient()
+ {
+ case .failure(let error):
+ return .failure(error)
+ case .success(let client):
+ return await client.listMethods(
+ accessToken: accessToken,
+ correlationId: correlationId
+ )
+ }
+ }
+
+ // MARK: - Public: Register Operations
+
+ /// Namespace grouping for method-specific registration flows.
+ ///
+ /// Each credential type has its own function because registration inputs
+ /// and activation flows differ per type.
+ ///
+ /// Usage:
+ /// ```swift
+ /// let params = MSALRegisterPasskeyParams(presentationAnchor: window, displayName: "My Key")
+ /// let result = await client.register.passkey(params: params)
+ /// // All register methods return Result
+ /// let result = await client.register.phoneNumber(params: MSALRegisterPhoneNumberParams(phoneNumber: "+1234567890"))
+ /// let result = await client.register.password(params: MSALRegisterPasswordParams(password: "secret"))
+ /// ```
+ public private(set) lazy var register: MSALRegisterMethods = MSALRegisterMethods(client: self)
+
+ // MARK: - Public: Delete Credential Method
+
+ /// Delete a credential method.
+ ///
+ /// - Parameter credentialMethod: The credential method to remove.
+ /// - Parameter correlationId: Optional correlation ID for request tracing. A new UUID is generated if nil.
+ /// - Returns: A `Result` indicating success or containing an error.
+ public func deleteCredentialMethod(
+ _ credentialMethod: any MSALCredentialMethodProtocol,
+ correlationId: UUID? = nil
+ ) async -> Result
+ {
+ let correlationId = correlationId ?? UUID()
+
+ MSIDLogger.shared().log(
+ level: .info,
+ correlationId: correlationId,
+ message: "deleteCredentialMethod: type=\(credentialMethod.credentialType.rawValue)"
+ )
+
+ let tokenResult = await acquireTokenAsync(correlationId: correlationId)
+ guard case .success(let accessToken) = tokenResult else
+ {
+ return .failure({ if case .failure(let e) = tokenResult { return e }; fatalError("Unreachable") }())
+ }
+
+ switch getAPIClient()
+ {
+ case .failure(let error):
+ return .failure(error)
+ case .success(let client):
+ return await client.deleteMethod(
+ type: credentialMethod.credentialType,
+ methodId: credentialMethod.id,
+ accessToken: accessToken,
+ correlationId: correlationId
+ )
+ }
+ }
+
+ // MARK: - Internal: Properties (accessible by extensions)
+
+ internal let config: MSALNativeCredentialManagementConfig
+ internal let operationQueue: DispatchQueue
+ internal var apiClient: (any CredentialManagementNetworkClientProtocol)?
+ internal var pendingEnrollmentType: MSALCredentialType?
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/MSALRegisterMethods.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/MSALRegisterMethods.swift
new file mode 100644
index 0000000000..3eeef7b9d0
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/MSALRegisterMethods.swift
@@ -0,0 +1,46 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+/// Namespace for credential method registration operations.
+///
+/// Access via `client.register.passkey(...)`, `client.register.phoneNumber(...)`,
+/// or `client.register.password(...)`.
+///
+/// Each credential type adds its registration method via an extension in its
+/// own folder under `credential_method//`. This follows the Open/Closed
+/// Principle — adding a new credential type requires only new files, without
+/// modifying existing code.
+public class MSALRegisterMethods
+{
+ // MARK: - Internal
+
+ internal weak var client: MSALNativeCredentialMethodsClient?
+
+ internal init(client: MSALNativeCredentialMethodsClient)
+ {
+ self.client = client
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/MSALRegisterParams.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/MSALRegisterParams.swift
new file mode 100644
index 0000000000..d280c6e719
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/MSALRegisterParams.swift
@@ -0,0 +1,46 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+/// Base class for all credential method registration parameters.
+///
+/// Subclasses add credential-specific fields (e.g., display name, phone number, password).
+@objcMembers
+public class MSALRegisterParams: NSObject
+{
+ /// Optional correlation ID for request tracing. A new UUID is generated if nil.
+ public var correlationId: UUID?
+
+ public override init()
+ {
+ super.init()
+ }
+
+ public init(correlationId: UUID?)
+ {
+ self.correlationId = correlationId
+ super.init()
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/credential_method/MSALCredentialMethodProtocol.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/credential_method/MSALCredentialMethodProtocol.swift
new file mode 100644
index 0000000000..4388237899
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/credential_method/MSALCredentialMethodProtocol.swift
@@ -0,0 +1,46 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+// MARK: - Protocol
+
+/// Protocol defining the contract for all credential method types.
+///
+/// All credential method classes must conform to this protocol.
+/// Use this protocol when you need to work with credential methods generically.
+public protocol MSALCredentialMethodProtocol: AnyObject {
+
+ /// Unique identifier of the credential method.
+ var id: String { get }
+
+ /// The type identifier (e.g., `.passkey`, `.phone`, `.password`).
+ var credentialType: MSALCredentialType { get }
+
+ /// Display-friendly name or hint (e.g., masked phone "+1 ***-***-1234").
+ var displayName: String? { get }
+
+ /// Timestamp of when this method was registered.
+ var createdAt: Date? { get }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/credential_method/MSALCredentialType.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/credential_method/MSALCredentialType.swift
new file mode 100644
index 0000000000..43aff303d5
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/credential_method/MSALCredentialType.swift
@@ -0,0 +1,51 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+/// A type-safe, extensible identifier for credential method types.
+///
+/// New credential types are defined by adding a `static let` extension
+/// in the corresponding credential class file — no central registry needed.
+///
+/// Example (in a new credential file):
+/// ```swift
+/// extension MSALCredentialType {
+/// public static let myNewType = MSALCredentialType("myNewType")
+/// }
+/// ```
+public struct MSALCredentialType: RawRepresentable, Hashable, Sendable {
+
+ public let rawValue: String
+
+ public init(rawValue: String)
+ {
+ self.rawValue = rawValue
+ }
+
+ public init(_ rawValue: String)
+ {
+ self.rawValue = rawValue
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/credential_method/passkey/MSALPasskeyCredentialMethod.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/credential_method/passkey/MSALPasskeyCredentialMethod.swift
new file mode 100644
index 0000000000..14bebcd3cd
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/credential_method/passkey/MSALPasskeyCredentialMethod.swift
@@ -0,0 +1,76 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+extension MSALCredentialType {
+ /// Passkey (FIDO2/WebAuthn) credential type.
+ public static let passkey = MSALCredentialType("fido")
+}
+
+/// Represents a passkey (FIDO2/WebAuthn) credential method.
+@objcMembers
+public class MSALPasskeyCredentialMethod: MSALCredentialMethod {
+
+ /// The base64-encoded credential ID from WebAuthn registration.
+ public let credentialID: String?
+
+ /// The AAGUID of the authenticator that created this passkey.
+ public let aaguid: String?
+
+ public init(
+ displayName: String?,
+ credentialID: String?,
+ aaguid: String? = nil
+ )
+ {
+ self.credentialID = credentialID
+ self.aaguid = aaguid
+ super.init(
+ id: "",
+ credentialType: .passkey,
+ displayName: displayName,
+ createdAt: nil
+ )
+ }
+
+ /// Internal initializer used by the SDK when hydrating from server responses.
+ internal init(
+ id: String,
+ displayName: String?,
+ createdAt: Date?,
+ credentialID: String?,
+ aaguid: String? = nil
+ )
+ {
+ self.credentialID = credentialID
+ self.aaguid = aaguid
+ super.init(
+ id: id,
+ credentialType: .passkey,
+ displayName: displayName,
+ createdAt: createdAt
+ )
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/credential_method/passkey/MSALRegisterMethods+Passkey.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/credential_method/passkey/MSALRegisterMethods+Passkey.swift
new file mode 100644
index 0000000000..b129540131
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/credential_method/passkey/MSALRegisterMethods+Passkey.swift
@@ -0,0 +1,69 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+extension MSALRegisterMethods
+{
+ /// Registers a new passkey (FIDO2/WebAuthn) credential.
+ ///
+ /// This single call handles the entire flow:
+ /// 1. Requests creation options from the server.
+ /// 2. Presents the system passkey sheet to the user.
+ /// 3. Submits the attestation back to the server.
+ ///
+ /// - Parameter params: Parameters including the presentation anchor and optional display name.
+ /// - Returns: A `Result` containing the registration result or an error.
+ ///
+ /// Example:
+ /// ```swift
+ /// let params = MSALRegisterPasskeyParams(
+ /// presentationAnchor: view.window!,
+ /// displayName: "My iPhone"
+ /// )
+ /// let result = await client.register.passkey(params: params)
+ /// switch result {
+ /// case .success(.completed(let method)):
+ /// print("Registered: \(method.id)")
+ /// case .failure(let error):
+ /// print("Failed: \(error.message ?? "")")
+ /// }
+ /// ```
+ public func passkey(
+ params: MSALRegisterPasskeyParams
+ ) async -> Result
+ {
+ guard let client = client else
+ {
+ let error = MSALNativeCredentialManagementError(
+ type: .generalError,
+ message: "Client was deallocated.",
+ correlationId: params.correlationId ?? UUID()
+ )
+ return .failure(error)
+ }
+
+ return await client.performRegisterPasskey(params: params)
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/credential_method/passkey/MSALRegisterPasskeyParams.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/credential_method/passkey/MSALRegisterPasskeyParams.swift
new file mode 100644
index 0000000000..84946af89d
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/credential_method/passkey/MSALRegisterPasskeyParams.swift
@@ -0,0 +1,61 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import AuthenticationServices
+#if os(macOS)
+import AppKit
+#else
+import UIKit
+#endif
+
+/// Parameters for `client.register.passkey()`.
+///
+/// The `presentationAnchor` is required — it provides the window in which the system
+/// passkey sheet is presented.
+@objcMembers
+public class MSALRegisterPasskeyParams: MSALRegisterParams
+{
+ /// The window used to present the passkey authorization sheet.
+ public var presentationAnchor: ASPresentationAnchor
+
+ /// Optional human-readable label for the passkey (e.g. "Work YubiKey").
+ public var displayName: String?
+
+ /// Creates passkey registration parameters.
+ ///
+ /// - Parameters:
+ /// - presentationAnchor: The window that will present the system passkey UI.
+ /// - displayName: Optional friendly name for the passkey.
+ /// - correlationId: Optional correlation ID for logging/diagnostics.
+ public init(
+ presentationAnchor: ASPresentationAnchor,
+ displayName: String? = nil,
+ correlationId: UUID? = nil
+ )
+ {
+ self.presentationAnchor = presentationAnchor
+ self.displayName = displayName
+ super.init(correlationId: correlationId)
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/credential_method/password/MSALPasswordCredentialMethod.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/credential_method/password/MSALPasswordCredentialMethod.swift
new file mode 100644
index 0000000000..a570cf1ac8
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/credential_method/password/MSALPasswordCredentialMethod.swift
@@ -0,0 +1,59 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+extension MSALCredentialType {
+ /// Password credential type.
+ public static let password = MSALCredentialType("password")
+}
+
+/// Represents a password credential method.
+@objcMembers
+public class MSALPasswordCredentialMethod: MSALCredentialMethod {
+
+ public init()
+ {
+ super.init(
+ id: "",
+ credentialType: .password,
+ displayName: nil,
+ createdAt: nil
+ )
+ }
+
+ /// Internal initializer used by the SDK when hydrating from server responses.
+ internal init(
+ id: String,
+ createdAt: Date?
+ )
+ {
+ super.init(
+ id: id,
+ credentialType: .password,
+ displayName: nil,
+ createdAt: createdAt
+ )
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/credential_method/password/MSALRegisterMethods+Password.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/credential_method/password/MSALRegisterMethods+Password.swift
new file mode 100644
index 0000000000..dd1efcc895
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/credential_method/password/MSALRegisterMethods+Password.swift
@@ -0,0 +1,49 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+extension MSALRegisterMethods
+{
+ /// Registers a password. Typically completes in a single step (no activation needed).
+ ///
+ /// - Parameter params: Parameters including the password value and optional correlation ID.
+ /// - Returns: A `Result` containing the registration outcome or an error.
+ public func password(
+ params: MSALRegisterPasswordParams
+ ) async -> Result
+ {
+ guard let client = client else
+ {
+ let error = MSALNativeCredentialManagementError(
+ type: .generalError,
+ message: "Client was deallocated.",
+ correlationId: params.correlationId ?? UUID()
+ )
+ return .failure(error)
+ }
+
+ return await client.performRegisterPassword(params: params)
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/credential_method/password/MSALRegisterPasswordParams.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/credential_method/password/MSALRegisterPasswordParams.swift
new file mode 100644
index 0000000000..73eb487c7f
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/credential_method/password/MSALRegisterPasswordParams.swift
@@ -0,0 +1,39 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+/// Parameters for `client.register.password()`.
+@objcMembers
+public class MSALRegisterPasswordParams: MSALRegisterParams
+{
+ /// The password value to register.
+ public var password: String
+
+ public init(password: String, correlationId: UUID? = nil)
+ {
+ self.password = password
+ super.init(correlationId: correlationId)
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/credential_method/phone/MSALPhoneCredentialMethod.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/credential_method/phone/MSALPhoneCredentialMethod.swift
new file mode 100644
index 0000000000..4ffabe04c7
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/credential_method/phone/MSALPhoneCredentialMethod.swift
@@ -0,0 +1,65 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+extension MSALCredentialType {
+ /// Phone number credential type (SMS or voice call OTP).
+ public static let phone = MSALCredentialType("phone")
+}
+
+/// Represents a phone number credential method (SMS or voice call OTP).
+@objcMembers
+public class MSALPhoneCredentialMethod: MSALCredentialMethod {
+
+ /// The masked phone number (e.g., "+1 ***-***-1234").
+ public let phoneNumber: String?
+
+ public init(phoneNumber: String?)
+ {
+ self.phoneNumber = phoneNumber
+ super.init(
+ id: "",
+ credentialType: .phone,
+ displayName: phoneNumber,
+ createdAt: nil
+ )
+ }
+
+ /// Internal initializer used by the SDK when hydrating from server responses.
+ internal init(
+ id: String,
+ createdAt: Date?,
+ phoneNumber: String?
+ )
+ {
+ self.phoneNumber = phoneNumber
+ super.init(
+ id: id,
+ credentialType: .phone,
+ displayName: phoneNumber,
+ createdAt: createdAt
+ )
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/credential_method/phone/MSALRegisterMethods+Phone.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/credential_method/phone/MSALRegisterMethods+Phone.swift
new file mode 100644
index 0000000000..e3600e051b
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/credential_method/phone/MSALRegisterMethods+Phone.swift
@@ -0,0 +1,49 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+extension MSALRegisterMethods
+{
+ /// Begins phone number registration with the phone number to enroll.
+ ///
+ /// - Parameter params: Parameters including the phone number (E.164 format) and optional correlation ID.
+ /// - Returns: A `Result` containing the registration outcome (completed or challenge required) or an error.
+ public func phoneNumber(
+ params: MSALRegisterPhoneNumberParams
+ ) async -> Result
+ {
+ guard let client = client else
+ {
+ let error = MSALNativeCredentialManagementError(
+ type: .generalError,
+ message: "Client was deallocated.",
+ correlationId: params.correlationId ?? UUID()
+ )
+ return .failure(error)
+ }
+
+ return await client.performRegisterPhoneNumber(params: params)
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/credential_method/phone/MSALRegisterPhoneNumberParams.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/credential_method/phone/MSALRegisterPhoneNumberParams.swift
new file mode 100644
index 0000000000..208866b691
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/credential_method/phone/MSALRegisterPhoneNumberParams.swift
@@ -0,0 +1,39 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+/// Parameters for `client.register.phoneNumber()`.
+@objcMembers
+public class MSALRegisterPhoneNumberParams: MSALRegisterParams
+{
+ /// The phone number to enroll, in E.164 format (e.g. "+35312345678").
+ public var phoneNumber: String
+
+ public init(phoneNumber: String, correlationId: UUID? = nil)
+ {
+ self.phoneNumber = phoneNumber
+ super.init(correlationId: correlationId)
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/token_provider/MSALNativeAuthTokenProvider.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/token_provider/MSALNativeAuthTokenProvider.swift
new file mode 100644
index 0000000000..c1fa70643d
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/token_provider/MSALNativeAuthTokenProvider.swift
@@ -0,0 +1,221 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+import MSAL
+#if os(iOS)
+import UIKit
+#elseif os(macOS)
+import AppKit
+#endif
+
+/// A built-in token provider that uses MSAL's web-based interactive flow to acquire tokens.
+///
+/// On first call, it presents a web view for interactive sign-in. On subsequent calls,
+/// it attempts silent token acquisition using the cached account, falling back to interactive
+/// if the silent attempt fails with `MSALErrorInteractionRequired`.
+///
+/// Usage:
+/// ```swift
+/// let tokenProvider = try MSALNativeAuthTokenProvider(clientId: "your-client-id")
+/// credConfig.tokenProvider = tokenProvider
+/// ```
+@objcMembers
+public class MSALNativeAuthTokenProvider: NSObject, MSALNativeCredentialManagementTokenProvider {
+
+ private let application: MSALPublicClientApplication
+ private var cachedAccount: MSALAccount?
+
+ /// Initialize with a client ID. Uses the default MSAL authority.
+ ///
+ /// - Parameter clientId: The application (client) ID registered in the identity platform.
+ /// - Throws: If the MSAL configuration is invalid.
+ public init(clientId: String) throws
+ {
+ let config = MSALPublicClientApplicationConfig(clientId: clientId)
+ config.cacheConfig.keychainSharingGroup = "com.microsoft.adalcache"
+// config.sliceConfig?.dc = "ESTS-PUB-SCUS-FD000-TEST1-100"
+
+// config.authority = try MSALAuthority(url: URL(string: "https://login.microsoftonline.com/40e32adb-2fb9-4616-8604-d73950c432f1")!)
+
+ config.authority = try MSALAuthority(url: URL(string: "https://login.microsoftonline.com/common")!)
+
+
+ // Set know authoirty to skip broker and run local flow only
+ config.knownAuthorities = [config.authority]
+
+ self.application = try MSALPublicClientApplication(configuration: config)
+ super.init()
+ }
+
+ /// Retrieve an access token using MSAL web flow.
+ ///
+ /// Attempts silent acquisition first. If no cached account exists or interaction is required,
+ /// falls back to interactive web view sign-in.
+ ///
+ /// - Parameters:
+ /// - scopes: The scopes required by the credential management operation.
+ /// - completionBlock: Called with the access token on success, or nil and an error on failure.
+ public func getAccessToken(
+ scopes: [String],
+ completionBlock: @escaping MSALNativeCredentialManagementTokenCompletionBlock
+ )
+ {
+ // When mock mode is ON, return a fake token immediately without hitting the network.
+ if CredentialManagementEnvironment.isMockAPIEnabled
+ {
+ completionBlock("mock-access-token-for-testing", nil)
+ return
+ }
+
+// if let account = cachedAccount ?? (try? application.allAccounts().first)
+// {
+// acquireTokenSilent(scopes: scopes, account: account, completionBlock: completionBlock)
+// }
+// else
+// {
+ acquireTokenInteractive(scopes: scopes, completionBlock: completionBlock)
+// }
+ }
+
+ /// Clear the cached account so the next token request triggers interactive sign-in.
+ public func signOut()
+ {
+ cachedAccount = nil
+ }
+
+ // MARK: - Private
+
+ private func acquireTokenSilent(
+ scopes: [String],
+ account: MSALAccount,
+ completionBlock: @escaping MSALNativeCredentialManagementTokenCompletionBlock
+ )
+ {
+ let silentParams = MSALSilentTokenParameters(scopes: scopes, account: account)
+
+ application.acquireTokenSilent(with: silentParams) { [weak self] result, error in
+ guard let self = self else { return }
+
+ if let result = result
+ {
+ self.cachedAccount = result.account
+ completionBlock(result.accessToken, nil)
+ return
+ }
+
+ if let nsError = error as NSError?,
+ nsError.domain == MSALErrorDomain,
+ nsError.code == MSALError.interactionRequired.rawValue
+ {
+ self.acquireTokenInteractive(scopes: scopes, completionBlock: completionBlock)
+ return
+ }
+
+ let credError = MSALNativeCredentialManagementError(
+ type: .unauthorized,
+ message: "Silent token acquisition failed: \(error?.localizedDescription ?? "Unknown error")"
+ )
+ completionBlock(nil, credError)
+ }
+ }
+
+ private func acquireTokenInteractive(
+ scopes: [String],
+ completionBlock: @escaping MSALNativeCredentialManagementTokenCompletionBlock
+ )
+ {
+ DispatchQueue.main.async { [weak self] in
+ guard let self = self else { return }
+
+ guard let viewController = self.topViewController() else
+ {
+ let error = MSALNativeCredentialManagementError(
+ type: .invalidConfiguration,
+ message: "Unable to find a view controller to present the web view from."
+ )
+ completionBlock(nil, error)
+ return
+ }
+
+ #if os(iOS)
+ let webParams = MSALWebviewParameters(authPresentationViewController: viewController)
+ #elseif os(macOS)
+ let webParams = MSALWebviewParameters(authPresentationViewController: viewController)
+ webParams.webviewType = .wkWebView
+ #endif
+
+ let interactiveParams = MSALInteractiveTokenParameters(scopes: scopes, webviewParameters: webParams)
+ interactiveParams.promptType = .login
+ interactiveParams.scopes = ["api://02815c3e-3ef8-40a4-8f95-cfb184350d7e/Me.UserAuthenticationMethod.ReadWrite"]
+ interactiveParams.claimsRequest = MSALClaimsRequest(jsonString: "{\"access_token\":{\"acrs\":{\"essential\":true,\"values\":[\"urn:user:registersecurityinfo\"]},\"amr\":{\"essential\":true,\"values\":[\"ngcmfa\"]}}}", error: nil)
+
+// parameters.claimsRequest = [[MSALClaimsRequest alloc] initWithJsonString:kDeviceIdClaimsValue error:nil];
+
+ self.application.acquireToken(with: interactiveParams) { [weak self] result, error in
+ guard let self = self else { return }
+
+ if let result = result
+ {
+ self.cachedAccount = result.account
+ completionBlock(result.accessToken, nil)
+ return
+ }
+
+ let credError = MSALNativeCredentialManagementError(
+ type: .unauthorized,
+ message: "Interactive sign-in failed: \(error?.localizedDescription ?? "Unknown error")"
+ )
+ completionBlock(nil, credError)
+ }
+ }
+ }
+
+ #if os(iOS)
+ private func topViewController() -> UIViewController?
+ {
+ guard let scene = UIApplication.shared.connectedScenes
+ .compactMap({ $0 as? UIWindowScene })
+ .first(where: { $0.activationState == .foregroundActive }),
+ let rootVC = scene.windows.first(where: { $0.isKeyWindow })?.rootViewController
+ else
+ {
+ return nil
+ }
+
+ var top = rootVC
+ while let presented = top.presentedViewController
+ {
+ top = presented
+ }
+ return top
+ }
+ #elseif os(macOS)
+ private func topViewController() -> NSViewController?
+ {
+ return NSApplication.shared.keyWindow?.contentViewController
+ }
+ #endif
+}
+
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/token_provider/MSALNativeCredentialManagementTokenProvider.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/token_provider/MSALNativeCredentialManagementTokenProvider.swift
new file mode 100644
index 0000000000..a85693002a
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagment/src/public/token_provider/MSALNativeCredentialManagementTokenProvider.swift
@@ -0,0 +1,50 @@
+//
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+/// Completion block type for token retrieval.
+public typealias MSALNativeCredentialManagementTokenCompletionBlock = @convention(block) (String?, Error?) -> Void
+
+/// Protocol for providing access tokens to the credential management client.
+///
+/// Implement this protocol to supply access tokens for credential management API calls.
+/// - P0: Provide a custom implementation that calls your own backend.
+/// - P1: Use the built-in `MSALNativeAuthTokenProvider` that wraps MSAL Native Auth.
+@objc public protocol MSALNativeCredentialManagementTokenProvider: NSObjectProtocol {
+
+ /// Retrieve an access token suitable for calling the credential management API.
+ ///
+ /// - Important: `completionBlock` **must always be called**, regardless of whether a token is available.
+ /// - On success, call `completionBlock(accessToken, nil)`.
+ /// - On failure, call `completionBlock(nil, error)`.
+ ///
+ /// - Parameters:
+ /// - scopes: The scopes required by the credential management operation.
+ /// - completionBlock: Must be called with an access token string on success, or nil and an error on failure.
+ func getAccessToken(
+ scopes: [String],
+ completionBlock: @escaping MSALNativeCredentialManagementTokenCompletionBlock
+ )
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentSampleApp/Assets.xcassets/AccentColor.colorset/Contents.json b/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentSampleApp/Assets.xcassets/AccentColor.colorset/Contents.json
new file mode 100644
index 0000000000..eb87897008
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentSampleApp/Assets.xcassets/AccentColor.colorset/Contents.json
@@ -0,0 +1,11 @@
+{
+ "colors" : [
+ {
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentSampleApp/Assets.xcassets/AppIcon.appiconset/Contents.json b/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentSampleApp/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000000..ffdfe150be
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentSampleApp/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,85 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "platform" : "ios",
+ "size" : "1024x1024"
+ },
+ {
+ "appearances" : [
+ {
+ "appearance" : "luminosity",
+ "value" : "dark"
+ }
+ ],
+ "idiom" : "universal",
+ "platform" : "ios",
+ "size" : "1024x1024"
+ },
+ {
+ "appearances" : [
+ {
+ "appearance" : "luminosity",
+ "value" : "tinted"
+ }
+ ],
+ "idiom" : "universal",
+ "platform" : "ios",
+ "size" : "1024x1024"
+ },
+ {
+ "idiom" : "mac",
+ "scale" : "1x",
+ "size" : "16x16"
+ },
+ {
+ "idiom" : "mac",
+ "scale" : "2x",
+ "size" : "16x16"
+ },
+ {
+ "idiom" : "mac",
+ "scale" : "1x",
+ "size" : "32x32"
+ },
+ {
+ "idiom" : "mac",
+ "scale" : "2x",
+ "size" : "32x32"
+ },
+ {
+ "idiom" : "mac",
+ "scale" : "1x",
+ "size" : "128x128"
+ },
+ {
+ "idiom" : "mac",
+ "scale" : "2x",
+ "size" : "128x128"
+ },
+ {
+ "idiom" : "mac",
+ "scale" : "1x",
+ "size" : "256x256"
+ },
+ {
+ "idiom" : "mac",
+ "scale" : "2x",
+ "size" : "256x256"
+ },
+ {
+ "idiom" : "mac",
+ "scale" : "1x",
+ "size" : "512x512"
+ },
+ {
+ "idiom" : "mac",
+ "scale" : "2x",
+ "size" : "512x512"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentSampleApp/Assets.xcassets/Contents.json b/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentSampleApp/Assets.xcassets/Contents.json
new file mode 100644
index 0000000000..73c00596a7
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentSampleApp/Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentSampleApp/Configuration.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentSampleApp/Configuration.swift
new file mode 100644
index 0000000000..bd2ad85283
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentSampleApp/Configuration.swift
@@ -0,0 +1,18 @@
+//
+// Configuration.swift
+// MSALNativeCredManagmentSampleApp
+//
+// Created by Serhii Demchenko on 2026-05-27.
+//
+
+import Foundation
+
+/// Sample app configuration.
+/// Replace these values with your own CIAM tenant settings.
+enum Configuration {
+ /// The client ID of the application registered in the CIAM tenant.
+ static let clientId = "6d0926a3-67d7-45b7-b429-9c25b0a699f7"
+
+ /// The tenant subdomain (e.g., "contoso" for contoso.ciamlogin.com).
+ static let tenantSubdomain = "Enter_the_Tenant_Subdomain_Here"
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentSampleApp/ContentView.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentSampleApp/ContentView.swift
new file mode 100644
index 0000000000..2113257bf6
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentSampleApp/ContentView.swift
@@ -0,0 +1,293 @@
+//
+// ContentView.swift
+// MSALNativeCredManagmentSampleApp
+//
+// Created by Serhii Demchenko on 2026-05-27.
+//
+
+import SwiftUI
+import MSALNativeCredManagment
+
+struct ContentView: View {
+
+ @EnvironmentObject var viewModel: CredentialManagementViewModel
+
+ @State private var email = ""
+ @State private var password = ""
+ @State private var newCredentialType = "phone"
+ @State private var newCredentialValue = ""
+ @State private var challengeCode = ""
+
+ var body: some View {
+ NavigationStack {
+ Group {
+ if viewModel.isSignedIn {
+ signedInView
+ } else {
+ signInView
+ }
+ }
+ .navigationTitle("Cred Management")
+ .overlay {
+ if viewModel.isLoading {
+ ProgressView()
+ .scaleEffect(1.5)
+ .frame(maxWidth: .infinity, maxHeight: .infinity)
+ .background(Color.black.opacity(0.2))
+ }
+ }
+ .alert("Error", isPresented: .constant(viewModel.errorMessage != nil)) {
+ Button("OK") { viewModel.errorMessage = nil }
+ } message: {
+ Text(viewModel.errorMessage ?? "")
+ }
+ .sheet(isPresented: $viewModel.showChallengeInput) {
+ challengeView
+ }
+ }
+ }
+
+ // MARK: - Challenge View
+
+ private var challengeView: some View {
+ NavigationStack {
+ VStack(spacing: 20) {
+ Image(systemName: "lock.shield")
+ .font(.system(size: 50))
+ .foregroundStyle(.orange)
+
+ Text("Verification Required")
+ .font(.title2)
+ .bold()
+
+ Text("A code was sent to \(viewModel.challengeHint). Enter it below to complete registration.")
+ .multilineTextAlignment(.center)
+ .foregroundStyle(.secondary)
+
+ TextField("Verification Code", text: $challengeCode)
+ .textFieldStyle(.roundedBorder)
+ #if os(iOS)
+ .keyboardType(.numberPad)
+ #endif
+ .multilineTextAlignment(.center)
+ .font(.title3)
+
+ Button("Verify") {
+ viewModel.submitChallenge(code: challengeCode)
+ challengeCode = ""
+ }
+ .buttonStyle(.borderedProminent)
+ .disabled(challengeCode.isEmpty)
+ }
+ .padding()
+ .navigationTitle("Verify")
+ #if os(iOS)
+ .navigationBarTitleDisplayMode(.inline)
+ #endif
+ .toolbar {
+ ToolbarItem(placement: .cancellationAction) {
+ Button("Cancel") {
+ viewModel.showChallengeInput = false
+ challengeCode = ""
+ }
+ }
+ }
+ }
+ }
+
+ // MARK: - Sign In View
+
+ private var signInView: some View {
+ VStack(spacing: 20) {
+ Image(systemName: "person.badge.key")
+ .font(.system(size: 60))
+ .foregroundStyle(.blue)
+
+ Text("Sign in to manage credentials")
+ .font(.headline)
+
+ // API mode toggle
+ Toggle(isOn: $viewModel.useMockAPI) {
+ HStack {
+ Image(systemName: viewModel.useMockAPI ? "server.rack" : "globe")
+ Text(viewModel.useMockAPI ? "Mock API" : "Real Server")
+ .font(.subheadline)
+ }
+ }
+ .padding(.horizontal)
+
+ TextField("Email", text: $email)
+ .textFieldStyle(.roundedBorder)
+ .textContentType(.emailAddress)
+ #if os(iOS)
+ .autocapitalization(.none)
+ #endif
+
+ SecureField("Password", text: $password)
+ .textFieldStyle(.roundedBorder)
+ .textContentType(.password)
+
+ Button("Sign In") {
+ viewModel.signIn(email: email, password: password)
+ }
+ .buttonStyle(.borderedProminent)
+ .disabled(email.isEmpty || password.isEmpty)
+
+ if !viewModel.statusMessage.isEmpty {
+ Text(viewModel.statusMessage)
+ .font(.caption)
+ .foregroundStyle(.secondary)
+ }
+ }
+ .padding()
+ }
+
+ // MARK: - Signed In View
+
+ private var signedInView: some View {
+ VStack(spacing: 16) {
+ // User info header
+ HStack {
+ VStack(alignment: .leading) {
+ Text("Signed in as")
+ .font(.caption)
+ .foregroundStyle(.secondary)
+ Text(viewModel.userName)
+ .font(.headline)
+ }
+ Spacer()
+ Button("Sign Out") {
+ viewModel.signOut()
+ }
+ .buttonStyle(.bordered)
+ .tint(.red)
+ }
+ .padding(.horizontal)
+
+ // API mode toggle
+ Toggle(isOn: $viewModel.useMockAPI) {
+ HStack {
+ Image(systemName: viewModel.useMockAPI ? "server.rack" : "globe")
+ Text(viewModel.useMockAPI ? "Mock API" : "Real Server")
+ .font(.subheadline)
+ }
+ }
+ .padding(.horizontal)
+
+ Divider()
+
+ // Status
+ if !viewModel.statusMessage.isEmpty {
+ Text(viewModel.statusMessage)
+ .font(.caption)
+ .foregroundStyle(.secondary)
+ .padding(.horizontal)
+ }
+
+ // Credential methods list
+ List {
+ Section("Registered Methods") {
+ if viewModel.credentialMethods.isEmpty {
+ Text("No credential methods found.")
+ .foregroundStyle(.secondary)
+ } else {
+ ForEach(viewModel.credentialMethods, id: \.id) { method in
+ credentialMethodRow(method)
+ }
+ }
+ }
+
+ Section("Add New Method") {
+ Picker("Type", selection: $newCredentialType) {
+ Text("Phone").tag("phone")
+ Text("Passkey").tag("passkey")
+ Text("Password").tag("password")
+ }
+
+ if newCredentialType == "password" {
+ SecureField("Password", text: $newCredentialValue)
+ .textFieldStyle(.roundedBorder)
+ } else {
+ TextField(newCredentialType == "passkey" ? "Passkey name" : "Phone number", text: $newCredentialValue)
+ .textFieldStyle(.roundedBorder)
+ }
+
+ Button("Register") {
+ switch newCredentialType {
+ case "passkey":
+ viewModel.registerPasskey(displayName: newCredentialValue.isEmpty ? nil : newCredentialValue)
+ case "password":
+ viewModel.registerPassword(password: newCredentialValue)
+ default:
+ viewModel.registerPhone(phoneNumber: newCredentialValue)
+ }
+ newCredentialValue = ""
+ }
+ .disabled(
+ (newCredentialType == "phone" && newCredentialValue.isEmpty) ||
+ (newCredentialType == "password" && newCredentialValue.isEmpty)
+ )
+ }
+ }
+ .refreshable {
+ viewModel.listCredentialMethods()
+ }
+ }
+ .onAppear {
+ viewModel.listCredentialMethods()
+ }
+ }
+
+ // MARK: - Credential Method Row
+
+ private func credentialMethodRow(_ method: MSALCredentialMethod) -> some View {
+ HStack {
+ VStack(alignment: .leading, spacing: 4) {
+ Text(method.credentialType.rawValue.capitalized)
+ .font(.subheadline)
+ .bold()
+ if method.credentialType == .password, let createdAt = method.createdAt {
+ Text("Last updated: \(relativeTimeString(from: createdAt))")
+ .font(.caption)
+ .foregroundStyle(.secondary)
+ } else if method.credentialType == .phone,
+ let phone = (method as? MSALPhoneCredentialMethod)?.phoneNumber {
+ Text(phone)
+ .font(.caption)
+ .foregroundStyle(.secondary)
+ } else if method.credentialType == .passkey,
+ let name = (method as? MSALPasskeyCredentialMethod)?.displayName {
+ Text(name)
+ .font(.caption)
+ .foregroundStyle(.secondary)
+ } else if let displayName = method.displayName {
+ Text(displayName)
+ .font(.caption)
+ .foregroundStyle(.secondary)
+ }
+ }
+ Spacer()
+ Button(role: .destructive) {
+ viewModel.deleteCredentialMethod(method)
+ } label: {
+ Image(systemName: "trash")
+ }
+ .buttonStyle(.borderless)
+ }
+ }
+
+ private func relativeTimeString(from date: Date) -> String {
+ let formatter = RelativeDateTimeFormatter()
+ formatter.unitsStyle = .full
+ return formatter.localizedString(for: date, relativeTo: Date())
+ }
+
+ // MARK: - Challenge Verification View
+
+}
+
+#Preview {
+ ContentView()
+ .environmentObject(CredentialManagementViewModel())
+}
+
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentSampleApp/CredentialManagementViewModel.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentSampleApp/CredentialManagementViewModel.swift
new file mode 100644
index 0000000000..10aba4cc92
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentSampleApp/CredentialManagementViewModel.swift
@@ -0,0 +1,289 @@
+//
+// CredentialManagementViewModel.swift
+// MSALNativeCredManagmentSampleApp
+//
+// Created by Serhii Demchenko on 2026-05-27.
+//
+
+import Foundation
+import MSAL
+import MSALNativeCredManagment
+import SwiftUI
+import AuthenticationServices
+#if os(macOS)
+import AppKit
+#else
+import UIKit
+#endif
+
+/// Main view model that demonstrates the credential management SDK integration.
+@MainActor
+class CredentialManagementViewModel: ObservableObject {
+
+ // MARK: - Published State
+
+ @Published var isSignedIn = false
+ @Published var userName: String = ""
+ @Published var credentialMethods: [MSALCredentialMethod] = []
+ @Published var isLoading = false
+ @Published var statusMessage: String = ""
+ @Published var errorMessage: String?
+
+ // Challenge state
+ @Published var showChallengeInput = false
+ @Published var challengeHint: String = ""
+
+ // Toggle: real server vs mock (backed by UserDefaults — SDK reads this internally)
+ @Published var useMockAPI: Bool = UserDefaults.standard.bool(
+ forKey: "com.microsoft.identity.credentialmanagement.useMockAPI"
+ ) {
+ didSet {
+ UserDefaults.standard.set(useMockAPI, forKey: "com.microsoft.identity.credentialmanagement.useMockAPI")
+ // Invalidate cached client so next call picks up new mode
+ credClient = nil
+ reinitializeClient()
+ }
+ }
+
+ // MARK: - Private Properties
+
+ private var credClient: MSALNativeCredentialMethodsClient?
+ private var tokenProvider: MSALNativeAuthTokenProvider?
+ private var pendingChallengeState: MSALCredentialMethodChallengeState?
+
+ // MARK: - Initialization
+
+ func initialize() {
+ reinitializeClient()
+ }
+
+ /// Sign in using MSAL interactive web flow. Email/password are passed as login hints.
+ func signIn(email: String, password: String) {
+ reinitializeClient()
+ }
+ private func reinitializeClient() {
+ do {
+ // 1. Configure shared logger (used by both MSAL and Credential Management)
+ MSALGlobalConfig.loggerConfig.logLevel = .verbose
+ MSALGlobalConfig.loggerConfig.setLogCallback { _, message, containsPII in
+ if !containsPII {
+ print("MSAL: \(message ?? "")")
+ }
+ }
+
+ // 2. Create token provider using MSAL web flow
+ let msalTokenProvider = try MSALNativeAuthTokenProvider(
+ clientId: Configuration.clientId
+ )
+ self.tokenProvider = msalTokenProvider
+
+ // 3. Create shared request interceptor
+ let sharedRequestInterceptor = SampleRequestInterceptor()
+
+ // 4. Initialize Credential Management Client
+ let credConfig = MSALNativeCredentialManagementConfig()
+ credConfig.requestInterceptor = sharedRequestInterceptor
+ credConfig.tokenProvider = msalTokenProvider
+ credConfig.tenantSubdomain = Configuration.tenantSubdomain
+
+ credClient = try MSALNativeCredentialMethodsClient(config: credConfig)
+
+ let mode = useMockAPI ? "Mock API (UserDefaults)" : "Real Server"
+ statusMessage = "SDK initialized (\(mode))."
+ isSignedIn = true
+ } catch {
+ errorMessage = "Failed to initialize: \(error.localizedDescription)"
+ }
+ }
+
+ // MARK: - Credential Management Operations
+
+ func listCredentialMethods() {
+ guard let credClient = credClient else {
+ errorMessage = "Credential client not initialized."
+ return
+ }
+
+ isLoading = true
+ statusMessage = "Loading credential methods..."
+ errorMessage = nil
+
+ Task {
+ let result = await credClient.listCredentialMethods()
+ switch result {
+ case .success(let methods):
+ isLoading = false
+ credentialMethods = methods.compactMap { $0 as? MSALCredentialMethod }
+ statusMessage = "Loaded \(methods.count) credential method(s)."
+ case .failure(let error):
+ isLoading = false
+ errorMessage = "List failed: \(error.message ?? "Unknown error")"
+ }
+ }
+ }
+
+ // MARK: - Register Phone
+
+ func registerPhone(phoneNumber: String) {
+ guard let credClient = credClient else {
+ errorMessage = "Credential client not initialized."
+ return
+ }
+
+ isLoading = true
+ statusMessage = "Registering phone..."
+ errorMessage = nil
+
+ let params = MSALRegisterPhoneNumberParams(phoneNumber: phoneNumber)
+
+ Task {
+ let result = await credClient.register.phoneNumber(params: params)
+ handleRegistrationResult(result)
+ }
+ }
+
+ // MARK: - Register Password
+
+ func registerPassword(password: String) {
+ guard let credClient = credClient else {
+ errorMessage = "Credential client not initialized."
+ return
+ }
+ guard !password.isEmpty else {
+ errorMessage = "Password cannot be empty."
+ return
+ }
+ isLoading = true
+ statusMessage = "Registering password..."
+ errorMessage = nil
+
+ let params = MSALRegisterPasswordParams(password: password)
+
+ Task {
+ let result = await credClient.register.password(params: params)
+ handleRegistrationResult(result)
+ }
+ }
+
+ // MARK: - Register Passkey
+
+ func registerPasskey(displayName: String? = nil) {
+ guard let credClient = self.credClient else { return }
+ isLoading = true
+
+ Task { @MainActor in
+ guard let anchor = Self.resolveAnchor() else
+ {
+ self.isLoading = false
+ self.errorMessage = "No window available."
+ return
+ }
+
+ let params = MSALRegisterPasskeyParams(
+ presentationAnchor: anchor,
+ displayName: displayName
+ )
+
+ let result = await credClient.register.passkey(params: params)
+ handleRegistrationResult(result)
+ }
+ }
+
+ private static func resolveAnchor() -> ASPresentationAnchor?
+ {
+ #if os(macOS)
+ return NSApplication.shared.keyWindow
+ #else
+ return UIApplication.shared.connectedScenes
+ .compactMap { $0 as? UIWindowScene }
+ .flatMap { $0.windows }
+ .first(where: { $0.isKeyWindow })
+ #endif
+ }
+
+ func submitChallenge(code: String) {
+ guard let state = pendingChallengeState else {
+ errorMessage = "No pending challenge."
+ return
+ }
+
+ isLoading = true
+ statusMessage = "Verifying code..."
+ showChallengeInput = false
+
+ Task {
+ let result = await state.submitChallenge(code: code)
+ switch result {
+ case .success(let method):
+ isLoading = false
+ pendingChallengeState = nil
+ statusMessage = "Registered \(method.credentialType.rawValue) successfully."
+ listCredentialMethods()
+ case .failure(let error):
+ isLoading = false
+ errorMessage = "Verification failed: \(error.message ?? "Unknown error")"
+ }
+ }
+ }
+
+ func deleteCredentialMethod(_ method: MSALCredentialMethod) {
+ guard let credClient = credClient else {
+ errorMessage = "Credential client not initialized."
+ return
+ }
+
+ isLoading = true
+ statusMessage = "Deleting credential method..."
+ errorMessage = nil
+
+ Task {
+ let result = await credClient.deleteCredentialMethod(method)
+ switch result {
+ case .success:
+ isLoading = false
+ statusMessage = "Credential method deleted."
+ listCredentialMethods()
+ case .failure(let error):
+ isLoading = false
+ errorMessage = "Delete failed: \(error.message ?? "Unknown error")"
+ }
+ }
+ }
+
+ // MARK: - Sign Out
+
+ func signOut() {
+ tokenProvider?.signOut()
+ isSignedIn = false
+ userName = ""
+ credentialMethods = []
+ statusMessage = "Signed out."
+ }
+
+ // MARK: - Private Helpers
+
+ private func handleRegistrationResult(
+ _ result: Result
+ ) {
+ switch result {
+ case .success(let registrationResult):
+ switch registrationResult {
+ case .completed(let method):
+ isLoading = false
+ statusMessage = "Registered \(method.credentialType.rawValue) successfully."
+ listCredentialMethods()
+ case .challengeRequired(let state):
+ isLoading = false
+ pendingChallengeState = state
+ challengeHint = state.sentTo ?? "your registered contact"
+ showChallengeInput = true
+ statusMessage = "Verification code sent to \(challengeHint)."
+ }
+ case .failure(let error):
+ isLoading = false
+ errorMessage = "Registration failed: \(error.message ?? "Unknown error")"
+ }
+ }
+}
+
+// MARK: - All credential operations use async/await (no delegates needed)
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentSampleApp/MSALNativeCredManagmentSampleApp.entitlements b/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentSampleApp/MSALNativeCredManagmentSampleApp.entitlements
new file mode 100644
index 0000000000..e5b94ba7c0
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentSampleApp/MSALNativeCredManagmentSampleApp.entitlements
@@ -0,0 +1,22 @@
+
+
+
+
+ com.apple.developer.associated-domains
+
+ webcredentials:login.microsoft.com
+
+ com.apple.security.app-sandbox
+
+ com.apple.security.files.user-selected.read-only
+
+ com.apple.security.network.client
+
+ com.apple.security.network.server
+
+ keychain-access-groups
+
+ $(AppIdentifierPrefix)com.microsoft.adalcache
+
+
+
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentSampleApp/MSALNativeCredManagmentSampleAppApp.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentSampleApp/MSALNativeCredManagmentSampleAppApp.swift
new file mode 100644
index 0000000000..aff6ad513f
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentSampleApp/MSALNativeCredManagmentSampleAppApp.swift
@@ -0,0 +1,24 @@
+//
+// MSALNativeCredManagmentSampleAppApp.swift
+// MSALNativeCredManagmentSampleApp
+//
+// Created by Serhii Demchenko on 2026-05-27.
+//
+
+import SwiftUI
+
+@main
+struct MSALNativeCredManagmentSampleAppApp: App {
+
+ @StateObject private var viewModel = CredentialManagementViewModel()
+
+ var body: some Scene {
+ WindowGroup {
+ ContentView()
+ .environmentObject(viewModel)
+ .onAppear {
+ viewModel.initialize()
+ }
+ }
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentSampleApp/Preview Content/Preview Assets.xcassets/Contents.json b/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentSampleApp/Preview Content/Preview Assets.xcassets/Contents.json
new file mode 100644
index 0000000000..73c00596a7
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentSampleApp/Preview Content/Preview Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentSampleApp/SampleRequestInterceptor.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentSampleApp/SampleRequestInterceptor.swift
new file mode 100644
index 0000000000..39f7107355
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentSampleApp/SampleRequestInterceptor.swift
@@ -0,0 +1,26 @@
+//
+// SampleRequestInterceptor.swift
+// MSALNativeCredManagmentSampleApp
+//
+// Created by Serhii Demchenko on 2026-05-27.
+//
+
+import Foundation
+import MSAL
+import MSALNativeCredManagment
+
+/// Sample request interceptor shared between MSAL and the Credential Management client.
+///
+/// Demonstrates how to inject custom headers into credential management requests.
+class SampleRequestInterceptor: NSObject, MSALNativeAuthRequestInterceptor {
+
+ func addAdditionalHeaderFields(
+ _ requestUrl: URL?,
+ completionBlock: @escaping MSALNativeAuthRequestInterceptorAddHeaderCompletionBlock
+ ) {
+ let headers: [String: String] = [
+ "x-sample-app-version": "1.0.0"
+ ]
+ completionBlock(headers)
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentSampleAppTests/MSALNativeCredManagmentSampleAppTests.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentSampleAppTests/MSALNativeCredManagmentSampleAppTests.swift
new file mode 100644
index 0000000000..811eeb7824
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentSampleAppTests/MSALNativeCredManagmentSampleAppTests.swift
@@ -0,0 +1,16 @@
+//
+// MSALNativeCredManagmentSampleAppTests.swift
+// MSALNativeCredManagmentSampleAppTests
+//
+// Created by Serhii Demchenko on 2026-05-27.
+//
+
+import Testing
+
+struct MSALNativeCredManagmentSampleAppTests {
+
+ @Test func example() async throws {
+ // Write your test here and use APIs like `#expect(...)` to check expected conditions.
+ }
+
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentSampleAppUITests/MSALNativeCredManagmentSampleAppUITests.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentSampleAppUITests/MSALNativeCredManagmentSampleAppUITests.swift
new file mode 100644
index 0000000000..d7215971fa
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentSampleAppUITests/MSALNativeCredManagmentSampleAppUITests.swift
@@ -0,0 +1,43 @@
+//
+// MSALNativeCredManagmentSampleAppUITests.swift
+// MSALNativeCredManagmentSampleAppUITests
+//
+// Created by Serhii Demchenko on 2026-05-27.
+//
+
+import XCTest
+
+final class MSALNativeCredManagmentSampleAppUITests: XCTestCase {
+
+ override func setUpWithError() throws {
+ // Put setup code here. This method is called before the invocation of each test method in the class.
+
+ // In UI tests it is usually best to stop immediately when a failure occurs.
+ continueAfterFailure = false
+
+ // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
+ }
+
+ override func tearDownWithError() throws {
+ // Put teardown code here. This method is called after the invocation of each test method in the class.
+ }
+
+ @MainActor
+ func testExample() throws {
+ // UI tests must launch the application that they test.
+ let app = XCUIApplication()
+ app.launch()
+
+ // Use XCTAssert and related functions to verify your tests produce the correct results.
+ }
+
+ @MainActor
+ func testLaunchPerformance() throws {
+ if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) {
+ // This measures how long it takes to launch your application.
+ measure(metrics: [XCTApplicationLaunchMetric()]) {
+ XCUIApplication().launch()
+ }
+ }
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentSampleAppUITests/MSALNativeCredManagmentSampleAppUITestsLaunchTests.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentSampleAppUITests/MSALNativeCredManagmentSampleAppUITestsLaunchTests.swift
new file mode 100644
index 0000000000..6c79bfd71c
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentSampleAppUITests/MSALNativeCredManagmentSampleAppUITestsLaunchTests.swift
@@ -0,0 +1,33 @@
+//
+// MSALNativeCredManagmentSampleAppUITestsLaunchTests.swift
+// MSALNativeCredManagmentSampleAppUITests
+//
+// Created by Serhii Demchenko on 2026-05-27.
+//
+
+import XCTest
+
+final class MSALNativeCredManagmentSampleAppUITestsLaunchTests: XCTestCase {
+
+ override class var runsForEachTargetApplicationUIConfiguration: Bool {
+ true
+ }
+
+ override func setUpWithError() throws {
+ continueAfterFailure = false
+ }
+
+ @MainActor
+ func testLaunch() throws {
+ let app = XCUIApplication()
+ app.launch()
+
+ // Insert steps here to perform after app launch but before taking a screenshot,
+ // such as logging into a test account or navigating somewhere in the app
+
+ let attachment = XCTAttachment(screenshot: app.screenshot())
+ attachment.name = "Launch Screen"
+ attachment.lifetime = .keepAlways
+ add(attachment)
+ }
+}
diff --git a/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentTests/MSALNativeCredManagmentTests.swift b/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentTests/MSALNativeCredManagmentTests.swift
new file mode 100644
index 0000000000..e655fc5cbd
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/MSALNativeCredManagmentTests/MSALNativeCredManagmentTests.swift
@@ -0,0 +1,17 @@
+//
+// MSALNativeCredManagmentTests.swift
+// MSALNativeCredManagmentTests
+//
+// Created by Serhii Demchenko on 2026-05-25.
+//
+
+import Testing
+@testable import MSALNativeCredManagment
+
+struct MSALNativeCredManagmentTests {
+
+ @Test func example() async throws {
+ // Write your test here and use APIs like `#expect(...)` to check expected conditions.
+ }
+
+}
diff --git a/lib/native/MSALNativeCredManagment/Package.swift b/lib/native/MSALNativeCredManagment/Package.swift
new file mode 100644
index 0000000000..fddb7f65ca
--- /dev/null
+++ b/lib/native/MSALNativeCredManagment/Package.swift
@@ -0,0 +1,67 @@
+// swift-tools-version: 5.9
+// The swift-tools-version declares the minimum version of Swift required to build this package.
+
+import PackageDescription
+import Foundation
+
+// Compute absolute path to MSAL root from this Package.swift location
+let packageDir = URL(fileURLWithPath: #filePath).deletingLastPathComponent().path
+let msalRoot = URL(fileURLWithPath: packageDir + "/../../../MSAL").standardized.path
+
+// Dynamically discover all subdirectories containing .h files.
+// This is necessary because IdentityCore headers use bare `#import "filename.h"` without relative paths.
+func findHeaderDirs(in basePath: String) -> [String] {
+ let fm = FileManager.default
+ guard let enumerator = fm.enumerator(atPath: basePath) else { return [] }
+ var dirs = Set()
+ dirs.insert(basePath)
+ while let item = enumerator.nextObject() as? String {
+ if item.hasSuffix(".h") {
+ let dir = (item as NSString).deletingLastPathComponent
+ if !dir.isEmpty {
+ dirs.insert(basePath + "/" + dir)
+ }
+ }
+ }
+ return Array(dirs).sorted()
+}
+
+let allHeaderDirs = findHeaderDirs(in: msalRoot + "/IdentityCore/IdentityCore/src")
+
+let package = Package(
+ name: "MSALNativeCredManagment",
+ platforms: [
+ .iOS(.v16),
+ .macOS(.v13)
+ ],
+ products: [
+ .library(
+ name: "MSALNativeCredManagment",
+ targets: ["MSALNativeCredManagment"]
+ )
+ ],
+ dependencies: [
+ // MSAL SDK as a local dependency (relative path to the root of microsoft-authentication-library-for-objc)
+ .package(path: "../../..")
+ ],
+ targets: [
+ .target(
+ name: "MSALNativeCredManagment",
+ dependencies: [
+ .product(name: "MSAL", package: "microsoft-authentication-library-for-objc")
+ ],
+ path: "MSALNativeCredManagment/src",
+ swiftSettings: [
+ .unsafeFlags(
+ ["-Xcc", "-fmodule-map-file=\(packageDir)/CMSAL_Private/include/module.modulemap"]
+ + allHeaderDirs.flatMap { ["-Xcc", "-I\($0)"] }
+ )
+ ]
+ ),
+ .testTarget(
+ name: "MSALNativeCredManagmentTests",
+ dependencies: ["MSALNativeCredManagment"],
+ path: "MSALNativeCredManagmentTests"
+ )
+ ]
+)