CredentialsManager

public struct CredentialsManager

Credentials management utility for securely storing and retrieving the user’s credentials from the Keychain.

  • Creates a new CredentialsManager instance.

    Declaration

    Swift

    public init(authentication: Authentication, storeKey: String = "credentials", storage: CredentialsStorage = A0SimpleKeychain())

    Parameters

    authentication

    Auth0 Authentication API client.

    storeKey

    Key used to store user credentials in the Keychain. Defaults to credentials.

    storage

    The CredentialsStorage instance used to manage credentials storage. Defaults to a standard A0SimpleKeychain instance.

  • Retrieves the user information from the Keychain synchronously, without checking if the credentials are expired. The user information is read from the stored ID Token.

    let user = credentialsManager.user
    

    Important

    Access to this property will not be protected by Biometric authentication.

    Declaration

    Swift

    public var user: UserInfo? { get }
  • Enables Biometric authentication for additional security during credentials retrieval.

    credentialsManager.enableBiometrics(withTitle: "Touch to Login")
    

    If needed, you can specify a particular LAPolicy to be used. E.g. you might want to support Face ID or Touch ID, but also allow fallback to passcode.

    credentialsManager.enableBiometrics(withTitle: "Touch or enter passcode to Login", 
                                        evaluationPolicy: .deviceOwnerAuthentication)
    

    Declaration

    Swift

    public mutating func enableBiometrics(withTitle title: String, cancelTitle: String? = nil, fallbackTitle: String? = nil, evaluationPolicy: LAPolicy = LAPolicy.deviceOwnerAuthenticationWithBiometrics)

    Parameters

    title

    Main message to display when Face ID or Touch ID is used.

    cancelTitle

    Cancel message to display when Face ID or Touch ID is used.

    fallbackTitle

    Fallback message to display when Face ID or Touch ID is used after a failed match.

    evaluationPolicy

    Policy to be used for authentication policy evaluation.

  • Stores a credentials instance in the Keychain.

    let didStore = credentialsManager.store(credentials: credentials)
    

    Declaration

    Swift

    public func store(credentials: Credentials) -> Bool

    Parameters

    credentials

    Credentials instance to store.

    Return Value

    If the credentials were stored.

  • Clears credentials stored in the Keychain.

    let didClear = credentialsManager.clear()
    

    Declaration

    Swift

    public func clear() -> Bool

    Return Value

    If the credentials were removed.

  • Calls the /oauth/revoke endpoint to revoke the Refresh Token and then clears the credentials if the request was successful. Otherwise, the credentials will not be cleared and the callback will be called with a failure result containing a revokeFailed error.

    credentialsManager.revoke { result in
       switch result {
       case .success:
           print("Revoked Refresh Token and cleared credentials")
       case .failure(let error):
           print("Failed with: \(error)")
       }
    }
    

    If you need to specify custom headers for the Refresh Token revocation:

    credentialsManager.revoke(headers: ["key": "value"]) { print($0) }
    

    If no Refresh Token is available the endpoint is not called, the credentials are cleared, and the callback is invoked with a success case.

    Declaration

    Swift

    public func revoke(headers: [String : String] = [:], _ callback: @escaping (CredentialsManagerResult<Void>) -> Void)

    Parameters

    headers

    Additional headers to use when revoking the Refresh Token.

    callback

    Callback that receives a Result containing either an empty success case or an error.

  • Checks that there are credentials stored, and that the Access Token has not expired and will not expire within the specified TTL.

    guard credentialsManager.hasValid() else {
        // No valid credentials exist, present the login page
    }
    // Retrieve stored credentials
    

    See

    expiresIn

    Declaration

    Swift

    public func hasValid(minTTL: Int = 0) -> Bool

    Parameters

    minTTL

    Minimum lifetime in seconds the Access Token must have left. Defaults to 0.

    Return Value

    If there are credentials stored containing an Access Token that is neither expired or about to expire.

  • Retrieves credentials from the Keychain and yields new credentials using the Refresh Token if the Access Token is expired. Otherwise, the retrieved credentials will be returned via the success case as they are not expired. Renewed credentials will be stored in the Keychain.

    credentialsManager.credentials { result in
       switch result {
       case .success(let credentials):
           print("Obtained credentials: \(credentials)")
       case .failure(let error):
           print("Failed with: \(error)")
       }
    }
    

    To avoid retrieving Access Tokens with too little time left, you can enforce a minimum TTL:

    credentialsManager.credentials(minTTL: 60) { print($0) }
    

    If you need to specify custom parameters or headers for the credentials renewal:

    credentialsManager.credentials(parameters: ["key": "value"],
                                   headers: ["key": "value"]) { print($0) }
    

    When renewing credentials you can get a downscoped Access Token by requesting fewer scopes than were requested on login. If you specify fewer scopes, the credentials will be renewed immediately, regardless of whether they are expired or not.

    credentialsManager.credentials(scope: "openid offline_access") { print($0) }
    

    Requires

    The scope offline_access to have been requested on login to get a Refresh Token from Auth0. If the credentials are expired and there is no Refresh Token, the callback will be called with a failure case containing a noRefreshToken error.

    Note

    This method is thread-safe.

    Declaration

    Swift

    public func credentials(withScope scope: String? = nil, minTTL: Int = 0, parameters: [String : Any] = [:], headers: [String : String] = [:], callback: @escaping (CredentialsManagerResult<Credentials>) -> Void)

    Parameters

    scope

    Space-separated list of scope values to request when renewing credentials. Defaults to nil, which will ask for the same scopes that were requested on login.

    minTTL

    Minimum time in seconds the Access Token must remain valid to avoid being renewed. Defaults to 0.

    parameters

    Additional parameters to use when renewing credentials.

    headers

    Additional headers to use when renewing credentials.

    callback

    Callback that receives a Result containing either the user’s credentials or an error.

  • Enables Biometric authentication for additional security during credentials retrieval.

    credentialsManager.enableBiometrics(withTitle: "Touch to Login")
    

    If needed, you can specify a particular LAPolicy to be used. E.g. you might want to support Face ID or Touch ID, but also allow fallback to passcode.

    credentialsManager.enableBiometrics(withTitle: "Touch or enter passcode to Login", 
                                        evaluationPolicy: .deviceOwnerAuthentication)
    

