From 586e1440cd92ecce9ddf9b313e6c9178c1b6c466 Mon Sep 17 00:00:00 2001 From: metalurgical <97008724+metalurgical@users.noreply.github.com> Date: Mon, 17 Jun 2024 03:35:38 +0200 Subject: [PATCH] cleanup returned errors --- .../CustomAuthDemo.xcodeproj/project.pbxproj | 28 ++++++- .../xcshareddata/WorkspaceSettings.xcsettings | 2 + .../xcschemes/CustomAuthDemoTests.xcscheme | 73 +++++++++++++++++++ .../xcschemes/CustomAuthDemoUITests.xcscheme | 73 +++++++++++++++++++ .../CustomAuthDemoTests.swift | 6 -- .../CustomAuthDemoUITests.swift | 18 +---- .../AggregateLoginParams.swift | 4 +- Sources/CustomAuth/CustomAuth.swift | 22 +++--- .../CustomAuth/Handlers/HandlerFactory.swift | 10 ++- .../CustomAuth/Handlers/JWTLoginHandler.swift | 4 +- .../Handlers/MockLoginHandler.swift | 4 +- .../Protocol/AbstractLoginHandler.swift | 4 +- Sources/CustomAuth/Helpers/Error.swift | 48 ++++++------ 13 files changed, 229 insertions(+), 67 deletions(-) create mode 100644 CustomAuthDemo/CustomAuthDemo.xcodeproj/xcshareddata/xcschemes/CustomAuthDemoTests.xcscheme create mode 100644 CustomAuthDemo/CustomAuthDemo.xcodeproj/xcshareddata/xcschemes/CustomAuthDemoUITests.xcscheme diff --git a/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.pbxproj b/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.pbxproj index 70ec3b7..208ada2 100644 --- a/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.pbxproj +++ b/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.pbxproj @@ -14,6 +14,8 @@ 511CEAEE2452D4EF00A7ACE9 /* CustomAuthDemoUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 511CEAED2452D4EF00A7ACE9 /* CustomAuthDemoUITests.swift */; }; 51775EB72484B66A00A29680 /* CustomAuth in Frameworks */ = {isa = PBXBuildFile; productRef = 51775EB62484B66A00A29680 /* CustomAuth */; }; B37E3CEE2C1CF30F00B63F41 /* CustomAuthDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = B37E3CED2C1CF30F00B63F41 /* CustomAuthDemo.swift */; }; + B37E3CF12C1E1C6E00B63F41 /* CustomAuth in Frameworks */ = {isa = PBXBuildFile; productRef = B37E3CF02C1E1C6E00B63F41 /* CustomAuth */; }; + B37E3CF32C1E23B700B63F41 /* CustomAuth in Frameworks */ = {isa = PBXBuildFile; productRef = B37E3CF22C1E23B700B63F41 /* CustomAuth */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -45,7 +47,6 @@ 511CEAE92452D4EF00A7ACE9 /* CustomAuthDemoUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CustomAuthDemoUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 511CEAED2452D4EF00A7ACE9 /* CustomAuthDemoUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomAuthDemoUITests.swift; sourceTree = ""; }; 511CEAEF2452D4EF00A7ACE9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 517C5F5D24693F9D006D5A43 /* CustomAuthDemo.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = CustomAuthDemo.entitlements; sourceTree = ""; }; A3C24F222A70FAF9002F4FC9 /* customauth-swift-sdk */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = "customauth-swift-sdk"; path = ..; sourceTree = ""; }; B37E3CED2C1CF30F00B63F41 /* CustomAuthDemo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomAuthDemo.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -63,6 +64,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + B37E3CF32C1E23B700B63F41 /* CustomAuth in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -70,6 +72,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + B37E3CF12C1E1C6E00B63F41 /* CustomAuth in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -84,6 +87,7 @@ 511CEAE12452D4EF00A7ACE9 /* CustomAuthDemoTests */, 511CEAEC2452D4EF00A7ACE9 /* CustomAuthDemoUITests */, 511CEAC92452D4EC00A7ACE9 /* Products */, + B37E3CEF2C1E1C6E00B63F41 /* Frameworks */, ); sourceTree = ""; }; @@ -101,7 +105,6 @@ isa = PBXGroup; children = ( B37E3CED2C1CF30F00B63F41 /* CustomAuthDemo.swift */, - 517C5F5D24693F9D006D5A43 /* CustomAuthDemo.entitlements */, 511CEACF2452D4EC00A7ACE9 /* ContentView.swift */, 511CEAD12452D4EF00A7ACE9 /* Assets.xcassets */, 511CEAD92452D4EF00A7ACE9 /* Info.plist */, @@ -144,6 +147,13 @@ name = Packages; sourceTree = ""; }; + B37E3CEF2C1E1C6E00B63F41 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -181,6 +191,9 @@ 511CEAE02452D4EF00A7ACE9 /* PBXTargetDependency */, ); name = CustomAuthDemoTests; + packageProductDependencies = ( + B37E3CF22C1E23B700B63F41 /* CustomAuth */, + ); productName = CustomAuthDemoTests; productReference = 511CEADE2452D4EF00A7ACE9 /* CustomAuthDemoTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; @@ -199,6 +212,9 @@ 511CEAEB2452D4EF00A7ACE9 /* PBXTargetDependency */, ); name = CustomAuthDemoUITests; + packageProductDependencies = ( + B37E3CF02C1E1C6E00B63F41 /* CustomAuth */, + ); productName = CustomAuthDemoUITests; productReference = 511CEAE92452D4EF00A7ACE9 /* CustomAuthDemoUITests.xctest */; productType = "com.apple.product-type.bundle.ui-testing"; @@ -611,6 +627,14 @@ isa = XCSwiftPackageProductDependency; productName = CustomAuth; }; + B37E3CF02C1E1C6E00B63F41 /* CustomAuth */ = { + isa = XCSwiftPackageProductDependency; + productName = CustomAuth; + }; + B37E3CF22C1E23B700B63F41 /* CustomAuth */ = { + isa = XCSwiftPackageProductDependency; + productName = CustomAuth; + }; /* End XCSwiftPackageProductDependency section */ }; rootObject = 511CEAC02452D4EC00A7ACE9 /* Project object */; diff --git a/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings index f9b0d7c..a6f6fb2 100644 --- a/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ b/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -2,6 +2,8 @@ + IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded + PreviewsEnabled diff --git a/CustomAuthDemo/CustomAuthDemo.xcodeproj/xcshareddata/xcschemes/CustomAuthDemoTests.xcscheme b/CustomAuthDemo/CustomAuthDemo.xcodeproj/xcshareddata/xcschemes/CustomAuthDemoTests.xcscheme new file mode 100644 index 0000000..5e0c2e2 --- /dev/null +++ b/CustomAuthDemo/CustomAuthDemo.xcodeproj/xcshareddata/xcschemes/CustomAuthDemoTests.xcscheme @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CustomAuthDemo/CustomAuthDemo.xcodeproj/xcshareddata/xcschemes/CustomAuthDemoUITests.xcscheme b/CustomAuthDemo/CustomAuthDemo.xcodeproj/xcshareddata/xcschemes/CustomAuthDemoUITests.xcscheme new file mode 100644 index 0000000..23e22d8 --- /dev/null +++ b/CustomAuthDemo/CustomAuthDemo.xcodeproj/xcshareddata/xcschemes/CustomAuthDemoUITests.xcscheme @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CustomAuthDemo/CustomAuthDemoTests/CustomAuthDemoTests.swift b/CustomAuthDemo/CustomAuthDemoTests/CustomAuthDemoTests.swift index 38a5a31..2a1647c 100644 --- a/CustomAuthDemo/CustomAuthDemoTests/CustomAuthDemoTests.swift +++ b/CustomAuthDemo/CustomAuthDemoTests/CustomAuthDemoTests.swift @@ -4,22 +4,16 @@ import CustomAuthDemo class CustomAuthDemoTests: XCTestCase { override func setUpWithError() throws { - // Put setup code here. This method is called before the invocation of each test method in the class. } override func tearDownWithError() throws { - // Put teardown code here. This method is called after the invocation of each test method in the class. } func testExample() throws { - // This is an example of a functional test case. - // Use XCTAssert and related functions to verify your tests produce the correct results. } func testPerformanceExample() throws { - // This is an example of a performance test case. self.measure { - // Put the code you want to measure the time of here. } } diff --git a/CustomAuthDemo/CustomAuthDemoUITests/CustomAuthDemoUITests.swift b/CustomAuthDemo/CustomAuthDemoUITests/CustomAuthDemoUITests.swift index 2c248ef..3d48c4c 100644 --- a/CustomAuthDemo/CustomAuthDemoUITests/CustomAuthDemoUITests.swift +++ b/CustomAuthDemo/CustomAuthDemoUITests/CustomAuthDemoUITests.swift @@ -2,35 +2,21 @@ import XCTest import CustomAuthDemo class CustomAuthDemoUITests: 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. } func testExample() throws { - // UI tests must launch the application that they test. - let app = XCUIApplication() - app.launch() - // Use recording to get started writing UI tests. - // Use XCTAssert and related functions to verify your tests produce the correct results. } func testLaunchPerformance() throws { - if #available(macOS 10.15, iOS 13.0, tvOS 13.0, *) { - // This measures how long it takes to launch your application. - measure(metrics: [XCTOSSignpostMetric.applicationLaunch]) { + measure(metrics: [XCTApplicationLaunchMetric.init()]) { XCUIApplication().launch() } - } } } diff --git a/Sources/CustomAuth/Common/AggregateVerifierParams/AggregateLoginParams.swift b/Sources/CustomAuth/Common/AggregateVerifierParams/AggregateLoginParams.swift index 5b74390..2e64f30 100644 --- a/Sources/CustomAuth/Common/AggregateVerifierParams/AggregateLoginParams.swift +++ b/Sources/CustomAuth/Common/AggregateVerifierParams/AggregateLoginParams.swift @@ -3,9 +3,9 @@ import Foundation public class AggregateLoginParams: Codable { public let aggregateVerifierType: AggregateVerifierType public let verifierIdentifier: String - public let subVerifierDetailsArray: [SubVerifierDetails] + public let subVerifierDetailsArray: [SingleLoginParams] - public init(aggregateVerifierType: AggregateVerifierType, verifierIdentifier: String, subVerifierDetailsArray: [SubVerifierDetails]) { + public init(aggregateVerifierType: AggregateVerifierType, verifierIdentifier: String, subVerifierDetailsArray: [SingleLoginParams]) { self.aggregateVerifierType = aggregateVerifierType self.verifierIdentifier = verifierIdentifier self.subVerifierDetailsArray = subVerifierDetailsArray diff --git a/Sources/CustomAuth/CustomAuth.swift b/Sources/CustomAuth/CustomAuth.swift index 3ae6c91..1946b1b 100644 --- a/Sources/CustomAuth/CustomAuth.swift +++ b/Sources/CustomAuth/CustomAuth.swift @@ -17,7 +17,7 @@ public class CustomAuth { public init(config: CustomAuthArgs) throws { if URL(string: config.urlScheme)?.scheme == nil { - throw CASDKError.unknownError + throw CASDKError.invalidCallbackURLScheme } self.config = config @@ -37,14 +37,14 @@ public class CustomAuth { torus.setApiKey(apiKey: config.apiKey ?? "") } - public func triggerLogin(args: SingleLoginParams) async throws -> TorusLoginResponse? { + public func triggerLogin(args: SingleLoginParams) async throws -> TorusLoginResponse { let loginHandler = try HandlerFactory.createHandler(params: CreateHandlerParams(typeOfLogin: args.typeOfLogin, verifier: args.verifier, clientId: args.clientId, urlScheme: config.urlScheme, redirectURL: args.redirectURL, jwtParams: args.jwtParams, customState: args.customState)) var loginParams: LoginWindowResponse if args.hash != nil && args.queryParams != nil { let (error, hashParams, instanceParams) = try handleRedirectParameters(hash: args.hash!, queryParameters: args.queryParams!) if !error.isEmpty { - throw CASDKError.unknownError + throw CASDKError.redirectParamsError(msg: error) } loginParams = LoginWindowResponse(accessToken: hashParams.params["access_token"], idToken: hashParams.params["idToken"], ref: hashParams.params["ref"] ?? "", extraParams: hashParams.params["extra_params"], extraParamsPassed: hashParams.params["extra_params_passed"]!, state: instanceParams) } else { @@ -62,12 +62,12 @@ public class CustomAuth { return TorusLoginResponse(singleVerifierResponse: TorusSingleVerifierResponse(userInfo: returnedInfo, loginResponse: loginParams), torusKey: torusKey) } - public func triggerAggregateLogin(args: AggregateLoginParams) async throws -> TorusAggregateLoginResponse? { + public func triggerAggregateLogin(args: AggregateLoginParams) async throws -> TorusAggregateLoginResponse { if args.subVerifierDetailsArray.isEmpty { - throw CASDKError.unknownError + throw CASDKError.invalidParameters } if args.subVerifierDetailsArray.count == 1 && args.aggregateVerifierType == AggregateVerifierType.single_id_verifier { - throw CASDKError.unknownError + throw CASDKError.invalidParameters } var loginParamsArray: [LoginWindowResponse] = [] @@ -79,7 +79,7 @@ public class CustomAuth { if subverifierDetail.hash != nil && subverifierDetail.queryParams != nil { let (error, hashParams, instanceParams) = try handleRedirectParameters(hash: subverifierDetail.hash!, queryParameters: subverifierDetail.queryParams!) if !error.isEmpty { - throw CASDKError.unknownError + throw CASDKError.redirectParamsError(msg: error) } loginParams = LoginWindowResponse(accessToken: hashParams.params["access_token"], idToken: hashParams.params["idToken"], ref: hashParams.params["ref"] ?? "", extraParams: hashParams.params["extra_params"], extraParamsPassed: hashParams.params["extra_params_passed"]!, state: instanceParams) } else { @@ -123,12 +123,12 @@ public class CustomAuth { return TorusAggregateLoginResponse(torusAggregateVerifierResponse: aggregateVerifierResponses, torusKey: aggregateTorusKey) } - public func triggerHybridAggregateLogin(args: HybridAggregateLoginParams) async throws -> TorusHybridAggregateLoginResponse? { + public func triggerHybridAggregateLogin(args: HybridAggregateLoginParams) async throws -> TorusHybridAggregateLoginResponse { if args.aggregateLoginParams.subVerifierDetailsArray.isEmpty { - throw CASDKError.unknownError + throw CASDKError.invalidParameters } if args.aggregateLoginParams.subVerifierDetailsArray.count == 1 && args.aggregateLoginParams.aggregateVerifierType == AggregateVerifierType.single_id_verifier { - throw CASDKError.unknownError + throw CASDKError.invalidParameters } let loginHandler = try HandlerFactory.createHandler(params: CreateHandlerParams(typeOfLogin: args.singleLogin.typeOfLogin, verifier: args.singleLogin.verifier, clientId: args.singleLogin.clientId, urlScheme: config.urlScheme, redirectURL: args.singleLogin.redirectURL, jwtParams: args.singleLogin.jwtParams, customState: args.singleLogin.customState)) @@ -137,7 +137,7 @@ public class CustomAuth { if args.singleLogin.hash != nil && args.singleLogin.queryParams != nil { let (error, hashParams, instanceParams) = try handleRedirectParameters(hash: args.singleLogin.hash!, queryParameters: args.singleLogin.queryParams!) if !error.isEmpty { - throw CASDKError.unknownError + throw CASDKError.redirectParamsError(msg: error) } loginParams = LoginWindowResponse(accessToken: hashParams.params["access_token"], idToken: hashParams.params["idToken"], ref: hashParams.params["ref"] ?? "", extraParams: hashParams.params["extra_params"], extraParamsPassed: hashParams.params["extra_params_passed"]!, state: instanceParams) } else { diff --git a/Sources/CustomAuth/Handlers/HandlerFactory.swift b/Sources/CustomAuth/Handlers/HandlerFactory.swift index 29b38b6..a737bb3 100644 --- a/Sources/CustomAuth/Handlers/HandlerFactory.swift +++ b/Sources/CustomAuth/Handlers/HandlerFactory.swift @@ -4,8 +4,12 @@ public class HandlerFactory { static func createHandler( params: CreateHandlerParams ) throws -> ILoginHandler { - if params.verifier.isEmpty || params.clientId.isEmpty { - throw CASDKError.unknownError + if params.verifier.isEmpty { + throw CASDKError.invalidVerifier + } + + if params.clientId.isEmpty { + throw CASDKError.invalidClientID } let domain = params.jwtParams?.domain @@ -34,7 +38,7 @@ public class HandlerFactory { } if domain == nil { - throw CASDKError.methodUnavailable + throw CASDKError.invalidAuth0Options } return try JWTLoginHandler(clientId: params.clientId, verifier: params.verifier, urlScheme: params.urlScheme, redirectURL: params.redirectURL, typeOfLogin: params.typeOfLogin) diff --git a/Sources/CustomAuth/Handlers/JWTLoginHandler.swift b/Sources/CustomAuth/Handlers/JWTLoginHandler.swift index f00662f..2d6b57d 100644 --- a/Sources/CustomAuth/Handlers/JWTLoginHandler.swift +++ b/Sources/CustomAuth/Handlers/JWTLoginHandler.swift @@ -22,7 +22,7 @@ class JWTLoginHandler: AbstractLoginHandler { var urlComponents = URLComponents() if jwtParams == nil { - throw CASDKError.unknownError + throw CASDKError.invalidAuth0Options } var params: [String: String] = try (JSONSerialization.jsonObject(with: try JSONEncoder().encode(jwtParams), options: []) as! [String: String]) @@ -70,7 +70,7 @@ class JWTLoginHandler: AbstractLoginHandler { } if idToken == nil { - throw CASDKError.idTokenFailed + throw CASDKError.idTokenNotProvided } else { let result = try JSONDecoder().decode(Auth0UserInfo.self, from: idToken!.data(using: .utf8)!) diff --git a/Sources/CustomAuth/Handlers/MockLoginHandler.swift b/Sources/CustomAuth/Handlers/MockLoginHandler.swift index 63c4f86..66c7055 100644 --- a/Sources/CustomAuth/Handlers/MockLoginHandler.swift +++ b/Sources/CustomAuth/Handlers/MockLoginHandler.swift @@ -8,7 +8,7 @@ class MockLoginHandler: AbstractLoginHandler { override public func setFinalUrl() throws { if jwtParams == nil { - throw CASDKError.unknownError + throw CASDKError.invalidAuth0Options } var params: [String: String] = try (JSONSerialization.jsonObject(with: try JSONEncoder().encode(jwtParams), options: []) as! [String: String]) @@ -57,7 +57,7 @@ class MockLoginHandler: AbstractLoginHandler { } if idToken == nil { - throw CASDKError.idTokenFailed + throw CASDKError.idTokenNotProvided } else { let result = try JSONDecoder().decode(Auth0UserInfo.self, from: idToken!.data(using: .utf8)!) diff --git a/Sources/CustomAuth/Handlers/Protocol/AbstractLoginHandler.swift b/Sources/CustomAuth/Handlers/Protocol/AbstractLoginHandler.swift index 2a2a424..80975ef 100644 --- a/Sources/CustomAuth/Handlers/Protocol/AbstractLoginHandler.swift +++ b/Sources/CustomAuth/Handlers/Protocol/AbstractLoginHandler.swift @@ -47,7 +47,7 @@ public class AbstractLoginHandler: ILoginHandler { public func handleLoginWindow(popupFeatures: String?) async throws -> LoginWindowResponse { guard let callbackURLScheme = URL(string: urlScheme)?.scheme else { - throw CASDKError.unknownError + throw CASDKError.invalidCallbackURLScheme } let urlWithTokenInfo = try await AuthenticationManager().authenticationManagerWrapper(url: finalUrl.url!, callbackURLScheme: callbackURLScheme, prefersEphemeralWebBrowserSession: false) @@ -65,6 +65,6 @@ public class AbstractLoginHandler: ILoginHandler { } public func setFinalUrl() throws { - fatalError("setFinalUrl must be implemented by concrete class") + throw CASDKError.invalidMethod(msg: "setFinalUrl cannot be called by abstract class") } } diff --git a/Sources/CustomAuth/Helpers/Error.swift b/Sources/CustomAuth/Helpers/Error.swift index e7dc587..2af425d 100644 --- a/Sources/CustomAuth/Helpers/Error.swift +++ b/Sources/CustomAuth/Helpers/Error.swift @@ -1,34 +1,40 @@ public enum CASDKError: Error { - case getUserInfoFailed case decodingFailed case encodingFailed - case accessTokenAPIFailed case accessTokenNotProvided - case authGrantNotProvided - case idTokenFailed - case unknownError - case methodUnavailable + case idTokenNotProvided + case invalidParameters + case invalidCallbackURLScheme + case invalidAuth0Options + case invalidVerifier + case invalidClientID + case invalidMethod(msg: String) + case redirectParamsError(msg: String) public var errorDescription: String { switch self { - case .getUserInfoFailed: - return "Unable to get verifier ID" case .decodingFailed: - return "decodingFailed" + return "decoding failed" case .encodingFailed: - return "encodingFailed" - case .accessTokenAPIFailed: - return "API failed for retrieving access token" + return "encoding failed" case .accessTokenNotProvided: - return "access token unavailable in data" - case .authGrantNotProvided: - return "authorization grant not available" - case .idTokenFailed: - return "idTokenFailed" - case .unknownError: - return "unknownError" - case .methodUnavailable: - return "method unavailable/unimplemented" + return "access token not provided" + case .idTokenNotProvided: + return "id token not provided" + case .invalidCallbackURLScheme: + return "callback scheme is invalid" + case .invalidParameters: + return "parameters are missing or invalid" + case .invalidAuth0Options: + return "auth0 options are missing or invalid" + case .invalidMethod(msg: let msg): + return msg + case .redirectParamsError(msg: let msg): + return msg + case .invalidVerifier: + return "invalid verifier" + case .invalidClientID: + return "invalid client ID" } } }