From 812c93a518fd17bc091d7f5536deda61c0fef5dd Mon Sep 17 00:00:00 2001 From: Nandan Prabhu Date: Sun, 29 Jun 2025 23:29:19 +0530 Subject: [PATCH 1/5] SDK-6104 My Account Auth apis added as per API spec --- Auth0.xcodeproj/project.pbxproj | 24 +++++++ .../Auth0MyAccountAuthenticationMethods.swift | 70 ++++++++++++++++++- .../AuthenticationMethods/Factor.swift | 4 ++ .../GetAuthenticationMethodsResponse.swift | 46 ++++++++++++ .../MyAccountAuthenticationMethods.swift | 41 +++++++++-- .../PasskeyEnrollmentChallenge.swift | 4 ++ Auth0/MyAccount/MyAccountHandlers.swift | 12 ++++ 7 files changed, 193 insertions(+), 8 deletions(-) create mode 100644 Auth0/MyAccount/AuthenticationMethods/Factor.swift create mode 100644 Auth0/MyAccount/AuthenticationMethods/GetAuthenticationMethodsResponse.swift diff --git a/Auth0.xcodeproj/project.pbxproj b/Auth0.xcodeproj/project.pbxproj index a0185c62..7cf3cc9a 100644 --- a/Auth0.xcodeproj/project.pbxproj +++ b/Auth0.xcodeproj/project.pbxproj @@ -553,6 +553,16 @@ D41DED402DCA09B500F5B1A4 /* SimpleKeychain.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CD9FC8526FE30EB009C2B27 /* SimpleKeychain.xcframework */; }; D4B8E9E42DCDD2340021262D /* CwlPreconditionTesting in Frameworks */ = {isa = PBXBuildFile; productRef = D4B8E9E32DCDD2340021262D /* CwlPreconditionTesting */; }; D4B8E9E62DCDD23C0021262D /* CwlPosixPreconditionTesting in Frameworks */ = {isa = PBXBuildFile; productRef = D4B8E9E52DCDD23C0021262D /* CwlPosixPreconditionTesting */; }; + D4BF84C42E0EC990006B106C /* GetAuthenticationMethodsResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4BF84BE2E0E9F2C006B106C /* GetAuthenticationMethodsResponse.swift */; }; + D4BF84C52E0EC990006B106C /* GetAuthenticationMethodsResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4BF84BE2E0E9F2C006B106C /* GetAuthenticationMethodsResponse.swift */; }; + D4BF84C62E0EC990006B106C /* GetAuthenticationMethodsResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4BF84BE2E0E9F2C006B106C /* GetAuthenticationMethodsResponse.swift */; }; + D4BF84C72E0EC990006B106C /* GetAuthenticationMethodsResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4BF84BE2E0E9F2C006B106C /* GetAuthenticationMethodsResponse.swift */; }; + D4BF84C82E0EC990006B106C /* GetAuthenticationMethodsResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4BF84BE2E0E9F2C006B106C /* GetAuthenticationMethodsResponse.swift */; }; + D4BF84D02E1023F0006B106C /* Factor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4BF84CF2E1023E8006B106C /* Factor.swift */; }; + D4BF84D12E1023F0006B106C /* Factor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4BF84CF2E1023E8006B106C /* Factor.swift */; }; + D4BF84D22E1023F0006B106C /* Factor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4BF84CF2E1023E8006B106C /* Factor.swift */; }; + D4BF84D32E1023F0006B106C /* Factor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4BF84CF2E1023E8006B106C /* Factor.swift */; }; + D4BF84D42E1023F0006B106C /* Factor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4BF84CF2E1023E8006B106C /* Factor.swift */; }; D581CF772757D773007327D1 /* RequestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D581CF762757D773007327D1 /* RequestSpec.swift */; }; D581CF782757D773007327D1 /* RequestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D581CF762757D773007327D1 /* RequestSpec.swift */; }; D581CF792757D773007327D1 /* RequestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D581CF762757D773007327D1 /* RequestSpec.swift */; }; @@ -900,6 +910,8 @@ C1B3B9B72C24B298004A32A4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; C1B3B9C02C24B39E004A32A4 /* Auth0.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Auth0.framework; sourceTree = BUILT_PRODUCTS_DIR; }; C1B3B9C72C24B39E004A32A4 /* Auth0Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Auth0Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + D4BF84BE2E0E9F2C006B106C /* GetAuthenticationMethodsResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetAuthenticationMethodsResponse.swift; sourceTree = ""; }; + D4BF84CF2E1023E8006B106C /* Factor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Factor.swift; sourceTree = ""; }; D581CF762757D773007327D1 /* RequestSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestSpec.swift; sourceTree = ""; }; D5E9E316273ACCA5000CDB0A /* ChallengeGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChallengeGenerator.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -1167,6 +1179,8 @@ 5CDF67282DD3925200A9B513 /* AuthenticationMethods */ = { isa = PBXGroup; children = ( + D4BF84CF2E1023E8006B106C /* Factor.swift */, + D4BF84BE2E0E9F2C006B106C /* GetAuthenticationMethodsResponse.swift */, 5CDF67472DD3B73D00A9B513 /* Auth0MyAccountAuthenticationMethods.swift */, 5CDF67532DD4AD7E00A9B513 /* MyAccountAuthenticationMethods.swift */, 5CDF673B2DD3B0DE00A9B513 /* PasskeyAuthenticationMethod.swift */, @@ -2240,6 +2254,7 @@ 5B16D8931F714324009476A5 /* WebAuthUserAgent.swift in Sources */, 5C3D87E22DB8276000AACC34 /* PublicKeyCredentialCreationOptions.swift in Sources */, 5F6FAC631D09E98000D5B4EA /* Logger.swift in Sources */, + D4BF84D02E1023F0006B106C /* Factor.swift in Sources */, 5C41F6B1244DCC3B00252548 /* MobileWebAuth.swift in Sources */, 5C3D88252DC1509800AACC34 /* LoginPasskey.swift in Sources */, 5F28B4611D8216180000EB23 /* Loggable.swift in Sources */, @@ -2284,6 +2299,7 @@ 5F74CB401CEFD5E600226823 /* JSONObjectPayload.swift in Sources */, 5FD255B41D14DD2600387ECB /* ManagementError.swift in Sources */, 5FE2F8B81CD0E910003628F4 /* Request.swift in Sources */, + D4BF84C42E0EC990006B106C /* GetAuthenticationMethodsResponse.swift in Sources */, 5CDF67512DD3DB5400A9B513 /* MyAccountHandlers.swift in Sources */, 5C41F6A4244DC94E00252548 /* LoginTransaction.swift in Sources */, 5F3965C21CF67CF000CDE7C0 /* WebAuth.swift in Sources */, @@ -2332,6 +2348,7 @@ 5FD255B81D14F00900387ECB /* Auth0Error.swift in Sources */, 5C41F6D0244F971700252548 /* JWK+RSA.swift in Sources */, 5C41F6C7244F968B00252548 /* AuthTransaction.swift in Sources */, + D4BF84C52E0EC990006B106C /* GetAuthenticationMethodsResponse.swift in Sources */, 5CFB82612D6D221F009FD237 /* Barrier.swift in Sources */, 5FD255B51D14DD2600387ECB /* ManagementError.swift in Sources */, 5C0AF09B28330CBA00162044 /* SafariProvider.swift in Sources */, @@ -2378,6 +2395,7 @@ 5CDF673E2DD3B0E400A9B513 /* PasskeyAuthenticationMethod.swift in Sources */, 5CDF67362DD3A8D600A9B513 /* Auth0APIError.swift in Sources */, 5FDE87561D8A424700EA27DC /* Auth0Authentication.swift in Sources */, + D4BF84D22E1023F0006B106C /* Factor.swift in Sources */, 5FADB6071CED27FB00D4BB50 /* Users.swift in Sources */, 5C41F6C3244F965E00252548 /* Array+Encode.swift in Sources */, 5CDF672B2DD395C700A9B513 /* NewPasskey.swift in Sources */, @@ -2526,10 +2544,12 @@ 5FDE875B1D8A424700EA27DC /* Authentication.swift in Sources */, 5F23E6E21D4ACD7F00C3F2D9 /* Users.swift in Sources */, 5FDE876B1D8A424700EA27DC /* Credentials.swift in Sources */, + D4BF84C72E0EC990006B106C /* GetAuthenticationMethodsResponse.swift in Sources */, 5CA541D02B1A81A700E4284D /* Documentation.docc in Sources */, 5FE1182A1D8A4A2B00A374BF /* Telemetry.swift in Sources */, 5CC9940324ED9EC50027DC74 /* CredentialsManager.swift in Sources */, 5CFB82712D6E640F009FD237 /* SSOCredentials.swift in Sources */, + D4BF84D12E1023F0006B106C /* Factor.swift in Sources */, 5CDF67382DD3A8D600A9B513 /* Auth0APIError.swift in Sources */, 5F23E6E41D4ACD8500C3F2D9 /* JSONObjectPayload.swift in Sources */, 5C4F551C23C8FB8E00C89615 /* String+URLSafe.swift in Sources */, @@ -2574,10 +2594,12 @@ 5C29743223FDBD5400BC18FA /* Optional+DebugDescription.swift in Sources */, 5F23E70B1D4B88F600C3F2D9 /* Users.swift in Sources */, 5FDE876C1D8A424700EA27DC /* Credentials.swift in Sources */, + D4BF84C62E0EC990006B106C /* GetAuthenticationMethodsResponse.swift in Sources */, 5CA541CF2B1A81A700E4284D /* Documentation.docc in Sources */, 5FE118291D8A4A2A00A374BF /* Telemetry.swift in Sources */, 5F23E70D1D4B88FC00C3F2D9 /* JSONObjectPayload.swift in Sources */, 5CFB82722D6E640F009FD237 /* SSOCredentials.swift in Sources */, + D4BF84D32E1023F0006B106C /* Factor.swift in Sources */, 5CDF67372DD3A8D600A9B513 /* Auth0APIError.swift in Sources */, 5C4F552623C8FBA100C89615 /* JWKS.swift in Sources */, 5B0893E620F8A52100FBF962 /* CredentialsManager.swift in Sources */, @@ -2650,6 +2672,7 @@ files = ( C1B3BA262C24B6F5004A32A4 /* Documentation.docc in Sources */, C1B3B9EE2C24B6D4004A32A4 /* Auth0Authentication.swift in Sources */, + D4BF84D42E1023F0006B106C /* Factor.swift in Sources */, C1B3B9EF2C24B6D4004A32A4 /* Authentication.swift in Sources */, C1B3B9F02C24B6D4004A32A4 /* AuthenticationError.swift in Sources */, C1B3B9F12C24B6D4004A32A4 /* PasswordlessType.swift in Sources */, @@ -2711,6 +2734,7 @@ 5CDF673A2DD3A8D600A9B513 /* Auth0APIError.swift in Sources */, C1B3BA182C24B6D4004A32A4 /* ClearSessionTransaction.swift in Sources */, C1B3BA192C24B6D4004A32A4 /* MobileWebAuth.swift in Sources */, + D4BF84C82E0EC990006B106C /* GetAuthenticationMethodsResponse.swift in Sources */, C1B3BA1B2C24B6D4004A32A4 /* AuthTransaction.swift in Sources */, C1B3BA1C2C24B6D4004A32A4 /* WebAuthUserAgent.swift in Sources */, C1B3BA1D2C24B6D4004A32A4 /* OAuth2Grant.swift in Sources */, diff --git a/Auth0/MyAccount/AuthenticationMethods/Auth0MyAccountAuthenticationMethods.swift b/Auth0/MyAccount/AuthenticationMethods/Auth0MyAccountAuthenticationMethods.swift index a1d3435c..731e6bb0 100644 --- a/Auth0/MyAccount/AuthenticationMethods/Auth0MyAccountAuthenticationMethods.swift +++ b/Auth0/MyAccount/AuthenticationMethods/Auth0MyAccountAuthenticationMethods.swift @@ -26,10 +26,15 @@ struct Auth0MyAccountAuthenticationMethods: MyAccountAuthenticationMethods { #if PASSKEYS_PLATFORM @available(iOS 16.6, macOS 13.5, visionOS 1.0, *) func passkeyEnrollmentChallenge(userIdentityId: String?, - connection: String?) -> Request { + connection: String?, + email: String?, + phoneNumber: String?, + preferredAuthenticationMethod: String?) -> Request { var payload: [String: Any] = ["type": "passkey"] payload["identity_user_id"] = userIdentityId payload["connection"] = connection + payload["email"] = email + payload["preferred_authentication_method"] = preferredAuthenticationMethod return Request(session: session, url: self.url, @@ -62,7 +67,8 @@ struct Auth0MyAccountAuthenticationMethods: MyAccountAuthenticationMethods { let payload: [String: Any] = [ "auth_session": challenge.authenticationSession, - "authn_response": authenticatorResponse + "authn_response": authenticatorResponse, + "otp_code" = "" ] return Request(session: session, @@ -76,4 +82,64 @@ struct Auth0MyAccountAuthenticationMethods: MyAccountAuthenticationMethods { } #endif + func deleteAuthenticationMethod(id: String) -> Request { + return Request(session: session, + url: self.url.appending(id), + method: "DELETE", + handle: myAccountDecodableNoBody, + headers: defaultHeaders, + logger: self.logger, + telemetry: self.telemetry) + } + + func getAuthenticationMethods() -> Request { + return Request(session: session, + url: url, + method: "GET", + handle: myAcccountDecodable, + logger: logger, + telemetry: telemetry) + } + + func getFactorStatus() -> Request<[Factor], MyAccountError> { + return Request(session: session, + url: url.appending("factors"), + method: "GET", + handle: myAcccountDecodable, + logger: logger, + telemetry: telemetry) + } + + func getAuthenticationMethod(id: String) -> Request { + return Request(session: session, + url: url.appending(id), + method: "GET", + handle: myAcccountDecodable, + logger: logger, + telemetry: telemetry) + } + + func deleteAuthenticationMethod(id: String) -> Request { + return Request(session: session, + url: url.appending(id), + method: "GET", + handle: myAcccountDecodable, + logger: logger, + telemetry: telemetry) + } + + func updateAuthenticationMethod(id: String, + name: String, + preferredAuthenticationMethod: String) -> Request { + var payload: [String: Any] = [:] + payload["name"] = name + payload["preferred_authentication_method"] = preferredAuthenticationMethod + return Request(session: session, + url: url.appending(id), + method: "PATCH", + handle: myAcccountDecodable, + parameters: payload, + logger: logger, + telemetry: telemetry) + } } diff --git a/Auth0/MyAccount/AuthenticationMethods/Factor.swift b/Auth0/MyAccount/AuthenticationMethods/Factor.swift new file mode 100644 index 00000000..2170af48 --- /dev/null +++ b/Auth0/MyAccount/AuthenticationMethods/Factor.swift @@ -0,0 +1,4 @@ +public struct Factor: Decodable { + let type: String? + let usage: String? +} diff --git a/Auth0/MyAccount/AuthenticationMethods/GetAuthenticationMethodsResponse.swift b/Auth0/MyAccount/AuthenticationMethods/GetAuthenticationMethodsResponse.swift new file mode 100644 index 00000000..8f0a7e70 --- /dev/null +++ b/Auth0/MyAccount/AuthenticationMethods/GetAuthenticationMethodsResponse.swift @@ -0,0 +1,46 @@ +public struct AuthenticationMethods: Decodable { + public let start: Int? + public let limit: Int? + public let total: Int? + public let authenticators: [AuthenticationMethod]? +} + +public struct AuthenticationMethod: Decodable { + let type: String? + let credentialBackedUp: Bool? + let credentialDeviceType: String? + let identityUserId: String? + let keyId: String? + let publicKey: String? + let transports: [String]? + let userAgent: String + let userHandle: String? + let lastPasswordReset: String? + let id: String? + let createdAt: String + let usage: [String] + let confirmed: Bool? + let name: String? + let preferredAuthenticationMethod: String? + let phoneNumber: String? + + enum CodingKeys: String, CodingKey { + case type + case identityUserId = "identity_user_id" + case lastPasswordReset = "last_password_reset" + case id + case createdAt = "created_at" + case usage + case credentialBackedUp = "credential_backed_up" + case credentialDeviceType = "credential_device_type" + case keyId = "key_id" + case userAgent = "user_agent" + case userHandle = "user_handle" + case publicKey = "public_key" + case transports + case confirmed + case name + case preferredAuthenticationMethod = "preferrred_authentication_method" + case phoneNumber = "phone_number" + } +} diff --git a/Auth0/MyAccount/AuthenticationMethods/MyAccountAuthenticationMethods.swift b/Auth0/MyAccount/AuthenticationMethods/MyAccountAuthenticationMethods.swift index 46b70783..840cca97 100644 --- a/Auth0/MyAccount/AuthenticationMethods/MyAccountAuthenticationMethods.swift +++ b/Auth0/MyAccount/AuthenticationMethods/MyAccountAuthenticationMethods.swift @@ -4,8 +4,8 @@ /// - ``MyAccount`` /// - ``MyAccountError`` public protocol MyAccountAuthenticationMethods: MyAccountClient { - - #if PASSKEYS_PLATFORM + +#if PASSKEYS_PLATFORM /// Requests a challenge for enrolling a new passkey. This is the first part of the enrollment flow. /// /// You can specify an optional user identity identifier and an optional database connection name. If a @@ -75,7 +75,7 @@ public protocol MyAccountAuthenticationMethods: MyAccountClient { @available(iOS 16.6, macOS 13.5, visionOS 1.0, *) func passkeyEnrollmentChallenge(userIdentityId: String?, connection: String?) -> Request - + /// Enrolls a new passkey credential. This is the last part of the enrollment flow. /// /// ## Availability @@ -111,13 +111,42 @@ public protocol MyAccountAuthenticationMethods: MyAccountClient { /// - Returns: A request that will yield an enrolled passkey authentication method. /// /// ## See Also - /// + /// /// - [Supporting passkeys](https://developer.apple.com/documentation/authenticationservices/supporting-passkeys#Register-a-new-account-on-a-service) @available(iOS 16.6, macOS 13.5, visionOS 1.0, *) func enroll(passkey: NewPasskey, challenge: PasskeyEnrollmentChallenge) -> Request - #endif - +#endif + + /// <#Description#> + /// - Parameter id: <#id description#> + /// - Returns: <#description#> + func deleteAuthenticationMethod(id: String) -> Request + + /// <#Description#> + /// - Returns: <#description#> + func getAuthenticationMethods() -> Request + + /// <#Description#> + /// - Returns: <#description#> + func getFactorStatus() -> Request<[Factor], MyAccountError> + + /// <#Description#> + /// - Parameter id: <#id description#> + /// - Returns: <#description#> + func getAuthenticationMethod(id: String) -> Request + + /// <#Description#> + /// - Parameter id: <#id description#> + /// - Returns: <#description#> + func deleteAuthenticationMethod(id: String) -> Request + + /// <#Description#> + /// - Parameter id: <#id description#> + /// - Returns: <#description#> + func updateAuthenticationMethod(id: String, + name: String, + preferredAuthenticationMethod: String) -> Request } // MARK: - Default Parameters diff --git a/Auth0/MyAccount/AuthenticationMethods/PasskeyEnrollmentChallenge.swift b/Auth0/MyAccount/AuthenticationMethods/PasskeyEnrollmentChallenge.swift index e45075ae..fabc6d4f 100644 --- a/Auth0/MyAccount/AuthenticationMethods/PasskeyEnrollmentChallenge.swift +++ b/Auth0/MyAccount/AuthenticationMethods/PasskeyEnrollmentChallenge.swift @@ -29,6 +29,10 @@ extension PasskeyEnrollmentChallenge: Decodable { enum CodingKeys: String, CodingKey { case authenticationSession = "auth_session" case credentialCreationOptions = "authn_params_public_key" + case id + case barcodeURI = "barcode_uri" + case manualInputCode = "manual_input_code" + case recovery_code = "recovery_code" } /// `Decodable` initializer. diff --git a/Auth0/MyAccount/MyAccountHandlers.swift b/Auth0/MyAccount/MyAccountHandlers.swift index 832e5fb7..5e084b05 100644 --- a/Auth0/MyAccount/MyAccountHandlers.swift +++ b/Auth0/MyAccount/MyAccountHandlers.swift @@ -18,6 +18,18 @@ func myAcccountDecodable(from response: Response, } } +func myAccountDecodableNoBody(from response: Response, + callback: Request.Callback) { + do { + _ = try response.result() + callback(.success(())) + } catch let error where error.code == emptyBodyError { + callback(.success(())) + } catch { + callback(.failure(error)) + } +} + extension CodingUserInfoKey { static var headersKey: CodingUserInfoKey { From 17fb373e8b118a489a86007df28812b26f6b7940 Mon Sep 17 00:00:00 2001 From: Nandan Prabhu Date: Fri, 4 Jul 2025 10:49:34 +0530 Subject: [PATCH 2/5] my account auth enrollment methods added --- Auth0.xcodeproj/project.pbxproj | 12 ++++ .../Auth0MyAccountAuthenticationMethods.swift | 56 ++++++++++++++----- .../AuthMethodEnrollmentChallenge.swift | 1 + .../MyAccountAuthenticationMethods.swift | 35 +++++------- 4 files changed, 68 insertions(+), 36 deletions(-) create mode 100644 Auth0/MyAccount/AuthenticationMethods/AuthMethodEnrollmentChallenge.swift diff --git a/Auth0.xcodeproj/project.pbxproj b/Auth0.xcodeproj/project.pbxproj index 7cf3cc9a..76f7f891 100644 --- a/Auth0.xcodeproj/project.pbxproj +++ b/Auth0.xcodeproj/project.pbxproj @@ -563,6 +563,11 @@ D4BF84D22E1023F0006B106C /* Factor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4BF84CF2E1023E8006B106C /* Factor.swift */; }; D4BF84D32E1023F0006B106C /* Factor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4BF84CF2E1023E8006B106C /* Factor.swift */; }; D4BF84D42E1023F0006B106C /* Factor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4BF84CF2E1023E8006B106C /* Factor.swift */; }; + D4BF84D72E177147006B106C /* AuthMethodEnrollmentChallenge.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4BF84D62E17713B006B106C /* AuthMethodEnrollmentChallenge.swift */; }; + D4BF84D82E177147006B106C /* AuthMethodEnrollmentChallenge.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4BF84D62E17713B006B106C /* AuthMethodEnrollmentChallenge.swift */; }; + D4BF84D92E177147006B106C /* AuthMethodEnrollmentChallenge.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4BF84D62E17713B006B106C /* AuthMethodEnrollmentChallenge.swift */; }; + D4BF84DA2E177147006B106C /* AuthMethodEnrollmentChallenge.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4BF84D62E17713B006B106C /* AuthMethodEnrollmentChallenge.swift */; }; + D4BF84DB2E177147006B106C /* AuthMethodEnrollmentChallenge.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4BF84D62E17713B006B106C /* AuthMethodEnrollmentChallenge.swift */; }; D581CF772757D773007327D1 /* RequestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D581CF762757D773007327D1 /* RequestSpec.swift */; }; D581CF782757D773007327D1 /* RequestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D581CF762757D773007327D1 /* RequestSpec.swift */; }; D581CF792757D773007327D1 /* RequestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D581CF762757D773007327D1 /* RequestSpec.swift */; }; @@ -912,6 +917,7 @@ C1B3B9C72C24B39E004A32A4 /* Auth0Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Auth0Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; D4BF84BE2E0E9F2C006B106C /* GetAuthenticationMethodsResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetAuthenticationMethodsResponse.swift; sourceTree = ""; }; D4BF84CF2E1023E8006B106C /* Factor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Factor.swift; sourceTree = ""; }; + D4BF84D62E17713B006B106C /* AuthMethodEnrollmentChallenge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthMethodEnrollmentChallenge.swift; sourceTree = ""; }; D581CF762757D773007327D1 /* RequestSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestSpec.swift; sourceTree = ""; }; D5E9E316273ACCA5000CDB0A /* ChallengeGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChallengeGenerator.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -1179,6 +1185,7 @@ 5CDF67282DD3925200A9B513 /* AuthenticationMethods */ = { isa = PBXGroup; children = ( + D4BF84D62E17713B006B106C /* AuthMethodEnrollmentChallenge.swift */, D4BF84CF2E1023E8006B106C /* Factor.swift */, D4BF84BE2E0E9F2C006B106C /* GetAuthenticationMethodsResponse.swift */, 5CDF67472DD3B73D00A9B513 /* Auth0MyAccountAuthenticationMethods.swift */, @@ -2304,6 +2311,7 @@ 5C41F6A4244DC94E00252548 /* LoginTransaction.swift in Sources */, 5F3965C21CF67CF000CDE7C0 /* WebAuth.swift in Sources */, 5FCAB1761D0900CF00331C84 /* TransactionStore.swift in Sources */, + D4BF84DB2E177147006B106C /* AuthMethodEnrollmentChallenge.swift in Sources */, 5FDE87471D8A422300EA27DC /* Telemetry.swift in Sources */, C107B51D2C9AC4D8006B6BEA /* WebViewProvider.swift in Sources */, 5FAE9C911D8878D400A871CE /* Auth0WebAuth.swift in Sources */, @@ -2382,6 +2390,7 @@ 5B7EE47320FCA00700367724 /* CredentialsManager.swift in Sources */, 5C4F551B23C8FB8E00C89615 /* String+URLSafe.swift in Sources */, 5FDE875A1D8A424700EA27DC /* Authentication.swift in Sources */, + D4BF84DA2E177147006B106C /* AuthMethodEnrollmentChallenge.swift in Sources */, 5C41F6D8244F976200252548 /* WebAuth.swift in Sources */, 5C41F6CC244F96F200252548 /* ClaimValidators.swift in Sources */, 5C41F6D9244F977900252548 /* WebAuthError.swift in Sources */, @@ -2528,6 +2537,7 @@ 970BC36D25C27095007A7745 /* MultifactorChallenge.swift in Sources */, 5FDE87571D8A424700EA27DC /* Auth0Authentication.swift in Sources */, 5C4F552523C8FBA100C89615 /* JWKS.swift in Sources */, + D4BF84D92E177147006B106C /* AuthMethodEnrollmentChallenge.swift in Sources */, 5F23E6E51D4ACD8500C3F2D9 /* Request.swift in Sources */, 5C38EA2D2DA4635B0085AC31 /* MyAccountError.swift in Sources */, 5CDF67492DD3B74200A9B513 /* Auth0MyAccountAuthenticationMethods.swift in Sources */, @@ -2578,6 +2588,7 @@ 5FDE87581D8A424700EA27DC /* Auth0Authentication.swift in Sources */, 5F23E7071D4B88EA00C3F2D9 /* NSURL+Auth0.swift in Sources */, 5F23E71A1D4B891E00C3F2D9 /* Auth0.swift in Sources */, + D4BF84D72E177147006B106C /* AuthMethodEnrollmentChallenge.swift in Sources */, 5F23E7101D4B88FC00C3F2D9 /* Response.swift in Sources */, 5C38EA2C2DA4635B0085AC31 /* MyAccountError.swift in Sources */, 5CDF674B2DD3B74200A9B513 /* Auth0MyAccountAuthenticationMethods.swift in Sources */, @@ -2711,6 +2722,7 @@ C1B3BA082C24B6D4004A32A4 /* Optional+DebugDescription.swift in Sources */, C1B3BA092C24B6D4004A32A4 /* Logger.swift in Sources */, C1B3BA0A2C24B6D4004A32A4 /* Loggable.swift in Sources */, + D4BF84D82E177147006B106C /* AuthMethodEnrollmentChallenge.swift in Sources */, C1B3BA0B2C24B6D4004A32A4 /* Management.swift in Sources */, 5C3D88242DC1509800AACC34 /* LoginPasskey.swift in Sources */, C1B3BA0C2C24B6D4004A32A4 /* UserPatchAttributes.swift in Sources */, diff --git a/Auth0/MyAccount/AuthenticationMethods/Auth0MyAccountAuthenticationMethods.swift b/Auth0/MyAccount/AuthenticationMethods/Auth0MyAccountAuthenticationMethods.swift index 731e6bb0..85066df6 100644 --- a/Auth0/MyAccount/AuthenticationMethods/Auth0MyAccountAuthenticationMethods.swift +++ b/Auth0/MyAccount/AuthenticationMethods/Auth0MyAccountAuthenticationMethods.swift @@ -15,7 +15,7 @@ struct Auth0MyAccountAuthenticationMethods: MyAccountAuthenticationMethods { telemetry: Telemetry = Telemetry(), logger: Logger? = nil) { self.token = token - self.url = url.appending("authentication-methods") + self.url = url self.session = session self.telemetry = telemetry self.logger = logger @@ -26,18 +26,13 @@ struct Auth0MyAccountAuthenticationMethods: MyAccountAuthenticationMethods { #if PASSKEYS_PLATFORM @available(iOS 16.6, macOS 13.5, visionOS 1.0, *) func passkeyEnrollmentChallenge(userIdentityId: String?, - connection: String?, - email: String?, - phoneNumber: String?, - preferredAuthenticationMethod: String?) -> Request { + connection: String?) -> Request { var payload: [String: Any] = ["type": "passkey"] payload["identity_user_id"] = userIdentityId payload["connection"] = connection - payload["email"] = email - payload["preferred_authentication_method"] = preferredAuthenticationMethod return Request(session: session, - url: self.url, + url: self.url.appending("authentication-methods"), method: "POST", handle: myAcccountDecodable, parameters: payload, @@ -68,11 +63,10 @@ struct Auth0MyAccountAuthenticationMethods: MyAccountAuthenticationMethods { let payload: [String: Any] = [ "auth_session": challenge.authenticationSession, "authn_response": authenticatorResponse, - "otp_code" = "" ] return Request(session: session, - url: self.url.appending(path), + url: self.url.appending("authentication-methods").appending(path), method: "POST", handle: myAcccountDecodable, parameters: payload, @@ -84,7 +78,7 @@ struct Auth0MyAccountAuthenticationMethods: MyAccountAuthenticationMethods { func deleteAuthenticationMethod(id: String) -> Request { return Request(session: session, - url: self.url.appending(id), + url: self.url.appending("authentication-methods").appending(id), method: "DELETE", handle: myAccountDecodableNoBody, headers: defaultHeaders, @@ -94,7 +88,7 @@ struct Auth0MyAccountAuthenticationMethods: MyAccountAuthenticationMethods { func getAuthenticationMethods() -> Request { return Request(session: session, - url: url, + url: url.appending("authentication-methods"), method: "GET", handle: myAcccountDecodable, logger: logger, @@ -112,7 +106,7 @@ struct Auth0MyAccountAuthenticationMethods: MyAccountAuthenticationMethods { func getAuthenticationMethod(id: String) -> Request { return Request(session: session, - url: url.appending(id), + url: url.appending("authentication-methods").appending(id), method: "GET", handle: myAcccountDecodable, logger: logger, @@ -121,7 +115,7 @@ struct Auth0MyAccountAuthenticationMethods: MyAccountAuthenticationMethods { func deleteAuthenticationMethod(id: String) -> Request { return Request(session: session, - url: url.appending(id), + url: url.appending("authentication-methods").appending(id), method: "GET", handle: myAcccountDecodable, logger: logger, @@ -135,11 +129,43 @@ struct Auth0MyAccountAuthenticationMethods: MyAccountAuthenticationMethods { payload["name"] = name payload["preferred_authentication_method"] = preferredAuthenticationMethod return Request(session: session, - url: url.appending(id), + url: url.appending("authentication-methods").appending(id), method: "PATCH", handle: myAcccountDecodable, parameters: payload, logger: logger, telemetry: telemetry) } + + func enrollAuthMethod(type: String, + connection: String?, + userIdentityId: String?, + email: String?, + phoneNumber: String?, + preferredAuthenticationMethod: String?) -> Request { + var payload: [String: Any] = [:] + + payload["type"] = type + payload["connection"] = connection + payload["user_identity_id"] = userIdentityId + payload["emaail"] = email + payload["phone_number"] = phoneNumber + payload["preferred_authentication_method"] = preferredAuthenticationMethod + + return Request(session: self.session, + url: self.url.appending("authentication-methods"), + method: "", + handle: myAcccountDecodable, + logger: self.logger, + telemetry: self.telemetry) + } + + func confirmEnrollment(id: String) -> Request { + return Request(session: session, + url: url.appending("authentication-methods").appending(id).appending("verify"), + method: "POST", + handle: myAcccountDecodable, + logger: logger, + telemetry: telemetry) + } } diff --git a/Auth0/MyAccount/AuthenticationMethods/AuthMethodEnrollmentChallenge.swift b/Auth0/MyAccount/AuthenticationMethods/AuthMethodEnrollmentChallenge.swift new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/Auth0/MyAccount/AuthenticationMethods/AuthMethodEnrollmentChallenge.swift @@ -0,0 +1 @@ + diff --git a/Auth0/MyAccount/AuthenticationMethods/MyAccountAuthenticationMethods.swift b/Auth0/MyAccount/AuthenticationMethods/MyAccountAuthenticationMethods.swift index 840cca97..56ce6e1e 100644 --- a/Auth0/MyAccount/AuthenticationMethods/MyAccountAuthenticationMethods.swift +++ b/Auth0/MyAccount/AuthenticationMethods/MyAccountAuthenticationMethods.swift @@ -117,36 +117,29 @@ public protocol MyAccountAuthenticationMethods: MyAccountClient { func enroll(passkey: NewPasskey, challenge: PasskeyEnrollmentChallenge) -> Request #endif - - /// <#Description#> - /// - Parameter id: <#id description#> - /// - Returns: <#description#> + func deleteAuthenticationMethod(id: String) -> Request - - /// <#Description#> - /// - Returns: <#description#> + func getAuthenticationMethods() -> Request - - /// <#Description#> - /// - Returns: <#description#> + func getFactorStatus() -> Request<[Factor], MyAccountError> - - /// <#Description#> - /// - Parameter id: <#id description#> - /// - Returns: <#description#> + func getAuthenticationMethod(id: String) -> Request - - /// <#Description#> - /// - Parameter id: <#id description#> - /// - Returns: <#description#> + func deleteAuthenticationMethod(id: String) -> Request - /// <#Description#> - /// - Parameter id: <#id description#> - /// - Returns: <#description#> func updateAuthenticationMethod(id: String, name: String, preferredAuthenticationMethod: String) -> Request + + func enrollAuthMethod(type: String, + connection: String, + userIdentityId: String, + email: String, + phoneNumber: String, + preferredAuthenticationMethod: String) -> Request + + func confirmEnrollment() -> Request } // MARK: - Default Parameters From ece11f49830fc7269f898e8a8683c43e734483ca Mon Sep 17 00:00:00 2001 From: Nandan Prabhu Date: Wed, 16 Jul 2025 10:42:31 +0530 Subject: [PATCH 3/5] added enrolment methods --- .../Auth0MyAccountAuthenticationMethods.swift | 71 ++++++++++--------- .../GetAuthenticationMethodsResponse.swift | 7 -- .../MyAccountAuthenticationMethods.swift | 20 +++--- 3 files changed, 47 insertions(+), 51 deletions(-) diff --git a/Auth0/MyAccount/AuthenticationMethods/Auth0MyAccountAuthenticationMethods.swift b/Auth0/MyAccount/AuthenticationMethods/Auth0MyAccountAuthenticationMethods.swift index 85066df6..32fe1751 100644 --- a/Auth0/MyAccount/AuthenticationMethods/Auth0MyAccountAuthenticationMethods.swift +++ b/Auth0/MyAccount/AuthenticationMethods/Auth0MyAccountAuthenticationMethods.swift @@ -85,8 +85,45 @@ struct Auth0MyAccountAuthenticationMethods: MyAccountAuthenticationMethods { logger: self.logger, telemetry: self.telemetry) } + + func enrollAuthenticationMethod(type: String) -> Request { + var payload: [String: Any] = [:] + payload["type"] = type + return Request(session: session, + url: url, + method: "POST", + handle: myAcccountDecodable, + logger: logger, + telemetry: telemetry) + } - func getAuthenticationMethods() -> Request { + func enroll(email: String) -> Request { + var payload: [String: Any] = [:] + payload["type"] = "email" + payload["email"] = email + return Request(session: session, + url: url.appending("authentication-methods"), + method: "POST", + handle: myAcccountDecodable, + logger: logger, + telemetry: telemetry) + } + + func enroll(phone: String, + preferredAuthenticationMethod: String) -> Request { + var payload: [String: Any] = [:] + payload["type"] = "phone" + payload["phone_number"] = phone + payload["preferred_authentication_method"] = preferredAuthenticationMethod + return Request(session: session, + url: url.appending("authentication-methods"), + method: "POST", + handle: myAcccountDecodable, + logger: logger, + telemetry: telemetry) + } + + func getAuthenticationMethods() -> Request<[AuthenticationMethod], MyAccountError> { return Request(session: session, url: url.appending("authentication-methods"), method: "GET", @@ -136,36 +173,4 @@ struct Auth0MyAccountAuthenticationMethods: MyAccountAuthenticationMethods { logger: logger, telemetry: telemetry) } - - func enrollAuthMethod(type: String, - connection: String?, - userIdentityId: String?, - email: String?, - phoneNumber: String?, - preferredAuthenticationMethod: String?) -> Request { - var payload: [String: Any] = [:] - - payload["type"] = type - payload["connection"] = connection - payload["user_identity_id"] = userIdentityId - payload["emaail"] = email - payload["phone_number"] = phoneNumber - payload["preferred_authentication_method"] = preferredAuthenticationMethod - - return Request(session: self.session, - url: self.url.appending("authentication-methods"), - method: "", - handle: myAcccountDecodable, - logger: self.logger, - telemetry: self.telemetry) - } - - func confirmEnrollment(id: String) -> Request { - return Request(session: session, - url: url.appending("authentication-methods").appending(id).appending("verify"), - method: "POST", - handle: myAcccountDecodable, - logger: logger, - telemetry: telemetry) - } } diff --git a/Auth0/MyAccount/AuthenticationMethods/GetAuthenticationMethodsResponse.swift b/Auth0/MyAccount/AuthenticationMethods/GetAuthenticationMethodsResponse.swift index 8f0a7e70..23bd3ee2 100644 --- a/Auth0/MyAccount/AuthenticationMethods/GetAuthenticationMethodsResponse.swift +++ b/Auth0/MyAccount/AuthenticationMethods/GetAuthenticationMethodsResponse.swift @@ -1,10 +1,3 @@ -public struct AuthenticationMethods: Decodable { - public let start: Int? - public let limit: Int? - public let total: Int? - public let authenticators: [AuthenticationMethod]? -} - public struct AuthenticationMethod: Decodable { let type: String? let credentialBackedUp: Bool? diff --git a/Auth0/MyAccount/AuthenticationMethods/MyAccountAuthenticationMethods.swift b/Auth0/MyAccount/AuthenticationMethods/MyAccountAuthenticationMethods.swift index 56ce6e1e..a46b6542 100644 --- a/Auth0/MyAccount/AuthenticationMethods/MyAccountAuthenticationMethods.swift +++ b/Auth0/MyAccount/AuthenticationMethods/MyAccountAuthenticationMethods.swift @@ -117,10 +117,17 @@ public protocol MyAccountAuthenticationMethods: MyAccountClient { func enroll(passkey: NewPasskey, challenge: PasskeyEnrollmentChallenge) -> Request #endif - + + func enrollAuthenticationMethod(type: String) -> Request + + func enroll(email: String) -> Request + + func enroll(phone: String, + preferredAuthenticationMethod: String) -> Request + func deleteAuthenticationMethod(id: String) -> Request - func getAuthenticationMethods() -> Request + func getAuthenticationMethods() -> Request<[AuthenticationMethod], MyAccountError> func getFactorStatus() -> Request<[Factor], MyAccountError> @@ -131,15 +138,6 @@ public protocol MyAccountAuthenticationMethods: MyAccountClient { func updateAuthenticationMethod(id: String, name: String, preferredAuthenticationMethod: String) -> Request - - func enrollAuthMethod(type: String, - connection: String, - userIdentityId: String, - email: String, - phoneNumber: String, - preferredAuthenticationMethod: String) -> Request - - func confirmEnrollment() -> Request } // MARK: - Default Parameters From 4ed2bfe4d2d67df607f28a2f081657a40ffa24d6 Mon Sep 17 00:00:00 2001 From: Nandan Prabhu Date: Thu, 17 Jul 2025 19:00:24 +0530 Subject: [PATCH 4/5] auth methods added enrolment methods --- .../Auth0MyAccountAuthenticationMethods.swift | 98 ++++++++++++++++++- .../MyAccountAuthenticationMethods.swift | 41 ++++++-- 2 files changed, 127 insertions(+), 12 deletions(-) diff --git a/Auth0/MyAccount/AuthenticationMethods/Auth0MyAccountAuthenticationMethods.swift b/Auth0/MyAccount/AuthenticationMethods/Auth0MyAccountAuthenticationMethods.swift index 32fe1751..a5667855 100644 --- a/Auth0/MyAccount/AuthenticationMethods/Auth0MyAccountAuthenticationMethods.swift +++ b/Auth0/MyAccount/AuthenticationMethods/Auth0MyAccountAuthenticationMethods.swift @@ -1,7 +1,6 @@ import Foundation struct Auth0MyAccountAuthenticationMethods: MyAccountAuthenticationMethods { - let url: URL let session: URLSession let token: String @@ -160,8 +159,8 @@ struct Auth0MyAccountAuthenticationMethods: MyAccountAuthenticationMethods { } func updateAuthenticationMethod(id: String, - name: String, - preferredAuthenticationMethod: String) -> Request { + name: String?, + preferredAuthenticationMethod: String?) -> Request { var payload: [String: Any] = [:] payload["name"] = name payload["preferred_authentication_method"] = preferredAuthenticationMethod @@ -173,4 +172,97 @@ struct Auth0MyAccountAuthenticationMethods: MyAccountAuthenticationMethods { logger: logger, telemetry: telemetry) } + + func confirmWebAuthRoamingEnrolment(id: String, + authSession: String) -> Request { + var payload: [String: Any] = [:] + + payload["authn_session"] = authSession + + return Request(session: session, + url: url.appending("authentication-methods").appending(id).appending("verify"), + method: "POST", + handle: myAcccountDecodable, + logger: logger, + telemetry: telemetry) + } + + func confirmWebAuthPlatformEnrolment(id: String, + authSession: String) -> Request { + var payload: [String: Any] = [:] + payload["auth_session"] = authSession + return Request(session: session, + url: url.appending("authentication-methods").appending(id).appending("verify"), + method: "POST", + handle: myAcccountDecodable, + logger: logger, + telemetry: telemetry + ) + } + + func confirmTOTPEnrolment(id: String, + authSession: String, + otpCode: String) -> Request { + return Request(session: session, + url: url.appending("authentication-methods").appending(id).appending("verify"), + method: "POST", + handle: myAcccountDecodable, + logger: logger, + telemetry: telemetry) + } + + func confirmEmailEnrolment(id: String, + authSession: String, + otpCode: String) -> Request { + var payload: [String: Any] = [:] + payload["auth_session"] = authSession + payload["otp_code"] = otpCode + return Request(session: session, + url: url.appending("authentication-methods").appending(id).appending("verify"), + method: "POST", + handle: myAcccountDecodable, + logger: logger, + telemetry: telemetry) + } + + func confirmPushNotificationEnrolment(id: String, + authSession: String) -> Request { + var payload: [String: Any] = [:] + payload["auth_session"] = authSession + payload["id"] = id + + return Request(session: session, + url: url.appending("authentication-methods").appending(id).appending("verify"), + method: "POST", + handle: myAcccountDecodable, + logger: logger, + telemetry: telemetry) + } + + func confirmPhoneEnrolment(id: String, + authSession: String, + otpCode: String) -> Request { + var payload: [String: Any] = [:] + payload["auth_session"] = authSession + payload["id"] = id + payload["otp_code"] = otpCode + return Request(session: session, + url: url.appending("authentication-methods").appending(id).appending("verify"), + method: "POST", + handle: myAcccountDecodable, + logger: logger, + telemetry: telemetry) + } + + func confirmRecoveryCodeEnrolment(id: String, + authSession: String) -> Request { + var payload: [String: Any] = [:] + payload["auth_session"] = authSession + return Request(session: session, + url: url.appending("authentication-methods").appending(id).appending("verify"), + method: "POST", + handle: myAcccountDecodable, + logger: logger, + telemetry: telemetry) + } } diff --git a/Auth0/MyAccount/AuthenticationMethods/MyAccountAuthenticationMethods.swift b/Auth0/MyAccount/AuthenticationMethods/MyAccountAuthenticationMethods.swift index a46b6542..8dcce034 100644 --- a/Auth0/MyAccount/AuthenticationMethods/MyAccountAuthenticationMethods.swift +++ b/Auth0/MyAccount/AuthenticationMethods/MyAccountAuthenticationMethods.swift @@ -117,16 +117,16 @@ public protocol MyAccountAuthenticationMethods: MyAccountClient { func enroll(passkey: NewPasskey, challenge: PasskeyEnrollmentChallenge) -> Request #endif - + + func deleteAuthenticationMethod(id: String) -> Request + func enrollAuthenticationMethod(type: String) -> Request - + func enroll(email: String) -> Request - + func enroll(phone: String, preferredAuthenticationMethod: String) -> Request - func deleteAuthenticationMethod(id: String) -> Request - func getAuthenticationMethods() -> Request<[AuthenticationMethod], MyAccountError> func getFactorStatus() -> Request<[Factor], MyAccountError> @@ -134,12 +134,35 @@ public protocol MyAccountAuthenticationMethods: MyAccountClient { func getAuthenticationMethod(id: String) -> Request func deleteAuthenticationMethod(id: String) -> Request - + func updateAuthenticationMethod(id: String, - name: String, - preferredAuthenticationMethod: String) -> Request -} + name: String?, + preferredAuthenticationMethod: String?) -> Request + + func confirmWebAuthRoamingEnrolment(id: String, + authSession: String) -> Request + + func confirmWebAuthPlatformEnrolment(id: String, + authSession: String) -> Request + + func confirmTOTPEnrolment(id: String, + authSession: String, + otpCode: String) -> Request + func confirmEmailEnrolment(id: String, + authSession: String, + otpCode: String) -> Request + + func confirmPushNotificationEnrolment(id: String, + authSession: String) -> Request + + func confirmPhoneEnrolment(id: String, + authSession: String, + otpCode: String) -> Request + + func confirmRecoveryCodeEnrolment(id: String, + authSession: String) -> Request +} // MARK: - Default Parameters public extension MyAccountAuthenticationMethods { From 8487bd22d5c15d3bb441cc85dd341b0c55b82b61 Mon Sep 17 00:00:00 2001 From: Nandan Prabhu Date: Mon, 21 Jul 2025 08:08:43 +0530 Subject: [PATCH 5/5] added UTs --- Auth0.xcodeproj/project.pbxproj | 10 +- .../Auth0MyAccountAuthenticationMethods.swift | 13 +-- .../MyAccountAuthenticationMethods.swift | 4 +- .../PasskeyEnrollmentChallenge.swift | 2 +- .../MyAccountAuthenticationMethodsSpec.swift | 105 ++++++++++++++++++ 5 files changed, 114 insertions(+), 20 deletions(-) diff --git a/Auth0.xcodeproj/project.pbxproj b/Auth0.xcodeproj/project.pbxproj index 76f7f891..1cd35a8a 100644 --- a/Auth0.xcodeproj/project.pbxproj +++ b/Auth0.xcodeproj/project.pbxproj @@ -3554,10 +3554,9 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ANALYZER_NONNULL = YES; CODE_SIGN_IDENTITY = "Apple Development"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CODE_SIGN_STYLE = Manual; + CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = 86WQXF56BC; INFOPLIST_FILE = App/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( @@ -3578,10 +3577,9 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ANALYZER_NONNULL = YES; CODE_SIGN_IDENTITY = "Apple Development"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CODE_SIGN_STYLE = Manual; + CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = 86WQXF56BC; INFOPLIST_FILE = App/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Auth0/MyAccount/AuthenticationMethods/Auth0MyAccountAuthenticationMethods.swift b/Auth0/MyAccount/AuthenticationMethods/Auth0MyAccountAuthenticationMethods.swift index a5667855..2d159b71 100644 --- a/Auth0/MyAccount/AuthenticationMethods/Auth0MyAccountAuthenticationMethods.swift +++ b/Auth0/MyAccount/AuthenticationMethods/Auth0MyAccountAuthenticationMethods.swift @@ -149,15 +149,6 @@ struct Auth0MyAccountAuthenticationMethods: MyAccountAuthenticationMethods { telemetry: telemetry) } - func deleteAuthenticationMethod(id: String) -> Request { - return Request(session: session, - url: url.appending("authentication-methods").appending(id), - method: "GET", - handle: myAcccountDecodable, - logger: logger, - telemetry: telemetry) - } - func updateAuthenticationMethod(id: String, name: String?, preferredAuthenticationMethod: String?) -> Request { @@ -176,7 +167,6 @@ struct Auth0MyAccountAuthenticationMethods: MyAccountAuthenticationMethods { func confirmWebAuthRoamingEnrolment(id: String, authSession: String) -> Request { var payload: [String: Any] = [:] - payload["authn_session"] = authSession return Request(session: session, @@ -203,6 +193,9 @@ struct Auth0MyAccountAuthenticationMethods: MyAccountAuthenticationMethods { func confirmTOTPEnrolment(id: String, authSession: String, otpCode: String) -> Request { + var payload: [String: Any] = [:] + payload["auth_session"] = authSession + payload["otp_code"] = otpCode return Request(session: session, url: url.appending("authentication-methods").appending(id).appending("verify"), method: "POST", diff --git a/Auth0/MyAccount/AuthenticationMethods/MyAccountAuthenticationMethods.swift b/Auth0/MyAccount/AuthenticationMethods/MyAccountAuthenticationMethods.swift index 8dcce034..0fbbd986 100644 --- a/Auth0/MyAccount/AuthenticationMethods/MyAccountAuthenticationMethods.swift +++ b/Auth0/MyAccount/AuthenticationMethods/MyAccountAuthenticationMethods.swift @@ -126,15 +126,13 @@ public protocol MyAccountAuthenticationMethods: MyAccountClient { func enroll(phone: String, preferredAuthenticationMethod: String) -> Request - + func getAuthenticationMethods() -> Request<[AuthenticationMethod], MyAccountError> func getFactorStatus() -> Request<[Factor], MyAccountError> func getAuthenticationMethod(id: String) -> Request - func deleteAuthenticationMethod(id: String) -> Request - func updateAuthenticationMethod(id: String, name: String?, preferredAuthenticationMethod: String?) -> Request diff --git a/Auth0/MyAccount/AuthenticationMethods/PasskeyEnrollmentChallenge.swift b/Auth0/MyAccount/AuthenticationMethods/PasskeyEnrollmentChallenge.swift index fabc6d4f..cd7ed249 100644 --- a/Auth0/MyAccount/AuthenticationMethods/PasskeyEnrollmentChallenge.swift +++ b/Auth0/MyAccount/AuthenticationMethods/PasskeyEnrollmentChallenge.swift @@ -32,7 +32,7 @@ extension PasskeyEnrollmentChallenge: Decodable { case id case barcodeURI = "barcode_uri" case manualInputCode = "manual_input_code" - case recovery_code = "recovery_code" + case recoveryCode = "recovery_code" } /// `Decodable` initializer. diff --git a/Auth0Tests/MyAccount/AuthenticationMethods/MyAccountAuthenticationMethodsSpec.swift b/Auth0Tests/MyAccount/AuthenticationMethods/MyAccountAuthenticationMethodsSpec.swift index 5480e24d..aef7c6b2 100644 --- a/Auth0Tests/MyAccount/AuthenticationMethods/MyAccountAuthenticationMethodsSpec.swift +++ b/Auth0Tests/MyAccount/AuthenticationMethods/MyAccountAuthenticationMethodsSpec.swift @@ -264,6 +264,111 @@ class MyAccountAuthenticationMethodsSpec: QuickSpec { } #endif + describe("MyAccountService") { + it("creates DELETE request for deleteAuthenticationMethod") { + let request = authMethods.deleteAuthenticationMethod(id: "124") + expect(request.method) == "DELETE" + expect(request.url.absoluteString) == "https://example.com/api/authentication-methodsabc123" + } + + it("creates POST request for enrollAuthenticationMethod") { + let request = authMethods.enrollAuthenticationMethod(type: "passkey") + expect(request.method) == "POST" + expect(request.url.absoluteString) == "https://example.com/api/" + // payload not set — maybe that's a bug? + } + + it("creates POST request for enroll(email:)") { + let request = authMethods.enroll(email: "me@example.com") + expect(request.method) == "POST" + expect(request.url.absoluteString) == "https://example.com/api/authentication-methods" + expect(request.parameters["type"] as? String) == "email" + expect(request.parameters["email"] as? String) == "me@example.com" + } + + it("creates POST request for enroll(phone:)") { + let request = authMethods.enroll(phone: "1234567890", preferredAuthenticationMethod: "sms") + expect(request.method) == "POST" + expect(request.url.absoluteString) == "https://example.com/api/authentication-methods" + expect(request.parameters["type"] as? String) == "phone" + expect(request.parameters["phone_number"] as? String) == "1234567890" + expect(request.parameters["preferred_authentication_method"] as? String) == "sms" + } + + it("creates GET request for getAuthenticationMethods") { + let request = authMethods.getAuthenticationMethods() + expect(request.method) == "GET" + expect(request.url.absoluteString) == "https://example.com/api/authentication-methods" + } + + it("creates GET request for getFactorStatus") { + let request = authMethods.getFactorStatus() + expect(request.method) == "GET" + expect(request.url.absoluteString) == "https://example.com/api/factors" + } + + it("creates GET request for getAuthenticationMethod") { + let request = authMethods.getAuthenticationMethod(id: "abc123") + expect(request.method) == "GET" + expect(request.url.absoluteString) == "https://example.com/api/authentication-methodsabc123" + } + + it("creates PATCH request for updateAuthenticationMethod") { + let request = authMethods.updateAuthenticationMethod(id: "abc123", name: "New Name", preferredAuthenticationMethod: "email") + expect(request.method) == "PATCH" + expect(request.url.absoluteString) == "https://example.com/api/authentication-methodsabc123" + expect(request.parameters["name"] as? String) == "New Name" + expect(request.parameters["preferred_authentication_method"] as? String) == "email" + } + it("creates POST request for confirmWebAuthRoamingEnrolment") { + let request = authMethods.confirmWebAuthRoamingEnrolment(id: "abc123", authSession: "sess1") + expect(request.method) == "POST" + expect(request.url.absoluteString) == "https://example.com/api/authentication-methodsabc123verify" + expect(request.parameters["authn_session"] as? String) == "sess1" + } + + it("creates POST request for confirmWebAuthPlatformEnrolment") { + let request = authMethods.confirmWebAuthPlatformEnrolment(id: "abc123", authSession: "sess2") + expect(request.method) == "POST" + expect(request.url.absoluteString) == "https://example.com/api/authentication-methodsabc123verify" + expect(request.parameters["auth_session"] as? String) == "sess2" + } + + it("creates POST request for confirmTOTPEnrolment") { + let request = authMethods.confirmTOTPEnrolment(id: "abc123", authSession: "sess3", otpCode: "000000") + expect(request.method) == "POST" + expect(request.parameters["auth_session"] as? String) == "sess3" + expect(request.parameters["otp_code"] as? String) == "000000" + } + + it("creates POST request for confirmEmailEnrolment") { + let request = authMethods.confirmEmailEnrolment(id: "abc123", authSession: "sess4", otpCode: "123456") + expect(request.method) == "POST" + expect(request.parameters["auth_session"] as? String) == "sess4" + expect(request.parameters["otp_code"] as? String) == "123456" + } + + it("creates POST request for confirmPushNotificationEnrolment") { + let request = authMethods.confirmPushNotificationEnrolment(id: "abc123", authSession: "sess5") + expect(request.method) == "POST" + expect(request.parameters["auth_session"] as? String) == "sess5" + expect(request.parameters["id"] as? String) == "abc123" + } + + it("creates POST request for confirmPhoneEnrolment") { + let request = authMethods.confirmPhoneEnrolment(id: "abc123", authSession: "sess6", otpCode: "654321") + expect(request.method) == "POST" + expect(request.parameters["auth_session"] as? String) == "sess6" + expect(request.parameters["id"] as? String) == "abc123" + expect(request.parameters["otp_code"] as? String) == "654321" + } + + it("creates POST request for confirmRecoveryCodeEnrolment") { + let request = authMethods.confirmRecoveryCodeEnrolment(id: "abc123", authSession: "sess7") + expect(request.method) == "POST" + expect(request.parameters["auth_session"] as? String) == "sess7" + } + } } }