Combine

  • Calls the /oauth/revoke endpoint to revoke the Refresh Token and then clears the credentials if the request was successful. Otherwise, the credentials are not cleared and the subscription completes with an error.

    credentialsManager
        .revoke()
        .sink(receiveCompletion: { completion in
            switch completion {
            case .finished:
                print("Revoked Refresh Token and cleared credentials")
            case .failure(let error):
                print("Failed with: \(error)")
            }
        }, receiveValue: {})
        .store(in: &cancellables)
    

    If you need to specify custom headers for the Refresh Token revocation:

    credentialsManager
        .revoke(headers: ["key": "value"])
        .sink(receiveCompletion: { print($0) },
              receiveValue: {})
        .store(in: &cancellables)
    

    If no Refresh Token is available the endpoint is not called, the credentials are cleared, and the subscription completes without an error.

    Declaration

    Swift

    func revoke(headers: [String : String] = [:]) -> AnyPublisher<Void, CredentialsManagerError>

    Parameters

    headers

    Additional headers to use when revoking the Refresh Token.

    Return Value

    A type-erased publisher.

  • Retrieves credentials from the Keychain and yields new credentials using the Refresh Token if the Access Token is expired. Otherwise, the subscription will complete with the retrieved credentials as they are not expired. Renewed credentials will be stored in the Keychain.

    credentialsManager
        .credentials()
        .sink(receiveCompletion: { completion in
            if case .failure(let error) = completion {
                print("Failed with: \(error)")
            }
        }, receiveValue: { credentials in
            print("Obtained credentials: \(credentials)")
        })
        .store(in: &cancellables)
    

    To avoid retrieving Access Tokens with too little time left, you can enforce a minimum TTL:

    credentialsManager
        .credentials(minTTL: 60)
        .sink(receiveCompletion: { print($0) },
              receiveValue: { print($0) })
        .store(in: &cancellables)
    

    If you need to specify custom parameters or headers for the credentials renewal:

    credentialsManager
        .credentials(parameters: ["key": "value"],
                     headers: ["key": "value"])
        .sink(receiveCompletion: { print($0) },
              receiveValue: { print($0) })
        .store(in: &cancellables)
    

    When renewing credentials you can get a downscoped Access Token by requesting fewer scopes than were requested on login. If you specify fewer scopes, the credentials will be renewed immediately, regardless of whether they are expired or not.

    credentialsManager
        .credentials(scope: "openid offline_access")
        .sink(receiveCompletion: { print($0) },
              receiveValue: { print($0) })
        .store(in: &cancellables)
    

    Requires

    The scope offline_access to have been requested on login to get a Refresh Token from Auth0. If the credentials are expired and there is no Refresh Token, the subscription will complete with a noRefreshToken error.

    Note

    This method is thread-safe.

    Declaration

    Swift

    func credentials(withScope scope: String? = nil, minTTL: Int = 0, parameters: [String : Any] = [:], headers: [String : String] = [:]) -> AnyPublisher<Credentials, CredentialsManagerError>

    Parameters

    scope

    Space-separated list of scope values to request when renewing credentials. Defaults to nil, which will ask for the same scopes that were requested on login.

    minTTL

    Minimum time in seconds the Access Token must remain valid to avoid being renewed. Defaults to 0.

    parameters

    Additional parameters to use when renewing credentials.

    headers

    Additional headers to use when renewing credentials.

    Return Value

    A type-erased publisher.

Async/Await