Skip to content

Commit

Permalink
Add support for async/await
Browse files Browse the repository at this point in the history
  • Loading branch information
Widcket committed Dec 6, 2021
1 parent 82e89d0 commit 2f66bae
Show file tree
Hide file tree
Showing 15 changed files with 784 additions and 62 deletions.
11 changes: 11 additions & 0 deletions Auth0.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@
5C4F553A23C9125600C89615 /* JWTAlgorithmSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C4F553923C9125600C89615 /* JWTAlgorithmSpec.swift */; };
5C53A7E92703A23200A7C0A3 /* UserInfoSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B2860D41EEF20F300C75D54 /* UserInfoSpec.swift */; };
5C53A7EA2703A23300A7C0A3 /* UserInfoSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B2860D41EEF20F300C75D54 /* UserInfoSpec.swift */; };
5C80980B275A7B8600DC0A76 /* CredentialsStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C80980A275A7B8600DC0A76 /* CredentialsStorage.swift */; };
5C80980C275A7B8600DC0A76 /* CredentialsStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C80980A275A7B8600DC0A76 /* CredentialsStorage.swift */; };
5C80980D275A7B8600DC0A76 /* CredentialsStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C80980A275A7B8600DC0A76 /* CredentialsStorage.swift */; };
5C80980E275A7B8600DC0A76 /* CredentialsStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C80980A275A7B8600DC0A76 /* CredentialsStorage.swift */; };
5CB41D4023D0BA2C00074024 /* IDTokenValidatorContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB41D3C23D0BA2C00074024 /* IDTokenValidatorContext.swift */; };
5CB41D4423D0BA2C00074024 /* IDTokenSignatureValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB41D3D23D0BA2C00074024 /* IDTokenSignatureValidator.swift */; };
5CB41D4823D0BA2C00074024 /* IDTokenValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB41D3E23D0BA2C00074024 /* IDTokenValidator.swift */; };
Expand Down Expand Up @@ -461,6 +465,7 @@
5C4F553423C9124200C89615 /* JWKSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JWKSpec.swift; sourceTree = "<group>"; };
5C4F553923C9125600C89615 /* JWTAlgorithmSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JWTAlgorithmSpec.swift; sourceTree = "<group>"; };
5C60412E27482A2600EEF515 /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = "<group>"; };
5C80980A275A7B8600DC0A76 /* CredentialsStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CredentialsStorage.swift; sourceTree = "<group>"; };
5CB41D3C23D0BA2C00074024 /* IDTokenValidatorContext.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IDTokenValidatorContext.swift; sourceTree = "<group>"; };
5CB41D3D23D0BA2C00074024 /* IDTokenSignatureValidator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IDTokenSignatureValidator.swift; sourceTree = "<group>"; };
5CB41D3E23D0BA2C00074024 /* IDTokenValidator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IDTokenValidator.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -687,6 +692,7 @@
5B1748731EF2D3A40060E653 /* Date.swift */,
5B9262BF1ECF0CA800F4F6D3 /* BioAuthentication.swift */,
5BEDE1891EC21B040007300D /* CredentialsManager.swift */,
5C80980A275A7B8600DC0A76 /* CredentialsStorage.swift */,
5B5E93F81EC45C22002A37F9 /* CredentialsManagerError.swift */,
);
name = Utils;
Expand Down Expand Up @@ -1557,6 +1563,7 @@
5F4A1F961D00AABC00C72242 /* OAuth2Grant.swift in Sources */,
5FCAB1731D09009600331C84 /* NSData+URLSafe.swift in Sources */,
5B16D88E1F7141A0009476A5 /* ASTransaction.swift in Sources */,
5C80980B275A7B8600DC0A76 /* CredentialsStorage.swift in Sources */,
5FD255BA1D14F70B00387ECB /* WebAuthError.swift in Sources */,
5BEDE18A1EC21B040007300D /* CredentialsManager.swift in Sources */,
5B2860CE1EEAC30500C75D54 /* UserInfo.swift in Sources */,
Expand Down Expand Up @@ -1615,6 +1622,7 @@
5FE2F8B31CCEAED8003628F4 /* Requestable.swift in Sources */,
5B2860CF1EEAC30900C75D54 /* UserInfo.swift in Sources */,
5C4F552423C8FBA100C89615 /* JWKS.swift in Sources */,
5C80980C275A7B8600DC0A76 /* CredentialsStorage.swift in Sources */,
5C41F6C9244F969F00252548 /* ASCallbackTransaction.swift in Sources */,
5C41F6D2244F972B00252548 /* JWTAlgorithm.swift in Sources */,
5C41F6D7244F975A00252548 /* TransactionStore.swift in Sources */,
Expand Down Expand Up @@ -1755,6 +1763,7 @@
5FDE875F1D8A424700EA27DC /* AuthenticationError.swift in Sources */,
5B1748761EF2D3A70060E653 /* Date.swift in Sources */,
5F23E6E31D4ACD7F00C3F2D9 /* ManagementError.swift in Sources */,
5C80980E275A7B8600DC0A76 /* CredentialsStorage.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -1790,6 +1799,7 @@
5FDE87601D8A424700EA27DC /* AuthenticationError.swift in Sources */,
5B1748771EF2D3A90060E653 /* Date.swift in Sources */,
5F23E70C1D4B88F600C3F2D9 /* ManagementError.swift in Sources */,
5C80980D275A7B8600DC0A76 /* CredentialsStorage.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -2392,6 +2402,7 @@
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
OTHER_SWIFT_FLAGS = "-DDEBUG";
PRODUCT_BUNDLE_IDENTIFIER = com.auth0.Auth0;
PRODUCT_NAME = Auth0;
SDKROOT = watchos;
Expand Down
43 changes: 43 additions & 0 deletions Auth0/Auth0WebAuth.swift
Original file line number Diff line number Diff line change
Expand Up @@ -264,4 +264,47 @@ extension Auth0WebAuth {

}

// MARK: - Async/Await

#if compiler(>=5.5) && canImport(_Concurrency)
extension Auth0WebAuth {

#if compiler(>=5.5.2)
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *)
func start() async throws -> Credentials {
return try await withCheckedThrowingContinuation { continuation in
self.start(continuation.resume)
}
}
#else
@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
func start() async throws -> Credentials {
return try await withCheckedThrowingContinuation { continuation in
self.start(continuation.resume)
}
}
#endif

#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
self.clearSession(federated: federated) { result in
continuation.resume(returning: 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
self.clearSession(federated: federated) { result in
continuation.resume(returning: result)
}
}
}
#endif

}
#endif
#endif
113 changes: 78 additions & 35 deletions Auth0/CredentialsManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,41 +8,6 @@ import LocalAuthentication
import Combine
#endif

/// Generic storage API for storing credentials
public protocol CredentialsStorage {
/// Retrieve a storage entry
///
/// - Parameters:
/// - forKey: The key to get from the store
/// - Returns: The stored data
func getEntry(forKey: String) -> Data?

/// Set a storage entry
///
/// - Parameters:
/// - _: The data to be stored
/// - forKey: The key to store it to
/// - Returns: if credentials were stored
func setEntry(_: Data, forKey: String) -> Bool

/// Delete a storage entry
///
/// - Parameters:
/// - forKey: The key to delete from the store
/// - Returns: if credentials were deleted
func deleteEntry(forKey: String) -> Bool
}

extension A0SimpleKeychain: CredentialsStorage {
public func getEntry(forKey: String) -> Data? {
return data(forKey: forKey)
}

public func setEntry(_ data: Data, forKey: String) -> Bool {
return setData(data, forKey: forKey)
}
}

/// Credentials management utility
public struct CredentialsManager {

Expand Down Expand Up @@ -343,3 +308,81 @@ public extension CredentialsManager {
}

}

// MARK: - Async/Await

#if compiler(>=5.5) && canImport(_Concurrency)
public extension CredentialsManager {

/// Calls the revoke token endpoint to revoke the refresh token and, if successful, the credentials are cleared. Otherwise,
/// the credentials are not cleared and an error is thrown.
///
/// If no refresh token is available the endpoint is not called, the credentials are cleared, and no error is thrown.
///
/// - Parameter headers: additional headers to add to a possible token revocation. The headers will be set via Request.headers.
/// - Throws: An error of type `CredentialsManagerError`.
#if compiler(>=5.5.2)
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *)
func revoke(headers: [String: String] = [:]) async throws {
return try await withCheckedThrowingContinuation { continuation in
self.revoke(headers: headers) { error in
if let error = error { return continuation.resume(throwing: error) }
continuation.resume(returning: ())
}
}
}
#else
@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
func revoke(headers: [String: String] = [:]) async throws {
return try await withCheckedThrowingContinuation { continuation in
self.revoke(headers: headers) { error in
if let error = error { return continuation.resume(throwing: error) }
continuation.resume(returning: ())
}
}
}
#endif

/// Retrieve credentials from the keychain and yield new credentials using `refreshToken` if `accessToken` has expired,
/// otherwise return the retrieved credentials as they have not expired. Renewed credentials will
/// be stored in the keychain.
///
/// ```
/// let credentials = try await credentialsManager.credentials()
/// ```
///
/// - Parameters:
/// - scope: scopes to request for the new tokens. By default is nil which will ask for the same ones requested during original Auth.
/// - minTTL: minimum time in seconds the access token must remain valid to avoid being renewed.
/// - parameters: additional parameters to add to a possible token refresh. The parameters will be set via Request.parameters.
/// - headers: additional headers to add to a possible token refresh. The headers will be set via Request.headers.
/// - Returns: the user's credentials.
/// - Throws: An error of type `CredentialsManagerError`.
/// - Important: This method only works for a refresh token obtained after auth with OAuth 2.0 API Authorization.
/// - Note: [Auth0 Refresh Tokens Docs](https://auth0.com/docs/security/tokens/refresh-tokens)
#if compiler(>=5.5.2)
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *)
func credentials(withScope scope: String? = nil, minTTL: Int = 0, parameters: [String: Any] = [:], headers: [String: String] = [:]) async throws -> Credentials {
return try await withCheckedThrowingContinuation { continuation in
self.credentials(withScope: scope,
minTTL: minTTL,
parameters: parameters,
headers: headers,
callback: continuation.resume)
}
}
#else
@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
func credentials(withScope scope: String? = nil, minTTL: Int = 0, parameters: [String: Any] = [:], headers: [String: String] = [:]) async throws -> Credentials {
return try await withCheckedThrowingContinuation { continuation in
self.credentials(withScope: scope,
minTTL: minTTL,
parameters: parameters,
headers: headers,
callback: continuation.resume)
}
}
#endif

}
#endif
38 changes: 38 additions & 0 deletions Auth0/CredentialsStorage.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import SimpleKeychain

/// Generic storage API for storing credentials
public protocol CredentialsStorage {
/// Retrieve a storage entry
///
/// - Parameters:
/// - forKey: The key to get from the store
/// - Returns: The stored data
func getEntry(forKey: String) -> Data?

/// Set a storage entry
///
/// - Parameters:
/// - _: The data to be stored
/// - forKey: The key to store it to
/// - Returns: if credentials were stored
func setEntry(_: Data, forKey: String) -> Bool

/// Delete a storage entry
///
/// - Parameters:
/// - forKey: The key to delete from the store
/// - Returns: if credentials were deleted
func deleteEntry(forKey: String) -> Bool
}

extension A0SimpleKeychain: CredentialsStorage {

public func getEntry(forKey: String) -> Data? {
return data(forKey: forKey)
}

public func setEntry(_ data: Data, forKey: String) -> Bool {
return setData(data, forKey: forKey)
}

}
6 changes: 4 additions & 2 deletions Auth0/NSURLComponents+OAuth2.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
import Foundation

extension URLComponents {
var a0_fragmentValues: [String: String] {

var fragmentValues: [String: String] {
var dict: [String: String] = [:]
let items = fragment?.components(separatedBy: "&")
items?.forEach { item in
Expand All @@ -17,10 +18,11 @@ extension URLComponents {
return dict
}

var a0_queryValues: [String: String] {
var queryValues: [String: String] {
var dict: [String: String] = [:]
self.queryItems?.forEach { dict[$0.name] = $0.value }
return dict
}

}
#endif
6 changes: 4 additions & 2 deletions Auth0/OAuth2Grant.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#if WEB_AUTH_PLATFORM
import Foundation

protocol OAuth2Grant {
Expand Down Expand Up @@ -95,9 +96,10 @@ struct PKCE: OAuth2Grant {
}

func values(fromComponents components: URLComponents) -> [String: String] {
var items = components.a0_fragmentValues
components.a0_queryValues.forEach { items[$0] = $1 }
var items = components.fragmentValues
components.queryValues.forEach { items[$0] = $1 }
return items
}

}
#endif
31 changes: 30 additions & 1 deletion Auth0/Request.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public struct Request<T, E: Auth0APIError>: Requestable {
/**
Starts the request to the server.

- parameter callback: called when the request finishes and yield it's result.
- Parameter callback: called when the request finishes and yield it's result.
*/
public func start(_ callback: @escaping Callback) {
let handler = self.handle
Expand Down Expand Up @@ -114,3 +114,32 @@ public extension Request {
}

}

// MARK: - Async/Await

#if compiler(>=5.5) && canImport(_Concurrency)
public extension Request {

/**
Starts the request to the server.

- Throws: An error that conforms to `Auth0APIError`; either an `AuthenticationError` or a `ManagementError`.
*/
#if compiler(>=5.5.2)
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *)
func start() async throws -> T {
return try await withCheckedThrowingContinuation { continuation in
self.start(continuation.resume)
}
}
#else
@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
func start() async throws -> T {
return try await withCheckedThrowingContinuation { continuation in
self.start(continuation.resume)
}
}
#endif

}
#endif
Loading

0 comments on commit 2f66bae

Please sign in to comment.