For the average person, it’s a monumental task to constantly monitor if any of their accounts have been affected by a breach. Because password reuse is an unfortunately extremely common practice, it becomes even more challenging to monitor all of the accounts that may be using the same credentials as the one involved in a breach.

On top of this, some passwords may not have been involved in a breach, but are still weak and should be updated. Some people have hundreds of accounts across all of their applications, so how can they possibly keep track of all of these credentials and make sure they aren’t vulnerable to an attack?

Apple aims to solve this problem with One Tap Account Upgrades.

At WWDC 2020, Apple announced some huge upgrades to how iOS manages passwords. These upgrades aim to alleviate some of the challenges faced by password management. In this article, we’ll look at Apple’s recent announcements on password upgrades, why they matter, and how they work behind the scenes.

What’s with Apple and Passwords?

Apple users often rely on Keychain and iCloud Keychain, Apple’s built-in credentials management system, to store and manage their passwords. Keychain is integrated deep within all of their operating systems and powers features such as WiFi hotspot credential sharing, beyond just being a password manager.

This year, Apple added several capabilities to Keychain related to breached or weak password detection and mitigation. Keychain now monitors for weak, re-used, or breached passwords, notifies the user regarding a breach, and offers mitigation options right away.

Apple Keychain homescreen
Apple Keychain password suggestion screen
Apple Keychain easily guessed reused password

The ability to check if your credentials or information were found in a breach is a great step towards mitigating the threats caused by a breach. Users have been able to check if they were affected by a breach using 3rd party password managers like 1Password or by checking websites like haveibeenpwned.com. Breached password detection is also offered by some service providers, such as Auth0’s breached password detection. With Apple’s recent announcement, this security feature has now been introduced to more than one billion iOS devices.

When it comes to handling a breach, notifying the user is only half of the problem. The other half is mitigating the threat. When a breached credential is detected, a user has to mitigate the threat by resetting the password manually, which can involve several steps. Apple intends to offer a one-tap mitigation to remove this burden on the user.

Easy Mitigation of Breached Credentials

One of the easiest ways to encourage a user to do something is to offer them a call to action (CTA) right away. Many password reset experiences are long and time-consuming, and some even require you to enter the answer to a secret security question that you set up ages ago!

Apple solves this problem by offering a CTA right in the report, inviting the user to mitigate the threat immediately. If a breached or weak password is detected, Keychain offers you a simple button that will replace the weak password with a new one or offer you to upgrade to Sign in with Apple. The image below demonstrates what happens when Keychain detects a weak password.

Apple Keychain easily guessed weak password

For this to work, there are two requirements:

  • The app must be installed on iOS
  • The app must offer an Account Upgrades Extension that offers the Upgrade to Strong Password capability

In addition to this, Apple introduced another call to action for apps that support Sign in with Apple. If your app supports it, Keychain will now offer a quick and easy way to upgrade the user’s account to Sign in with Apple with just the click of a button. Now, the user doesn’t have to worry about managing another username and password for that application!

It's exciting to see these password security upgrades. My personal wishlist for these features would include an experience similar to App Clips, but for account upgrades. App Clips are Apple’s ephemeral apps, which means you do not need to install the full application to use them. App Clips offer a great balance between opening a web page and installing an app. If you want to learn more about App Clips, keep an eye out for our upcoming blog post on App Clips.

For now, let’s look at how Account Upgrades work and some of the options Apple is offering to enhance password security:

  • Upgrade to Strong Password
  • Upgrade to Sign in with Apple
  • In-App Upgrades

How do Account Upgrades work?

Apple uses something called an App Extension to power the button that upgrades a weak password to Sign in with Apple. If you are unfamiliar with iOS nitty-gritty, an App Extension can be thought of as a service, intent, or an action handler. These are single-purpose micro-apps with specific entry and exit points. They are iOS triggered events that let a developer return a custom action in response. This is similar in concept to Auth0’s Hooks and Rules, but in this case, all of this is on the iOS client.

Some App Extension examples include Account Upgrade, SSO Capabilities, and more. Let’s take a closer look at the Account Upgrade Extension introduced in WWDC 2020.

