From 029efbd9ecacfbcd6a9f01b1540a44491a359688 Mon Sep 17 00:00:00 2001 From: Eric Jensen Date: Wed, 27 Jan 2021 21:06:16 -0800 Subject: [PATCH 1/6] Add support for starting MFA challenges and logging in with OOB and recovery codes --- Auth0.xcodeproj/project.pbxproj | 10 ++++ Auth0/Auth0Authentication.swift | 67 ++++++++++++++++++++++++++ Auth0/Authentication.swift | 34 +++++++++++++ Auth0/Challenge.swift | 33 +++++++++++++ Auth0Tests/AuthenticationSpec.swift | 74 ++++++++++++++++++++++++++++- Auth0Tests/Responses.swift | 2 + 6 files changed, 219 insertions(+), 1 deletion(-) create mode 100644 Auth0/Challenge.swift diff --git a/Auth0.xcodeproj/project.pbxproj b/Auth0.xcodeproj/project.pbxproj index b83ce1f8..f1e8b031 100644 --- a/Auth0.xcodeproj/project.pbxproj +++ b/Auth0.xcodeproj/project.pbxproj @@ -352,6 +352,10 @@ 5FF2866F1D8A417B00314B72 /* _ObjectiveWebAuth.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FF2866E1D8A417B00314B72 /* _ObjectiveWebAuth.swift */; }; 5FF465BC1CE2AC4500F7ED8C /* Management.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FF465BB1CE2AC4500F7ED8C /* Management.swift */; }; 5FF465BD1CE2AC4500F7ED8C /* Management.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FF465BB1CE2AC4500F7ED8C /* Management.swift */; }; + 970BC36B25C27095007A7745 /* Challenge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 970BC36A25C27095007A7745 /* Challenge.swift */; }; + 970BC36C25C27095007A7745 /* Challenge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 970BC36A25C27095007A7745 /* Challenge.swift */; }; + 970BC36D25C27095007A7745 /* Challenge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 970BC36A25C27095007A7745 /* Challenge.swift */; }; + 970BC36E25C27095007A7745 /* Challenge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 970BC36A25C27095007A7745 /* Challenge.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -655,6 +659,7 @@ 5FF346491CEFEC04000799DE /* Auth0Tests.iOS-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Auth0Tests.iOS-Bridging-Header.h"; sourceTree = ""; }; 5FF3464A1CEFEC04000799DE /* Auth0Tests.OSX-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Auth0Tests.OSX-Bridging-Header.h"; sourceTree = ""; }; 5FF465BB1CE2AC4500F7ED8C /* Management.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Management.swift; path = Auth0/Management.swift; sourceTree = SOURCE_ROOT; }; + 970BC36A25C27095007A7745 /* Challenge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Challenge.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -1192,6 +1197,7 @@ 5C4F552223C8FBA100C89615 /* JWKS.swift */, 5FDE874E1D8A424700EA27DC /* Credentials.swift */, 5FDE874F1D8A424700EA27DC /* Handlers.swift */, + 970BC36A25C27095007A7745 /* Challenge.swift */, ); name = Authentication; sourceTree = ""; @@ -1848,6 +1854,7 @@ 5FDE876D1D8A424700EA27DC /* Handlers.swift in Sources */, 5FF2866F1D8A417B00314B72 /* _ObjectiveWebAuth.swift in Sources */, 5FE2F8BB1CD0EAAD003628F4 /* Response.swift in Sources */, + 970BC36B25C27095007A7745 /* Challenge.swift in Sources */, 5FCCC31C1CF51DF300901E2E /* _ObjectiveManagementAPI.swift in Sources */, 5FDE87591D8A424700EA27DC /* Authentication.swift in Sources */, 5B16D88F1F7141A0009476A5 /* SafariSession.swift in Sources */, @@ -1973,6 +1980,7 @@ 5C41F6D9244F977900252548 /* WebAuthError.swift in Sources */, 5FCAB1741D09009600331C84 /* NSData+URLSafe.swift in Sources */, 5F7504F61D8C3F2900E3BA1C /* NSError+Helper.swift in Sources */, + 970BC36C25C27095007A7745 /* Challenge.swift in Sources */, 5C41F6DD244F982700252548 /* DesktopWebAuth.swift in Sources */, 5FCAB17A1D09124D00331C84 /* NSURL+Auth0.swift in Sources */, 5FDE87521D8A424700EA27DC /* _ObjectiveAuthenticationAPI.swift in Sources */, @@ -2076,6 +2084,7 @@ 5CC9940424ED9EC90027DC74 /* CredentialsManagerError.swift in Sources */, 5F23E6EA1D4ACD9600C3F2D9 /* Auth0Error.swift in Sources */, 5FDE876F1D8A424700EA27DC /* Handlers.swift in Sources */, + 970BC36D25C27095007A7745 /* Challenge.swift in Sources */, 5FDE87571D8A424700EA27DC /* Auth0Authentication.swift in Sources */, 5C4F552523C8FBA100C89615 /* JWKS.swift in Sources */, 5F23E6E51D4ACD8500C3F2D9 /* Request.swift in Sources */, @@ -2114,6 +2123,7 @@ 5F23E7111D4B88FC00C3F2D9 /* Result.swift in Sources */, 5FDE87701D8A424700EA27DC /* Handlers.swift in Sources */, 5C4F551D23C8FB8E00C89615 /* String+URLSafe.swift in Sources */, + 970BC36E25C27095007A7745 /* Challenge.swift in Sources */, 5FDE87581D8A424700EA27DC /* Auth0Authentication.swift in Sources */, 5F23E7071D4B88EA00C3F2D9 /* NSURL+Auth0.swift in Sources */, 5F23E71A1D4B891E00C3F2D9 /* Auth0.swift in Sources */, diff --git a/Auth0/Auth0Authentication.swift b/Auth0/Auth0Authentication.swift index 66463c22..f3ed0c44 100644 --- a/Auth0/Auth0Authentication.swift +++ b/Auth0/Auth0Authentication.swift @@ -133,6 +133,73 @@ struct Auth0Authentication: Authentication { telemetry: self.telemetry) } + func login(withOOBCode oobCode: String, mfaToken: String, bindingCode: String?) -> Request { + let url = URL(string: "/oauth/token", relativeTo: self.url)! + var payload: [String: Any] = [ + "oob_code": oobCode, + "mfa_token": mfaToken, + "grant_type": "http://auth0.com/oauth/grant-type/mfa-oob", + "client_id": self.clientId + ] + + if let bindingCode = bindingCode { + payload["binding_code"] = bindingCode + } + + return Request(session: session, + url: url, + method: "POST", + handle: authenticationObject, + payload: payload, + logger: self.logger, + telemetry: self.telemetry) + } + + func login(withRecoveryCode recoveryCode: String, mfaToken: String) -> Request { + let url = URL(string: "/oauth/token", relativeTo: self.url)! + let payload: [String: Any] = [ + "recovery_code": recoveryCode, + "mfa_token": mfaToken, + "grant_type": "http://auth0.com/oauth/grant-type/mfa-recovery-code", + "client_id": self.clientId + ] + return Request(session: session, + url: url, + method: "POST", + handle: authenticationObject, + payload: payload, + logger: self.logger, + telemetry: self.telemetry) + } + + func multifactorChallenge(mfaToken: String, types: [String]?, channel: String?, authenticatorId: String?) -> Request { + let url = URL(string: "/mfa/challenge", relativeTo: self.url)! + var payload: [String: String] = [ + "mfa_token": mfaToken, + "client_id": self.clientId + ] + + if let types = types { + payload["challenge_type"] = types.joined(separator: " ") + } + + if let channel = channel { + payload["oob_channel"] = channel + } + + if let authenticatorId = authenticatorId { + payload["authenticator_id"] = authenticatorId + } + + return Request(session: session, + url: url, + method: "POST", + handle: codable, + payload: payload, + logger: self.logger, + telemetry: self.telemetry) + } + func login(appleAuthorizationCode authorizationCode: String, fullName: PersonNameComponents?, profile: [String: Any]?, scope: String?, audience: String?) -> Request { var parameters: [String: Any] = [:] var profile: [String: Any] = profile ?? [:] diff --git a/Auth0/Authentication.swift b/Auth0/Authentication.swift index a5f2f006..93a3cb2e 100644 --- a/Auth0/Authentication.swift +++ b/Auth0/Authentication.swift @@ -233,6 +233,40 @@ public protocol Authentication: Trackable, Loggable { */ func login(withOTP otp: String, mfaToken: String) -> Request + /// Verifies multi-factor authentication (MFA) using an out-of-band (OOB) challenge (either Push notification, SMS, or Voice). + /// + /// - Parameters: + /// - oobCode: The oob code received from the challenge request + /// - mfaToken: Token returned when authentication fails due to MFA requirement + /// - bindingCode: A code used to bind the side channel (used to deliver the challenge) with the main channel you are using to authenticate. This is usually an OTP-like code delivered as part of the challenge message + /// + /// - returns: authentication request that will yield Auth0 User Credentials + /// - requires: Grant `http://auth0.com/oauth/grant-type/mfa-oob`. Check [our documentation](https://auth0.com/docs/clients/client-grant-types) for more info and how to enable it. + func login(withOOBCode oobCode: String, mfaToken: String, bindingCode: String?) -> Request + + /// Verifies multi-factor authentication (MFA) using a recovery code. + /// Some multi-factor authentication (MFA) providers (such as Guardian) support using a recovery code to login. Use this method to authenticate when the user's enrolled device is unavailable, or the user cannot receive the challenge or accept it due to connectivity issues. + /// + /// - Parameters: + /// - recoveryCode: Recovery code provided by the end-user + /// - mfaToken: Token returned when authentication fails due to MFA requirement + /// + /// - returns: authentication request that will yield Auth0 User Credentials + /// - requires: Grant `http://auth0.com/oauth/grant-type/mfa-recovery-code`. Check [our documentation](https://auth0.com/docs/clients/client-grant-types) for more info and how to enable it. + func login(withRecoveryCode recoveryCode: String, mfaToken: String) -> Request + + /// Request a challenge for multi-factor authentication (MFA) based on the challenge types supported by the application and user. + /// The `type` is how the user will get the challenge and prove possession. Supported challenge types include: + /// `otp`: for one-time password (OTP) + /// `oob`: for SMS/Voice messages or out-of-band (OOB) + /// + /// - Parameters: + /// - mfaToken: Token returned when authentication fails due to MFA requirement + /// - types: A list of the challenges types accepted by your application. Accepted challenge types are `oob` or `otp`. Excluding this parameter means that your client application accepts all supported challenge types + /// - channel: The channel to use for OOB. Can only be provided when challenge type is `oob`. Accepted values are `sms`, `voice`, or `auth0`. Excluding this parameter means that your client application will accept all supported OOB channels + /// - authenticatorId: The ID of the authenticator to challenge. You can get the ID by querying the list of available authenticators for the user + func multifactorChallenge(mfaToken: String, types: [String]?, channel: String?, authenticatorId: String?) -> Request + /** Authenticate a user with their Sign In With Apple authorization code. diff --git a/Auth0/Challenge.swift b/Auth0/Challenge.swift new file mode 100644 index 00000000..4d0f2125 --- /dev/null +++ b/Auth0/Challenge.swift @@ -0,0 +1,33 @@ +// Challenge.swift +// +// Copyright (c) 2021 Auth0 (http://auth0.com) +// +// 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. + +public struct Challenge: Codable { + public let challengeType: String + public let oobCode: String? + public let bindingMethod: String? + + public enum CodingKeys: String, CodingKey { + case challengeType = "challenge_type" + case oobCode = "oob_code" + case bindingMethod = "binding_method" + } +} diff --git a/Auth0Tests/AuthenticationSpec.swift b/Auth0Tests/AuthenticationSpec.swift index bf6fc851..659eb83b 100644 --- a/Auth0Tests/AuthenticationSpec.swift +++ b/Auth0Tests/AuthenticationSpec.swift @@ -147,7 +147,7 @@ class AuthenticationSpec: QuickSpec { } - describe("login MFA") { + describe("login MFA OTP") { beforeEach { stub(condition: isToken(Domain) && hasAtLeast(["otp": OTP, "mfa_token": MFAToken])) { _ in return authResponse(accessToken: AccessToken, idToken: IdToken) }.name = "OpenID Auth" @@ -183,6 +183,78 @@ class AuthenticationSpec: QuickSpec { } } + describe("login MFA OOB") { + + beforeEach { + stub(condition: isToken(Domain) && hasAtLeast(["oob_code": OOB, "mfa_token": MFAToken])) { _ in return authResponse(accessToken: AccessToken, idToken: IdToken) }.name = "OpenID Auth" + stub(condition: isToken(Domain) && hasAtLeast(["oob_code": "bad_oob", "mfa_token": MFAToken])) { _ in return authFailure(code: "invalid_grant", description: "Invalid oob_code.") }.name = "invalid oob_code" + stub(condition: isToken(Domain) && hasAtLeast(["oob_code": OOB, "mfa_token": "bad_token"])) { _ in return authFailure(code: "invalid_grant", description: "Malformed mfa_token") }.name = "invalid mfa_token" + } + + it("should login with oob code and mfa tokens") { + waitUntil(timeout: Timeout) { done in + auth.login(withOOBCode: OOB, mfaToken: MFAToken, bindingCode: nil).start { result in + expect(result).to(haveCredentials()) + done() + } + } + } + + it("should fail login with bad oob code") { + waitUntil(timeout: Timeout) { done in + auth.login(withOOBCode: "bad_oob", mfaToken: MFAToken, bindingCode: nil).start { result in + expect(result).to(haveAuthenticationError(code: "invalid_grant", description: "Invalid oob_code.")) + done() + } + } + } + + it("should fail login with invalid mfa") { + waitUntil(timeout: Timeout) { done in + auth.login(withOOBCode: OOB, mfaToken: "bad_token", bindingCode: nil).start { result in + expect(result).to(haveAuthenticationError(code: "invalid_grant", description: "Malformed mfa_token")) + done() + } + } + } + } + + describe("login MFA recovery code") { + + beforeEach { + stub(condition: isToken(Domain) && hasAtLeast(["recovery_code": RecoveryCode, "mfa_token": MFAToken])) { _ in return authResponse(accessToken: AccessToken, idToken: IdToken) }.name = "OpenID Auth" + stub(condition: isToken(Domain) && hasAtLeast(["recovery_code": "bad_recovery", "mfa_token": MFAToken])) { _ in return authFailure(code: "invalid_grant", description: "Invalid recovery_code.") }.name = "invalid recovery code" + stub(condition: isToken(Domain) && hasAtLeast(["recovery_code": RecoveryCode, "mfa_token": "bad_token"])) { _ in return authFailure(code: "invalid_grant", description: "Malformed mfa_token") }.name = "invalid mfa_token" + } + + it("should login with recovery code and mfa tokens") { + waitUntil(timeout: Timeout) { done in + auth.login(withRecoveryCode: RecoveryCode, mfaToken: MFAToken).start { result in + expect(result).to(haveCredentials()) + done() + } + } + } + + it("should fail login with bad recovery code") { + waitUntil(timeout: Timeout) { done in + auth.login(withRecoveryCode: "bad_recovery", mfaToken: MFAToken).start { result in + expect(result).to(haveAuthenticationError(code: "invalid_grant", description: "Invalid recovery_code.")) + done() + } + } + } + + it("should fail login with invalid mfa") { + waitUntil(timeout: Timeout) { done in + auth.login(withRecoveryCode: RecoveryCode, mfaToken: "bad_token").start { result in + expect(result).to(haveAuthenticationError(code: "invalid_grant", description: "Malformed mfa_token")) + done() + } + } + } + } + // MARK:- Refresh Tokens describe("renew auth with refresh token") { diff --git a/Auth0Tests/Responses.swift b/Auth0Tests/Responses.swift index 0be279b1..431b1893 100644 --- a/Auth0Tests/Responses.swift +++ b/Auth0Tests/Responses.swift @@ -43,6 +43,8 @@ let Sub = "auth0|\(UUID().uuidString.replacingOccurrences(of: "-", with: ""))" let LocaleUS = "en-US" let ZoneEST = "US/Eastern" let OTP = "123456" +let OOB = "654321" +let RecoveryCode = "162534" let MFAToken = UUID().uuidString.replacingOccurrences(of: "-", with: "") let JWKKid = "key123" From 83a6bd694fe740295c9cfc940ad20989c0f729db Mon Sep 17 00:00:00 2001 From: Rita Zerrizuela Date: Mon, 1 Feb 2021 16:49:47 -0300 Subject: [PATCH 2/6] Fix linter warning --- Auth0/Auth0Authentication.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Auth0/Auth0Authentication.swift b/Auth0/Auth0Authentication.swift index f3ed0c44..c073fbb4 100644 --- a/Auth0/Auth0Authentication.swift +++ b/Auth0/Auth0Authentication.swift @@ -24,6 +24,7 @@ import Foundation +// swiftlint:disable:next type_body_length struct Auth0Authentication: Authentication { let clientId: String From 5f2619a42986516cf1bcbc39d9809fc9140e3d52 Mon Sep 17 00:00:00 2001 From: Rita Zerrizuela Date: Mon, 1 Feb 2021 19:47:05 -0300 Subject: [PATCH 3/6] Add BindingCode --- Auth0Tests/Responses.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Auth0Tests/Responses.swift b/Auth0Tests/Responses.swift index 431b1893..731b8c7b 100644 --- a/Auth0Tests/Responses.swift +++ b/Auth0Tests/Responses.swift @@ -44,6 +44,7 @@ let LocaleUS = "en-US" let ZoneEST = "US/Eastern" let OTP = "123456" let OOB = "654321" +let BindingCode = "214365" let RecoveryCode = "162534" let MFAToken = UUID().uuidString.replacingOccurrences(of: "-", with: "") let JWKKid = "key123" From 0041bd2b12e2ed4c4ca6ec4afa1726d1c4c091dd Mon Sep 17 00:00:00 2001 From: Rita Zerrizuela Date: Mon, 1 Feb 2021 19:47:38 -0300 Subject: [PATCH 4/6] Use BindingCode in tests --- Auth0Tests/AuthenticationSpec.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Auth0Tests/AuthenticationSpec.swift b/Auth0Tests/AuthenticationSpec.swift index 659eb83b..745631ac 100644 --- a/Auth0Tests/AuthenticationSpec.swift +++ b/Auth0Tests/AuthenticationSpec.swift @@ -186,14 +186,14 @@ class AuthenticationSpec: QuickSpec { describe("login MFA OOB") { beforeEach { - stub(condition: isToken(Domain) && hasAtLeast(["oob_code": OOB, "mfa_token": MFAToken])) { _ in return authResponse(accessToken: AccessToken, idToken: IdToken) }.name = "OpenID Auth" + stub(condition: isToken(Domain) && hasAtLeast(["oob_code": OOB, "mfa_token": MFAToken, "binding_code": BindingCode])) { _ in return authResponse(accessToken: AccessToken, idToken: IdToken) }.name = "OpenID Auth" stub(condition: isToken(Domain) && hasAtLeast(["oob_code": "bad_oob", "mfa_token": MFAToken])) { _ in return authFailure(code: "invalid_grant", description: "Invalid oob_code.") }.name = "invalid oob_code" stub(condition: isToken(Domain) && hasAtLeast(["oob_code": OOB, "mfa_token": "bad_token"])) { _ in return authFailure(code: "invalid_grant", description: "Malformed mfa_token") }.name = "invalid mfa_token" } it("should login with oob code and mfa tokens") { waitUntil(timeout: Timeout) { done in - auth.login(withOOBCode: OOB, mfaToken: MFAToken, bindingCode: nil).start { result in + auth.login(withOOBCode: OOB, mfaToken: MFAToken, bindingCode: BindingCode).start { result in expect(result).to(haveCredentials()) done() } From b0fb3b2ee5e79010d1d5e796b714c3c7c4e1de58 Mon Sep 17 00:00:00 2001 From: Eric Jensen Date: Tue, 2 Feb 2021 16:51:54 -0800 Subject: [PATCH 5/6] Add tests for multifactorChallenge --- Auth0Tests/AuthenticationSpec.swift | 25 +++++++++++++++++++++++++ Auth0Tests/Matchers.swift | 4 ++++ Auth0Tests/Responses.swift | 7 +++++++ 3 files changed, 36 insertions(+) diff --git a/Auth0Tests/AuthenticationSpec.swift b/Auth0Tests/AuthenticationSpec.swift index 745631ac..f725d33a 100644 --- a/Auth0Tests/AuthenticationSpec.swift +++ b/Auth0Tests/AuthenticationSpec.swift @@ -255,6 +255,31 @@ class AuthenticationSpec: QuickSpec { } } + // MARK:- MFA Challenge + + describe("MFA challenge") { + + beforeEach { + stub(condition: isMultifactorChallenge(Domain) && hasAtLeast([ + "mfa_token": MFAToken, + "client_id": ClientId, + "challenge_type": "oob otp", + "oob_channel": OOBChannel, + "authenticator_id": AuthenticatorId + ])) { _ in return multifactorChallengeResponse(challengeType: "oob") }.name = "MFA Challenge" + } + + it("should request without filters") { + waitUntil(timeout: Timeout) { done in + auth.multifactorChallenge(mfaToken: MFAToken, types: ChallengeTypes, channel: OOBChannel, authenticatorId: AuthenticatorId).start { result in + expect(result).to(beSuccessful()) + done() + } + } + } + + } + // MARK:- Refresh Tokens describe("renew auth with refresh token") { diff --git a/Auth0Tests/Matchers.swift b/Auth0Tests/Matchers.swift index 5ead2705..4bb429e7 100644 --- a/Auth0Tests/Matchers.swift +++ b/Auth0Tests/Matchers.swift @@ -140,6 +140,10 @@ func isJWKSPath(_ domain: String) -> HTTPStubsTestBlock { return isHost(domain) && isPath("/.well-known/jwks.json") } +func isMultifactorChallenge(_ domain: String) -> HTTPStubsTestBlock { + return isMethodPOST() && isHost(domain) && isPath("/mfa/challenge") +} + func hasBearerToken(_ token: String) -> HTTPStubsTestBlock { return { request in return request.value(forHTTPHeaderField: "Authorization") == "Bearer \(token)" diff --git a/Auth0Tests/Responses.swift b/Auth0Tests/Responses.swift index 731b8c7b..f73cb8f4 100644 --- a/Auth0Tests/Responses.swift +++ b/Auth0Tests/Responses.swift @@ -44,9 +44,12 @@ let LocaleUS = "en-US" let ZoneEST = "US/Eastern" let OTP = "123456" let OOB = "654321" +let OOBChannel = "sms" let BindingCode = "214365" let RecoveryCode = "162534" let MFAToken = UUID().uuidString.replacingOccurrences(of: "-", with: "") +let AuthenticatorId = UUID().uuidString.replacingOccurrences(of: "-", with: "") +let ChallengeTypes = ["oob", "otp"] let JWKKid = "key123" func authResponse(accessToken: String, idToken: String? = nil, refreshToken: String? = nil, expiresIn: Double? = nil) -> HTTPStubsResponse { @@ -152,3 +155,7 @@ func jwksResponse(kid: String? = JWKKid) -> HTTPStubsResponse { func jwksErrorResponse() -> HTTPStubsResponse { return HTTPStubsResponse(jsonObject: [], statusCode: 500, headers: nil) } + +func multifactorChallengeResponse(challengeType: String, oobCode: String? = nil, bindingMethod: String? = nil) -> HTTPStubsResponse { + return HTTPStubsResponse(jsonObject: ["challenge_type": challengeType, "oob_code": oobCode, "binding_method": bindingMethod], statusCode: 200, headers: nil) +} From 202aeb8d67791752c33c93cfc586052d4ceceff8 Mon Sep 17 00:00:00 2001 From: Rita Zerrizuela Date: Thu, 4 Feb 2021 09:20:46 -0300 Subject: [PATCH 6/6] Kickstart CI --- Auth0/Auth0Authentication.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Auth0/Auth0Authentication.swift b/Auth0/Auth0Authentication.swift index c073fbb4..0fc594b1 100644 --- a/Auth0/Auth0Authentication.swift +++ b/Auth0/Auth0Authentication.swift @@ -164,6 +164,7 @@ struct Auth0Authentication: Authentication { "grant_type": "http://auth0.com/oauth/grant-type/mfa-recovery-code", "client_id": self.clientId ] + return Request(session: session, url: url, method: "POST",