diff --git a/Auth0.xcodeproj/project.pbxproj b/Auth0.xcodeproj/project.pbxproj index 288931a9..fac1b98d 100644 --- a/Auth0.xcodeproj/project.pbxproj +++ b/Auth0.xcodeproj/project.pbxproj @@ -146,6 +146,9 @@ 5CB41D8223D611AE00074024 /* ClaimValidatorsSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB41D8123D611AE00074024 /* ClaimValidatorsSpec.swift */; }; 5CB41D8323D611AE00074024 /* ClaimValidatorsSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB41D8123D611AE00074024 /* ClaimValidatorsSpec.swift */; }; 5CB41D8423D611AE00074024 /* ClaimValidatorsSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB41D8123D611AE00074024 /* ClaimValidatorsSpec.swift */; }; + 5CDB7FA723FC78A300AE8B42 /* AuthenticationAPISpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 5FCCC3101CF4D4FF00901E2E /* AuthenticationAPISpec.m */; }; + 5CDB7FA823FC78CF00AE8B42 /* AuthenticationAPISpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 5FCCC3101CF4D4FF00901E2E /* AuthenticationAPISpec.m */; }; + 5CDB7FAC23FC7AC200AE8B42 /* A0WebAuthSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 5FBEF3DD1D07A4B700D90941 /* A0WebAuthSpec.m */; }; 5F06DDA51CC451540011842B /* Auth0.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F06DD781CC448B10011842B /* Auth0.framework */; }; 5F06DDB41CC451700011842B /* Auth0.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F06DD851CC448C90011842B /* Auth0.framework */; }; 5F06DDC91CC66B710011842B /* Auth0.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F06DDC81CC66B710011842B /* Auth0.swift */; }; @@ -1757,7 +1760,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "AUTH0_PLIST=\"${SRCROOT}/Auth0.plist\"\nif [ -f $AUTH0_PLIST ];\nthen\ncp \"$AUTH0_PLIST\" \"${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app\"\nfi"; + shellScript = "AUTH0_PLIST=\"${SRCROOT}/Auth0.plist\"\nif [ -f $AUTH0_PLIST ];\nthen\ncp \"$AUTH0_PLIST\" \"${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/Contents/Resources\"\nfi\n"; }; 5BEDE1801EC213C10007300D /* Carthage */ = { isa = PBXShellScriptBuildPhase; @@ -1946,7 +1949,9 @@ 5CB41D6923D0BAD600074024 /* IDTokenSignatureValidatorSpec.swift in Sources */, 5FADB60F1CED7E5200D4BB50 /* UserPatchAttributesSpec.swift in Sources */, 5C4F553523C9124200C89615 /* JWKSpec.swift in Sources */, + 5CDB7FAC23FC7AC200AE8B42 /* A0WebAuthSpec.m in Sources */, 5FA250541D4A85A200C544FA /* WebAuthErrorSpec.swift in Sources */, + 5CDB7FA723FC78A300AE8B42 /* AuthenticationAPISpec.m in Sources */, 5CB41D7623D0C15000074024 /* IDTokenValidatorBaseSpec.swift in Sources */, 5B9262C31ECF0CC200F4F6D3 /* BioAuthenticationSpec.swift in Sources */, 5FBBF0381CC964BC0024D2AF /* Matchers.swift in Sources */, @@ -1983,6 +1988,7 @@ 5FBBF03C1CC96AA70024D2AF /* Responses.swift in Sources */, 5FADB6101CED7E5200D4BB50 /* UserPatchAttributesSpec.swift in Sources */, 5FBBF0391CC964BC0024D2AF /* Matchers.swift in Sources */, + 5CDB7FA823FC78CF00AE8B42 /* AuthenticationAPISpec.m in Sources */, 5CB41D6A23D0BAD700074024 /* IDTokenSignatureValidatorSpec.swift in Sources */, 5F93BC0C1CC6B0DE0031519F /* Auth0Spec.swift in Sources */, 5C4F552F23C9123000C89615 /* Generators.swift in Sources */, diff --git a/Auth0/SafariWebAuth.swift b/Auth0/SafariWebAuth.swift index 394590b8..102639ee 100644 --- a/Auth0/SafariWebAuth.swift +++ b/Auth0/SafariWebAuth.swift @@ -43,6 +43,17 @@ class SafariWebAuth: WebAuth { var nonce: String? var leeway: Int = 60 * 1000 // Default leeway is 60 seconds var maxAge: Int? + + lazy var redirectURL: URL? = { + let bundleIdentifier = Bundle.main.bundleIdentifier ?? SafariWebAuth.NoBundleIdentifier + var components = URLComponents(url: self.url, resolvingAgainstBaseURL: true) + components?.scheme = self.universalLink ? "https" : bundleIdentifier + return components?.url? + .appendingPathComponent("ios") + .appendingPathComponent(bundleIdentifier) + .appendingPathComponent("callback") + }() + private var authenticationSession = true private var safariPresentationStyle = UIModalPresentationStyle.fullScreen @@ -93,6 +104,11 @@ class SafariWebAuth: WebAuth { return self } + func redirectURL(_ redirectURL: URL) -> Self { + self.redirectURL = redirectURL + return self + } + func nonce(_ nonce: String) -> Self { self.nonce = nonce return self @@ -124,10 +140,8 @@ class SafariWebAuth: WebAuth { } func start(_ callback: @escaping (Result) -> Void) { - guard - let redirectURL = self.redirectURL, !redirectURL.absoluteString.hasPrefix(SafariWebAuth.NoBundleIdentifier) - else { - return callback(Result.failure(error: WebAuthError.noBundleIdentifierFound)) + guard let redirectURL = self.redirectURL else { + return callback(Result.failure(error: WebAuthError.noBundleIdentifierFound)) } if self.responseType.contains(.idToken) { guard self.nonce != nil else { return callback(Result.failure(error: WebAuthError.noNonceProvided)) } @@ -136,7 +150,6 @@ class SafariWebAuth: WebAuth { let state = self.parameters["state"] ?? generateDefaultState() let authorizeURL = self.buildAuthorizeURL(withRedirectURL: redirectURL, defaults: handler.defaults, state: state) - #if swift(>=3.2) if #available(iOS 11.0, *), self.authenticationSession { let session = SafariAuthenticationSession(authorizeURL: authorizeURL, redirectURL: redirectURL, state: state, handler: handler, finish: callback, logger: logger) logger?.trace(url: authorizeURL, source: "SafariAuthenticationSession") @@ -149,14 +162,6 @@ class SafariWebAuth: WebAuth { logger?.trace(url: authorizeURL, source: "Safari") self.storage.store(session) } - #else - let (controller, finish) = newSafari(authorizeURL, callback: callback) - let session = SafariSession(controller: controller, redirectURL: redirectURL, state: state, handler: handler, finish: finish, logger: self.logger) - controller.delegate = session - self.presenter.present(controller: controller) - logger?.trace(url: authorizeURL, source: "Safari") - self.storage.store(session) - #endif } func newSafari(_ authorizeURL: URL, callback: @escaping (Result) -> Void) -> (SFSafariViewController, (Result) -> Void) { @@ -229,19 +234,8 @@ class SafariWebAuth: WebAuth { nonce: self.nonce) } - var redirectURL: URL? { - let bundleIdentifier = Bundle.main.bundleIdentifier ?? SafariWebAuth.NoBundleIdentifier - var components = URLComponents(url: self.url, resolvingAgainstBaseURL: true) - components?.scheme = self.universalLink ? "https" : bundleIdentifier - return components?.url? - .appendingPathComponent("ios") - .appendingPathComponent(bundleIdentifier) - .appendingPathComponent("callback") - } - func clearSession(federated: Bool, callback: @escaping (Bool) -> Void) { let logoutURL = federated ? URL(string: "/v2/logout?federated", relativeTo: self.url)! : URL(string: "/v2/logout", relativeTo: self.url)! - #if swift(>=3.2) if #available(iOS 11.0, *), self.authenticationSession { let returnTo = URLQueryItem(name: "returnTo", value: self.redirectURL?.absoluteString) let clientId = URLQueryItem(name: "client_id", value: self.clientId) @@ -258,11 +252,6 @@ class SafariWebAuth: WebAuth { logger?.trace(url: logoutURL, source: "Safari") self.presenter.present(controller: controller) } - #else - let controller = SilentSafariViewController(url: logoutURL) { callback($0) } - logger?.trace(url: logoutURL, source: "Safari") - self.presenter.present(controller: controller) - #endif } } diff --git a/Auth0/WebAuth.swift b/Auth0/WebAuth.swift index a3930e0f..831e3f12 100644 --- a/Auth0/WebAuth.swift +++ b/Auth0/WebAuth.swift @@ -156,6 +156,12 @@ public protocol WebAuth: Trackable, Loggable { /// - Returns: the same WebAuth instance to allow method chaining func responseType(_ response: [ResponseType]) -> Self + /// Specify a redirect url to be used instead of a custom scheme + /// + /// - Parameter redirectURL: custom redirect url + /// - Returns: the same WebAuth instance to allow method chaining + func redirectURL(_ redirectURL: URL) -> Self + /// Add `nonce` parameter for authentication, this is a requirement /// when response type `.idToken` is specified. /// @@ -235,7 +241,6 @@ public protocol WebAuth: Trackable, Loggable { For iOS 11+ you will need to ensure that the **Callback URL** has been added to the **Allowed Logout URLs** section of your application in the [Auth0 Dashboard](https://manage.auth0.com/#/applications/). - ``` Auth0 .webAuth() diff --git a/Auth0Tests/WebAuthSpec.swift b/Auth0Tests/WebAuthSpec.swift index c18dc6d0..6ab37782 100644 --- a/Auth0Tests/WebAuthSpec.swift +++ b/Auth0Tests/WebAuthSpec.swift @@ -267,6 +267,10 @@ class WebAuthSpec: QuickSpec { expect(newWebAuth().useUniversalLink().redirectURL?.absoluteString) == "https://\(Domain)/ios/\(bundleId)/callback" } + it("should build with a custom url") { + expect(newWebAuth().redirectURL(RedirectURL).redirectURL) == RedirectURL + } + }