The Account Upgrade Extension has four tasks:

  • Present the UI to accommodate extra steps when changing the password.
  • Upgrade the user’s password.
  • Present the UI to accommodate extra steps when changing the password.
  • Upgrade the user’s account to use Sign in with Apple.
  • To implement Account Upgrade Extension, you simply add a new target and select “Account Upgrade Extension”.
  • XCode then generates a template extension file, which includes each task as a single function handler. You are then expected to provide the business logic to perform the tasks. XCode will also generate an Info.plist file for the extension that informs iOS about the individual capabilities for account upgrades offered by this extension.

Next, let’s look at how the Upgrade to Strong Password feature works.

Upgrade to Strong Password

Programmatically, the Upgrade to Strong Password flow is similar to how the Account Upgrade to Sign in with Apple described in the previous section works.

On a high level, the Upgrade to Strong Password flow works as follows:

  • User taps on the "Upgrade to Strong Password" button
  • iOS will generate a strong password
  • Optionally, you can define the specific criteria for this password
  • iOS then activates your extension and calls changePasswordWithoutUserInteraction with the existing set of credentials and the new set of generated credentials.
  • At this point, your application needs to perform additional steps, such as calling an API, to actually finish this operation. Some next steps may include:
    • Check if the credentials don’t exist with .credentialIdentityNotFound
    • If second-factor authentication is required, you can respond with .userInteractionRequired
    • In any other error scenario, you can respond with .failed
    • Lastly, if everything goes correctly, you should invoke the completeChangePasswordRequest with the new set of credentials. This tells iOS that the process has successfully completed, at which point iOS will update its copy.
  • If your application responds with .userInteractionRequired, iOS will call prepareInterfaceToChangePassword to actually update the password.

The screenshots below show the Upgrade to Strong Password process in action. The “Easily guessed password warning” is displayed in the application. The user clicks “Change to Strong Password”, then the password is updated.

Apple Keychain change to strong password upgrade
Apple Keychain password upgrade confirmation
Apple Keychain account using strong password screen

Here is an example of what the Upgrade to Strong Password would look like in your application code:

override func changePasswordWithoutUserInteraction(for serviceIdentifier: ASCredentialServiceIdentifier, existingCredential: ASPasswordCredential, newPassword: String, userInfo: [AnyHashable : Any]? = nil) {
  changePassword(existingCredentials, newPassword, userInfo) { result in
    switch (result) {
      case .error(let errorCode):
        self.extensionContext.cancelRequest(withError: NSError(domain: ASExtensionErrorDomain, code: errorCode))
      case .success(_):
        let newCredential = ASPasswordCredential(
          user: existingCredential.user, 
          password: newPassword
        )
        self.extensionContext.completeChangePasswordRequest(
          updatedCredential: newCredential
        )
    }
  }
}

Let’s break it down a bit.

  • changePassword performs the actual operations for changing the user’s password.
  • If the result fails, it responds by canceling the request and showing the error to the user.
  • If the API change was successful, it will notify iOS regarding the state of the change.

Next, let’s look at how Upgrade to Sign in with Apple works.

Upgrade to Sign in with Apple

The Upgrade to Sign in with Apple flow is almost exactly the same. However, instead of a new set of credentials, iOS provides the original set of credentials and offers a way to perform Sign in With Apple interactions without having to start the application.

This interaction is slightly different from the usual Sign in with Apple flow when signing up or logging the user in. It explicitly informs the user about the action being taken and that their information from the past account will be linked to the new identity.

The flow is as follows:

  • The user taps on Upgrade to Sign in with Apple.
  • iOS will invoke convertAccountToSignInWithAppleWithoutUserInteraction with the set of existing credentials.
  • Like the password reset, you can respond with the appropriate error, and iOS will offer to perform second-factor authentication or inform the user.
  • Once this flow is complete, it’s important to note that Keychain will remove the password from its store. From this point, the user is supposed to use Sign in With Apple.
Apple Keychain easily guessed password
Apple Keychain SIWA upgrade

Let's walk through some of the code that could be used to accomplish this:

override func convertAccountToSignInWithAppleWithoutUserInteraction(for serviceIdentifier: ASCredentialServiceIdentifier, existingCredential: ASPasswordCredential, userInfo: [AnyHashable : Any]? = nil) {
  let challenge = validateExistingAccountAndPrepareForUpgrade(existingCredentials, userInfo)
  self.extensionContext.getSignInWithAppleUpgradeAuthorization(
    state: challenge.state, 
    nonce: challenge.nonce
    ) { (authorization, error) in
      if error != nil {
        // Handle error
        self.extensionContext.cancelRequest(withError: NSError(domain: ASExtensionErrorDomain, code: ASExtensionError.failed.rawValue))

        return
      }

      // handle the authorization 
      upgradeAccount(challenge, authorization) { error in
        if error != nil {
          // Handle error
          self.extensionContext.cancelRequest(withError: NSError(domain: ASExtensionErrorDomain, code: ASExtensionError.failed.rawValue))

          return
        }

        self.extensionContext.completeUpgradeToSignInWithApple(userInfo: nil)
      }
    }
  }
}

Let’s break it down a bit.

  • validateExistingAccountAndPrepareForUpgrade performs the actual operations for changing the user’s password.
  • If the result fails, it responds by canceling the request and showing the error to the user.
  • If the API change was successful, it will request Sign in with Apple authorization using getSignInWithAppleUpgradeAuthorization on extensionContext.
  • If this is successful, it will then try to upgrade the accounts.

In-App Upgrades

Since the underlying API is an extension, Apple also allows you to leverage the extension you have built from within your application. When doing so, you do not access the password, as your application should have already logged the user in.

You can do this as follows:

class ASInAppSIWALinkHelper: NSObject, ASAccountAuthenticationModificationControllerDelegate {
  var controller: ASAccountAuthenticationModificationController =  ASAccountAuthenticationModificationController()

  func accountAuthenticationModificationController(_ controller: ASAccountAuthenticationModificationController, didFail request: ASAccountAuthenticationModificationRequest, error: Error) {
    print("Error \(error) \(request.description)")
  }
  func accountAuthenticationModificationController(_ controller: ASAccountAuthenticationModificationController, didSuccessfullyComplete request: ASAccountAuthenticationModificationRequest, userInfo: [AnyHashable : Any]? = nil) {
    print("Success \(String(describing: userInfo))")
  }

  func siwaUpgrade() {
    print("Attempt")
    let userInfo = ["someid": "foobar"]
    let siwaUpgrade = ASAccountAuthenticationModificationReplacePasswordWithSignInWithAppleRequest(
        user: userIdenitifer,
        serviceIdentifier: ASCredentialServiceIdentifier(
            identifier: "yourdomain.com",
            type: .domain
        ),
        userInfo: userInfo
    )
    controller.delegate = self
    controller.perform(siwaUpgrade)
  }
}

Note that you are only sending the user’s identifier to the extension here. The app should retrieve the existing credentials from Keychain (or any storage mechanism) and use that token instead. The code for the upgrade will stay the same for the rest. This means that you can re-use most of your logic for In-App Upgrades as well as Keychain-initiated upgrades.

Security Concerns

As of writing this, the API for these features is currently in beta. iOS 14 is due to release in September, so we may see some changes in the APIs by then. In their current state, there are some concerns regarding these APIs.

One concern is that the Upgrade Password request does not allow the use of more modern password resetting flows, such as sending a one-time password reset link through email or some other verifiable factor. Additionally, in case of a breached credential, an attacker would be able to use the same API to potentially take over the account. While second-factor password does offer protection here, you should implement some sort of second-factor before allowing either interaction.

Conclusion

Apple has released several welcome changes to the Keychain that all iOS users can benefit from. This improves security for everyone on iOS. However, there are still some concerns to be resolved and design decisions to accommodate these solutions.

How would you use these extensions and enhancements in your application? What does your password reset experience look like? Do you wish to offer account upgrades in your app? Let us know in the comments below!

About Auth0

Auth0 provides a platform to authenticate, authorize, and secure access for applications, devices, and users. Security and development teams rely on Auth0's simplicity, extensibility, and expertise to make identity work for everyone. Safeguarding more than 4.5 billion login transactions each month, Auth0 secures identities so innovators can innovate, and empowers global enterprises to deliver trusted, superior digital experiences to their customers around the world.

For more information, visit https://auth0.com or follow @auth0 on Twitter.

Sources