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

Have clearSession() yield a Result<Void, WebAuthError> #584

Merged
merged 1 commit into from
Dec 9, 2021
Merged
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
4 changes: 2 additions & 2 deletions App/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ class ViewController: UIViewController {
.logging(enabled: true)
.clearSession(federated: false) { result in
switch result {
case true: print("Logged out")
case false: print("Log out failed")
case .success: print("Logged out")
case .failure(let error): print(error)
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion Auth0.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -837,11 +837,11 @@
5F3965C01CF679B500CDE7C0 /* WebAuth */ = {
isa = PBXGroup;
children = (
5B16D8901F7141E5009476A5 /* AuthTransactions */,
5C41F6AF244DCC1100252548 /* Platforms */,
5F53F5CD1CFD157300476A46 /* AuthTransaction.swift */,
5B16D8921F714324009476A5 /* AuthSession.swift */,
5F4A1F951D00AABC00C72242 /* OAuth2Grant.swift */,
5B16D8901F7141E5009476A5 /* AuthTransactions */,
5FCAB1751D0900CF00331C84 /* TransactionStore.swift */,
5F3965C11CF67CF000CDE7C0 /* WebAuth.swift */,
5FAE9C901D8878D400A871CE /* Auth0WebAuth.swift */,
Expand Down
14 changes: 11 additions & 3 deletions Auth0/ASCallbackTransaction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,20 @@ import AuthenticationServices

final class ASCallbackTransaction: BaseCallbackTransaction {

init(url: URL, schemeURL: URL, callback: @escaping (Bool) -> Void) {
init(url: URL, schemeURL: URL, callback: @escaping (WebAuthResult<Void>) -> Void) {
super.init(callback: callback)

let authSession = ASWebAuthenticationSession(url: url,
callbackURLScheme: schemeURL.scheme) { [weak self] url, _ in
self?.callback(url != nil)
callbackURLScheme: schemeURL.scheme) { [weak self] in
guard $0 != nil, $1 == nil else {
if let authError = $1, case ASWebAuthenticationSessionError.canceledLogin = authError {
self?.callback(.failure(WebAuthError(code: .userCancelled)))
} else {
self?.callback(.failure(WebAuthError(code: .unknown("ASWebAuthenticationSession failed"))))
}
return TransactionStore.shared.clear()
}
self?.callback(.success(()))
TransactionStore.shared.clear()
}

Expand Down
20 changes: 10 additions & 10 deletions Auth0/Auth0WebAuth.swift
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ final class Auth0WebAuth: WebAuth {
self.storage.store(session)
}

func clearSession(federated: Bool, callback: @escaping (Bool) -> Void) {
func clearSession(federated: Bool, callback: @escaping (WebAuthResult<Void>) -> Void) {
let endpoint = federated ?
URL(string: "v2/logout?federated", relativeTo: self.url)! :
URL(string: "v2/logout", relativeTo: self.url)!
Expand All @@ -170,7 +170,7 @@ final class Auth0WebAuth: WebAuth {
components?.queryItems = queryItems + [returnTo, clientId]

guard let logoutURL = components?.url, let redirectURL = self.redirectURL else {
return callback(false)
return callback(.failure(WebAuthError(code: .noBundleIdentifier)))
}

let session = ASCallbackTransaction(url: logoutURL,
Expand Down Expand Up @@ -252,11 +252,11 @@ extension Auth0WebAuth {
return Deferred { Future(self.start) }.eraseToAnyPublisher()
}

public func clearSession(federated: Bool) -> AnyPublisher<Bool, Never> {
public func clearSession(federated: Bool) -> AnyPublisher<Void, WebAuthError> {
return Deferred {
Future { callback in
self.clearSession(federated: federated) { result in
callback(.success(result))
callback(result)
}
}
}.eraseToAnyPublisher()
Expand Down Expand Up @@ -287,19 +287,19 @@ extension Auth0WebAuth {

#if compiler(>=5.5.2)
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *)
func clearSession(federated: Bool) async -> Bool {
return await withCheckedContinuation { continuation in
func clearSession(federated: Bool) async throws {
return try await withCheckedThrowingContinuation { continuation in
self.clearSession(federated: federated) { result in
continuation.resume(returning: result)
continuation.resume(with: result)
}
}
}
#else
@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
func clearSession(federated: Bool) async -> Bool {
return await withCheckedContinuation { continuation in
func clearSession(federated: Bool) async throws {
return try await withCheckedThrowingContinuation { continuation in
self.clearSession(federated: federated) { result in
continuation.resume(returning: result)
continuation.resume(with: result)
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions Auth0/BaseCallbackTransaction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@ class BaseCallbackTransaction: NSObject, AuthTransaction {

var authSession: AuthSession?
var state: String?
let callback: (Bool) -> Void
let callback: (WebAuthResult<Void>) -> Void

init(callback: @escaping (Bool) -> Void) {
init(callback: @escaping (WebAuthResult<Void>) -> Void) {
self.callback = callback
}

func cancel() {
self.callback(false)
self.callback(.failure(WebAuthError(code: .userCancelled)))
}

func resume(_ url: URL) -> Bool {
self.callback(true)
self.callback(.success(()))
return true
}

Expand Down
93 changes: 68 additions & 25 deletions Auth0/WebAuth.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// swiftlint:disable file_length

#if WEB_AUTH_PLATFORM
import Foundation
#if canImport(Combine)
Expand Down Expand Up @@ -139,9 +141,14 @@ public protocol WebAuth: Trackable, Loggable {
Starts the WebAuth flow.

```
let credentials = try await Auth0
.webAuth(clientId: clientId, domain: "samples.auth0.com")
.start()
do {
let credentials = try await Auth0
.webAuth(clientId: clientId, domain: "samples.auth0.com")
.start()
print("Obtained credentials: \(credentials)")
} catch {
print("Failed with \(error)")
}
```

Any on going WebAuth Auth session will be automatically cancelled when starting a new one,
Expand Down Expand Up @@ -194,7 +201,13 @@ public protocol WebAuth: Trackable, Loggable {
```
Auth0
.webAuth()
.clearSession { print($0) }
.clearSession { result in
switch result {
case .success:
print("Logged out")
case .failure(let error):
print("Failed with \(error)")
}
```

Remove Auth0 session and remove the IdP session:
Expand All @@ -209,7 +222,7 @@ public protocol WebAuth: Trackable, Loggable {
- federated: `Bool` to remove the IdP session. Defaults to `false`.
- callback: Callback called with bool outcome of the call.
*/
func clearSession(federated: Bool, callback: @escaping (Bool) -> Void)
func clearSession(federated: Bool, callback: @escaping (WebAuthResult<Void>) -> Void)

/**
Removes Auth0 session and optionally remove the Identity Provider session.
Expand All @@ -222,7 +235,14 @@ public protocol WebAuth: Trackable, Loggable {
Auth0
.webAuth()
.clearSession()
.sink(receiveValue: { print($0) })
.sink(receiveCompletion: { completion in
switch completion {
case .failure(let error):
print("Failed with \(error)")
case .finished:
print("Logged out")
}
}, receiveValue: { _ in })
.store(in: &cancellables)
```

Expand All @@ -240,7 +260,7 @@ public protocol WebAuth: Trackable, Loggable {
- Returns: A type-erased publisher.
*/
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *)
func clearSession(federated: Bool) -> AnyPublisher<Bool, Never>
func clearSession(federated: Bool) -> AnyPublisher<Void, WebAuthError>

#if compiler(>=5.5) && canImport(_Concurrency)
/**
Expand All @@ -251,15 +271,20 @@ public protocol WebAuth: Trackable, Loggable {
to the **Allowed Logout URLs** section of your application in the [Auth0 Dashboard](https://manage.auth0.com/#/applications/).

```
let result = await Auth0
.webAuth(clientId: clientId, domain: "samples.auth0.com")
.clearSession()
do {
try await Auth0
.webAuth(clientId: clientId, domain: "samples.auth0.com")
.clearSession()
print("Logged out")
} catch {
print("Failed with \(error)")
}
```

Remove Auth0 session and remove the IdP session:

```
let result = await Auth0
try await Auth0
.webAuth(clientId: clientId, domain: "samples.auth0.com")
.clearSession(federated: true)
```
Expand All @@ -269,10 +294,10 @@ public protocol WebAuth: Trackable, Loggable {
*/
#if compiler(>=5.5.2)
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *)
func clearSession(federated: Bool) async -> Bool
func clearSession(federated: Bool) async throws
#else
@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
func clearSession(federated: Bool) async -> Bool
func clearSession(federated: Bool) async throws
#endif
#endif
}
Expand All @@ -289,7 +314,13 @@ public extension WebAuth {
```
Auth0
.webAuth()
.clearSession { print($0) }
.clearSession { result in
switch result {
case .success:
print("Logged out")
case .failure(let error):
print("Failed with \(error)")
}
```

Remove Auth0 session and remove the IdP session:
Expand All @@ -304,7 +335,7 @@ public extension WebAuth {
- federated: `Bool` to remove the IdP session. Defaults to `false`.
- callback: Callback called with bool outcome of the call.
*/
func clearSession(federated: Bool = false, callback: @escaping (Bool) -> Void) {
func clearSession(federated: Bool = false, callback: @escaping (WebAuthResult<Void>) -> Void) {
self.clearSession(federated: federated, callback: callback)
}

Expand All @@ -319,7 +350,14 @@ public extension WebAuth {
Auth0
.webAuth()
.clearSession()
.sink(receiveValue: { print($0) })
.sink(receiveCompletion: { completion in
switch completion {
case .failure(let error):
print("Failed with \(error)")
case .finished:
print("Logged out")
}
}, receiveValue: { _ in })
.store(in: &cancellables)
```

Expand All @@ -337,7 +375,7 @@ public extension WebAuth {
- Returns: A type-erased publisher.
*/
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *)
func clearSession(federated: Bool = false) -> AnyPublisher<Bool, Never> {
func clearSession(federated: Bool = false) -> AnyPublisher<Void, WebAuthError> {
return self.clearSession(federated: federated)
}

Expand All @@ -350,15 +388,20 @@ public extension WebAuth {
to the **Allowed Logout URLs** section of your application in the [Auth0 Dashboard](https://manage.auth0.com/#/applications/).

```
let result = await Auth0
.webAuth(clientId: clientId, domain: "samples.auth0.com")
.clearSession()
do {
try await Auth0
.webAuth(clientId: clientId, domain: "samples.auth0.com")
.clearSession()
print("Logged out")
} catch {
print("Failed with \(error)")
}
```

Remove Auth0 session and remove the IdP session:

```
let result = await Auth0
try await Auth0
.webAuth(clientId: clientId, domain: "samples.auth0.com")
.clearSession(federated: true)
```
Expand All @@ -368,13 +411,13 @@ public extension WebAuth {
*/
#if compiler(>=5.5.2)
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *)
func clearSession(federated: Bool = false) async -> Bool {
return await self.clearSession(federated: federated)
func clearSession(federated: Bool = false) async throws {
return try await self.clearSession(federated: federated)
}
#else
@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
func clearSession(federated: Bool = false) async -> Bool {
return await self.clearSession(federated: federated)
func clearSession(federated: Bool = false) async throws {
return try await self.clearSession(federated: federated)
}
#endif
#endif
Expand Down
8 changes: 8 additions & 0 deletions Auth0Tests/Matchers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,14 @@ func beSuccessful<T>() -> Predicate<ManagementResult<T>> {
}
}

#if WEB_AUTH_PLATFORM
func beSuccessful<T>() -> Predicate<WebAuthResult<T>> {
return Predicate<WebAuthResult<T>>.define("be a successful result") { expression, failureMessage -> PredicateResult in
return try beSuccessful(expression, failureMessage)
}
}
#endif

func beSuccessful<T>() -> Predicate<CredentialsManagerResult<T>> {
return Predicate<CredentialsManagerResult<T>>.define("be a successful result") { expression, failureMessage -> PredicateResult in
return try beSuccessful(expression, failureMessage)
Expand Down
Loading