Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: added support for webview as a provider for webauth #875

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions App/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,15 @@ class ViewController: UIViewController {
@IBAction func login(_ sender: Any) {
Auth0
.webAuth()
.provider(WebAuthentication.webViewProvider())
.logging(enabled: true)
.start(onAuth)
}

@IBAction func logout(_ sender: Any) {
Auth0
.webAuth()
.provider(WebAuthentication.webViewProvider())
.logging(enabled: true)
.clearSession(federated: false) { result in
switch result {
Expand Down
4 changes: 3 additions & 1 deletion Auth0.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ web_auth_files = [
'Auth0/WebAuth.swift',
'Auth0/WebAuthentication.swift',
'Auth0/WebAuthError.swift',
'Auth0/WebAuthUserAgent.swift'
'Auth0/WebAuthUserAgent.swift',
'Auth0/UIWindow+TopViewController.swift',
'Auth0/WebViewProvider.swift'
]

ios_files = ['Auth0/MobileWebAuth.swift']
Expand Down
24 changes: 24 additions & 0 deletions Auth0.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -321,8 +321,12 @@
A7DDDF6D2BC9A81E0077B067 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = A7DDDF6B2BC9A81E0077B067 /* PrivacyInfo.xcprivacy */; };
A7DDDF6E2BC9A81E0077B067 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = A7DDDF6B2BC9A81E0077B067 /* PrivacyInfo.xcprivacy */; };
A7DDDF702BC9A93F0077B067 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = A7DDDF6B2BC9A81E0077B067 /* PrivacyInfo.xcprivacy */; };
C107B51D2C9AC4D8006B6BEA /* WebViewProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = C107B51B2C9AC4D3006B6BEA /* WebViewProvider.swift */; };
C107B5222CA27F7C006B6BEA /* WebViewProviderSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = C107B5202CA27F76006B6BEA /* WebViewProviderSpec.swift */; };
C12BFE432C352DD400D1CC00 /* NetworkStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = C177D76F2C2BDFE40094C657 /* NetworkStub.swift */; };
C12BFE442C352DD700D1CC00 /* StubURLProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C177D7742C2BE00D0094C657 /* StubURLProtocol.swift */; };
C160EE352CABD0E5005ACE8E /* UIWindow+TopViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C160EE302CABD0DA005ACE8E /* UIWindow+TopViewController.swift */; };
C160EE382CABD35A005ACE8E /* UIWindow+TopViewControllerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = C160EE372CABD358005ACE8E /* UIWindow+TopViewControllerSpec.swift */; };
C177D6C32C2ADDEB0094C657 /* Auth0.plist in Resources */ = {isa = PBXBuildFile; fileRef = C177D6C22C2ADDEB0094C657 /* Auth0.plist */; };
C177D6C72C2ADEB60094C657 /* CwlPreconditionTesting in Frameworks */ = {isa = PBXBuildFile; productRef = C177D6C62C2ADEB60094C657 /* CwlPreconditionTesting */; };
C177D6D42C2B0DCB0094C657 /* CwlPreconditionTesting in Frameworks */ = {isa = PBXBuildFile; productRef = C177D6D32C2B0DCB0094C657 /* CwlPreconditionTesting */; };
Expand Down Expand Up @@ -746,6 +750,10 @@
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 = "<group>"; };
A7DDDF6B2BC9A81E0077B067 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
C107B51B2C9AC4D3006B6BEA /* WebViewProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewProvider.swift; sourceTree = "<group>"; };
C107B5202CA27F76006B6BEA /* WebViewProviderSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewProviderSpec.swift; sourceTree = "<group>"; };
C160EE302CABD0DA005ACE8E /* UIWindow+TopViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIWindow+TopViewController.swift"; sourceTree = "<group>"; };
C160EE372CABD358005ACE8E /* UIWindow+TopViewControllerSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIWindow+TopViewControllerSpec.swift"; sourceTree = "<group>"; };
C177D6C22C2ADDEB0094C657 /* Auth0.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Auth0.plist; sourceTree = "<group>"; };
C177D76F2C2BDFE40094C657 /* NetworkStub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkStub.swift; sourceTree = "<group>"; };
C177D7742C2BE00D0094C657 /* StubURLProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StubURLProtocol.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -928,6 +936,7 @@
5C0AF09828330CA000162044 /* Providers */ = {
isa = PBXGroup;
children = (
C107B51B2C9AC4D3006B6BEA /* WebViewProvider.swift */,
5B16D88C1F7141A0009476A5 /* ASProvider.swift */,
5C0AF09928330CBA00162044 /* SafariProvider.swift */,
);
Expand Down Expand Up @@ -977,6 +986,7 @@
5CF539222836DC360073F623 /* Providers */ = {
isa = PBXGroup;
children = (
C107B5202CA27F76006B6BEA /* WebViewProviderSpec.swift */,
5CF5392A283835460073F623 /* ASProviderSpec.swift */,
5CF539232836DCC10073F623 /* SafariProviderSpec.swift */,
);
Expand Down Expand Up @@ -1051,6 +1061,7 @@
5F06DD921CC451430011842B /* Auth0Tests */ = {
isa = PBXGroup;
children = (
C160EE362CABD352005ACE8E /* Extensions */,
C177D76E2C2BDF9D0094C657 /* StubNetworking */,
5F28B4651D8300BB0000EB23 /* Logger */,
5FE686A81D1894990075874C /* Telemetry */,
Expand Down Expand Up @@ -1203,6 +1214,7 @@
5FCAB16E1D08FFE900331C84 /* Extensions */ = {
isa = PBXGroup;
children = (
C160EE302CABD0DA005ACE8E /* UIWindow+TopViewController.swift */,
5C4F551923C8FB8E00C89615 /* Array+Encode.swift */,
5C4F551823C8FB8E00C89615 /* String+URLSafe.swift */,
5FCAB1721D09009600331C84 /* NSData+URLSafe.swift */,
Expand Down Expand Up @@ -1287,6 +1299,14 @@
name = Management;
sourceTree = "<group>";
};
C160EE362CABD352005ACE8E /* Extensions */ = {
isa = PBXGroup;
children = (
C160EE372CABD358005ACE8E /* UIWindow+TopViewControllerSpec.swift */,
);
path = Extensions;
sourceTree = "<group>";
};
C177D76E2C2BDF9D0094C657 /* StubNetworking */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -2046,8 +2066,10 @@
5F3965C21CF67CF000CDE7C0 /* WebAuth.swift in Sources */,
5FCAB1761D0900CF00331C84 /* TransactionStore.swift in Sources */,
5FDE87471D8A422300EA27DC /* Telemetry.swift in Sources */,
C107B51D2C9AC4D8006B6BEA /* WebViewProvider.swift in Sources */,
5FAE9C911D8878D400A871CE /* Auth0WebAuth.swift in Sources */,
5B5E93F91EC45C22002A37F9 /* CredentialsManagerError.swift in Sources */,
C160EE352CABD0E5005ACE8E /* UIWindow+TopViewController.swift in Sources */,
5CA541CD2B1A81A700E4284D /* Documentation.docc in Sources */,
5C41F6AA244DCAFB00252548 /* ClearSessionTransaction.swift in Sources */,
5FDE875D1D8A424700EA27DC /* AuthenticationError.swift in Sources */,
Expand Down Expand Up @@ -2151,7 +2173,9 @@
5FADB6091CED500900D4BB50 /* ManagementSpec.swift in Sources */,
5FCAB16D1D07AC3500331C84 /* WebAuthSpec.swift in Sources */,
5F28B4671D8300D50000EB23 /* LoggerSpec.swift in Sources */,
C107B5222CA27F7C006B6BEA /* WebViewProviderSpec.swift in Sources */,
5FBBF0431CCA90300024D2AF /* AuthenticationSpec.swift in Sources */,
C160EE382CABD35A005ACE8E /* UIWindow+TopViewControllerSpec.swift in Sources */,
5B2860D61EEF210A00C75D54 /* UserInfoSpec.swift in Sources */,
5C809D9A275FA3EF00F15A67 /* ManagementErrorSpec.swift in Sources */,
5FCAB16B1D07AC3500331C84 /* OAuth2GrantSpec.swift in Sources */,
Expand Down
6 changes: 5 additions & 1 deletion Auth0.xcodeproj/xcshareddata/xcschemes/Auth0.iOS.xcscheme
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1400"
version = "1.3">
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
Expand Down Expand Up @@ -47,6 +47,10 @@
BlueprintName = "Auth0Tests.iOS"
ReferencedContainer = "container:Auth0.xcodeproj">
</BuildableReference>
<LocationScenarioReference
identifier = "com.apple.dt.IDEFoundation.CurrentLocationScenarioIdentifier"
referenceType = "1">
</LocationScenarioReference>
</TestableReference>
</Testables>
</TestAction>
Expand Down
4 changes: 2 additions & 2 deletions Auth0/Auth0WebAuth.swift
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,8 @@ final class Auth0WebAuth: WebAuth {
state: state,
organization: organization,
invitation: invitation)
let provider = self.provider ?? WebAuthentication.asProvider(redirectURL: redirectURL,
ephemeralSession: ephemeralSession)

let provider = self.provider ?? WebAuthentication.asProvider(redirectURL: redirectURL, ephemeralSession: ephemeralSession)
let userAgent = provider(authorizeURL) { [storage, onCloseCallback] result in
storage.clear()

Expand Down
13 changes: 13 additions & 0 deletions Auth0/Helpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,16 @@
guard let scope = scope, !scope.split(separator: " ").map(String.init).contains("openid") else { return scope }
return "openid \(scope)"
}

func extractRedirectURL(from url: URL) -> URL? {
guard let components = URLComponents(url: url, resolvingAgainstBaseURL: true) else {
return nil
}

Check warning on line 23 in Auth0/Helpers.swift

View workflow job for this annotation

GitHub Actions / Lint code with SwiftLint

Lines should not have trailing whitespace (trailing_whitespace)
if let redirectURIString = components.queryItems?.first(where: { $0.name == "redirect_uri" || $0.name == "returnTo" })?.value,
let redirectURI = URL(string: redirectURIString) {
return redirectURI
}

Check warning on line 28 in Auth0/Helpers.swift

View workflow job for this annotation

GitHub Actions / Lint code with SwiftLint

Lines should not have trailing whitespace (trailing_whitespace)
return nil
}

Check warning on line 30 in Auth0/Helpers.swift

View workflow job for this annotation

GitHub Actions / Lint code with SwiftLint

Files should have a single trailing newline (trailing_newline)
36 changes: 1 addition & 35 deletions Auth0/SafariProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,39 +45,6 @@ public extension WebAuthentication {

}

extension SFSafariViewController {

var topViewController: UIViewController? {
guard let root = UIApplication.shared()?.windows.last(where: \.isKeyWindow)?.rootViewController else {
return nil
}
return self.findTopViewController(from: root)
}

func present() {
self.topViewController?.present(self, animated: true, completion: nil)
}

private func findTopViewController(from root: UIViewController) -> UIViewController? {
if let presented = root.presentedViewController { return self.findTopViewController(from: presented) }

switch root {
case let split as UISplitViewController:
guard let last = split.viewControllers.last else { return split }
return self.findTopViewController(from: last)
case let navigation as UINavigationController:
guard let top = navigation.topViewController else { return navigation }
return self.findTopViewController(from: top)
case let tab as UITabBarController:
guard let selected = tab.selectedViewController else { return tab }
return self.findTopViewController(from: selected)
default:
return root
}
}

}

class SafariUserAgent: NSObject, WebAuthUserAgent {

let controller: SFSafariViewController
Expand All @@ -92,7 +59,7 @@ class SafariUserAgent: NSObject, WebAuthUserAgent {
}

func start() {
self.controller.present()
UIWindow.topViewController?.present(controller, animated: true, completion: nil)
}

func finish(with result: WebAuthResult<Void>) {
Expand Down Expand Up @@ -125,7 +92,6 @@ extension SafariUserAgent: SFSafariViewControllerDelegate {
// If you are developing a custom Web Auth provider, call WebAuthentication.cancel() instead
// TransactionStore is internal
TransactionStore.shared.cancel()

}

}
Expand Down
38 changes: 38 additions & 0 deletions Auth0/UIWindow+TopViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//
// UIWindow+TopViewController.swift
// Auth0
//
// Created by Desu Sai Venkat on 01/10/24.
// Copyright © 2024 Auth0. All rights reserved.
//

#if os(iOS)
import UIKit

extension UIWindow {
static var topViewController: UIViewController? {
guard let root = UIApplication.shared()?.windows.last(where: \.isKeyWindow)?.rootViewController else {
return nil
}
return findTopViewController(from: root)
}

Check warning on line 19 in Auth0/UIWindow+TopViewController.swift

View workflow job for this annotation

GitHub Actions / Lint code with SwiftLint

Lines should not have trailing whitespace (trailing_whitespace)
private static func findTopViewController(from root: UIViewController) -> UIViewController? {
if let presented = root.presentedViewController { return self.findTopViewController(from: presented) }

switch root {
case let split as UISplitViewController:
guard let last = split.viewControllers.last else { return split }
return self.findTopViewController(from: last)
case let navigation as UINavigationController:
guard let top = navigation.topViewController else { return navigation }
return self.findTopViewController(from: top)
case let tab as UITabBarController:
guard let selected = tab.selectedViewController else { return tab }
return self.findTopViewController(from: selected)
default:
return root
}
}
}
#endif
1 change: 0 additions & 1 deletion Auth0/WebAuth.swift
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,5 @@ public extension WebAuth {
return try await self.clearSession(federated: federated)
}
#endif

}
#endif
2 changes: 2 additions & 0 deletions Auth0/WebAuthError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
public struct WebAuthError: Auth0Error {

enum Code: Equatable {
case webViewFailure(String)
case noBundleIdentifier
case transactionActiveAlready
case invalidInvitationURL(String)
Expand Down Expand Up @@ -39,7 +40,7 @@
/// build a valid URL.
/// This error does not include a ``Auth0Error/cause-9wuyi``.
public static let noBundleIdentifier: WebAuthError = .init(code: .noBundleIdentifier)

Check warning on line 43 in Auth0/WebAuthError.swift

View workflow job for this annotation

GitHub Actions / Lint code with SwiftLint

Lines should not have trailing whitespace (trailing_whitespace)
/// There is already an active transaction at the moment; therefore, this newly initiated transaction is canceled.
/// This error does not include a ``Auth0Error/cause-9wuyi``.
public static let transactionActiveAlready: WebAuthError = .init(code: .transactionActiveAlready)
Expand Down Expand Up @@ -82,6 +83,7 @@

var message: String {
switch self.code {
case .webViewFailure(let webViewFailureMessage): return webViewFailureMessage
case .noBundleIdentifier: return "Unable to retrieve the bundle identifier from Bundle.main.bundleIdentifier,"
+ " or it could not be used to build a valid URL."
case .transactionActiveAlready: return "Failed to start this transaction, as there is an active transaction at the"
Expand Down
Loading
Loading