Passkey, the solution for more secure authentication ?

BforBank
Bforbank Tech
Published in
10 min readNov 6, 2023

Written by Alexandre Legros

Introduction

In 2022, 90% of websites were targeted by phishing attacks, and one in two passwords was reused to access various online accounts, according to a source from the FIDO Alliance (Passkeys (Passkey Authentication) .

To mitigate these risks and prevent data breaches, it is recommended to avoid reusing credentials, opt for strong passwords, and change them immediately if a leak is detected on a service where you are registered.

These statistics and behaviors reveal glaring vulnerabilities in our current authentication systems. However, many improvements have been made to these systems to strengthen security.

Methods such as two-factor authentication and SMS confirmation after a transaction are now commonplace to enhance security. Nonetheless, these methods are not without flaws.

In the face of these security challenges faced by both individuals and businesses, a new standard has emerged, promising speed, simplicity, and robustness.

In this article, we will explore this new standard before delving specifically into Apple’s perspective on passkeys.

I. Current state of authentication

The method we commonly use to authenticate ourselves on websites and mobile applications has evolved over time, incorporating enhanced protection mechanisms.

Typically, the procedure goes as follows: we create an account by providing a username, usually an email address, and a password that must meet various criteria (presence of uppercase letters, numbers, special characters, etc.). When we wish to log in, we enter these identification details. The back-end logic validates these data, and if they are correct, it provides, for example, an access token, which will subsequently allow access to secure content. This mechanism is widely used for authentication on digital platforms.

Two-factor authentication is one of the major innovations aimed at strengthening the security of authentication systems. In this setup, the user receives a code via SMS or email, which they must then enter when logging in to confirm their identity. Other similar methods exist, such as the use of dedicated apps like Google Authenticator.

Fundamentally, the management of identification data (creation, modification, deletion of accounts, etc.) is handled server-side. However, this approach has its challenges. For instance, it’s common for users to reuse the same credentials across multiple sites, making them easier to remember. This habit, coupled with attacks leading to data breaches, presents a serious security issue. Phishing, where scammers duplicate the appearance of a legitimate site to deceive the user and fraudulently gather their information, is another well-known threat.

Given these realities, it’s clear that the traditional combination of username and password is no longer sufficient to ensure secure authentication. Therefore, it's imperative to rethink this method.

II. More Secure Authentication

II.I: FIDO

The Fast Identity Online Alliance (FIDO) was established in 2013, bringing together technology companies, government agencies, service providers, financial institutions, and various other industries (list of project participants: FIDO Alliance Member Companies & Organizations). Its primary goal was to reduce the reliance on passwords for accessing websites and applications.

Non-exhaustive list of companies contributing to this technology
Non-exhaustive list of companies contributing to this technology

The primary goal of this alliance is to develop authentication standards aimed at reducing the use of passwords while enhancing authentication standards for desktop computers and mobile devices.

FIDO is specifically designed to strengthen user security and privacy. This is achieved by ensuring that private keys and biometric data, where applicable, always remain on the user’s device. Thus, it becomes possible to authenticate using methods such as fingerprint recognition or entering a one-time PIN, without the need to memorize a complex password.

FIDO is also supported by major browsers and operating systems.

II.II: Passkey — Fast, Easy, Secure

Passkey is a new authentication method that allows you to log into an account, whether on a website or an application. It is based on three fundamental principles: Simplicity, Efficiency, and Security.

Here are the advantages of passkeys compared to traditional passwords:

Simplicity :

  • Instant account creation: the device is in charge of generating the credentials.
  • No need for memorization: the authentication codes, linked to private keys, are saved only on a given user’s devices.
  • Passkeys can be shared among different devices. In Apple’s context, this synchronization is done via iCloud. Thus, devices act as password managers, retaining all the information for you.

Efficiency :

  • Passkeys are generated quickly and can be synchronized across different devices. With Apple, this is done via iCloud, turning each device into a true digital safe.

Security :

  • By nature, passkeys are robust and unique, eliminating risks associated with password reuse.
  • Only public keys are accessible by the servers.
  • They are encrypted and stored in the iCloud keychain.
  • Access to the private key requires biometric authentication.
  • If data is compromised on one site, it doesn’t affect other sites or services as each passkey is distinct.

III. Implementation on iOS

To implement this solution, we will explore how to integrate Passkey into an iOS project. Apple offers a project template incorporating Passkey on its website. We will use this model as a basis to detail the steps necessary for the integration of this method.

For this procedure, it will be necessary to have a web domain on which we can upload an AASA file containing the identifier of our application.

III.I Project configuration

For the project to support associated domains, we need to configure it so that it can communicate with a remote server.

Here are the steps to follow:

Adding an associated domains type capability
Adding an associated domains type capability
  • Integrate the Associated Domains capability into the project. For this, navigate to Target > Signing & Capabilities.
  • Click on + Capabilities and then select the Associated Domains capability.
  • Add a domain of type webcredentials and fill in the corresponding domain. It's essential that this domain is accessible via HTTPS.

III.II Adding credentials

Depending on the information we wish to exchange between the app and the website, we will need to place a json type file in a specific location. For Passkey, it's the folder related to web credentials that is relevant.

Here’s how to proceed:

III.III Passkey API — ASAuthorization

Having completed the configurations, it’s now time to implement the functionality.

First, integrate the AuthenticationServices framework into a class dedicated to account creation and authentication.

import AuthenticationServices

The approach to set up Passkey remains consistent and covers the following phases:

  • Generation and saving of new keys.
  • Managing authentication via keys or password.

We could consider crafting three functions within a ViewModel, similar to what Apple suggests in its sample. These three functions are:

  • signInWith(…): This function will trigger authentication via a passkey.
  • beginAutoFillAssistedPasskeySignIn(…): It will use pre-existing Passkeys.
  • signUpWith(…): It will generate new Passkeys.

Each of these methods follows a similar logic. Firstly, set up a provider to handle a context, including communication with the domain. Then, generate a request tied to a challenge, and finally, use a controller to execute these requests.

III.III.I: signUpWith(…)

Modal offering the creation of a Passkey with biometric confirmation
Modal offering the creation of a Passkey with biometric confirmation

The purpose of this function is to generate a new pair of keys for the phone. To produce a key pair, Passkey requires a username. Hence the need to integrate a field for the identifier and enforce its completion.

Firstly, initialize a constant, publicKeyCredentialProvider, which solicits an ASAuthorizationPlatformPublicKeyCredentialProvider. This provider manages the context of our requests. It requires a string type parameter corresponding to our domain, previously defined in a constant.

let publicKeyCredentialProvider = ASAuthorizationPlatformPublicKeyCredentialProvider(relyingPartyIdentifier: domain)

After setting up the provider, we need to provide it with contextual elements before triggering the request. Firstly, establish a challenge that must be unique. Every interaction with the server should be distinct. This challenge will be of the Data type. Since our intention is to create a new key, additional information is required. Thus, we set up a userID and retrieve the userName (from the text field) passed as an argument to the function.

The preparation of our request then revolves around the challenge :

let challenge = Data()
let userID = Data(UUID().uuidString.utf8)
let registrationRequest = publicKeyCredentialProvider.createCredentialRegistrationRequest(challenge: challenge, name: userName, userID: userID)

All that’s left is to launch this request using an ASAuthorizationController with a list of requests as a parameter. Calling authController.performRequests() triggers the request.

let authController = ASAuthorizationController(authorizationRequests: [registrationRequest])
authController.delegate = self
authController.presentationContextProvider = self
authController.performRequests()
isPerformingModalReqest = true

When the request is processed, a response will be returned and handled by a specific delegate.

This results in the following method :

func signUpWith(userName: String, anchor: ASPresentationAnchor) {
self.authenticationAnchor = anchor
let publicKeyCredentialProvider = ASAuthorizationPlatformPublicKeyCredentialProvider(relyingPartyIdentifier: domain)

let challenge = Data()
let userID = Data(UUID().uuidString.utf8)

let registrationRequest = publicKeyCredentialProvider.createCredentialRegistrationRequest(challenge: challenge,
name: userName, userID: userID)
let authController = ASAuthorizationController(authorizationRequests: [registrationRequest])
authController.delegate = self
authController.presentationContextProvider = self
authController.performRequests()
isPerformingModalReqest = true
}

III.III.II: authorizationController(…)

When creating a new key, the response obtained is of the type ASAuthorizationPlatformPublicKeyCredentialRegistration. In this example, we only display the information, but in reality, we could save the key in the iCloud keychain, for instance. Furthermore, there's another method, authorizationController(...), designed to handle any potential errors.

Complete method :

func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
let logger = Logger()

switch authorization.credential {
case let credentialRegistration as ASAuthorizationPlatformPublicKeyCredentialRegistration:
logger.log("A new passkey was registered: \(credentialRegistration)")
// After the server verifies the registration and creates the user account, sign in the user with the new account.
didFinishSignIn()
case let credentialAssertion as ASAuthorizationPlatformPublicKeyCredentialAssertion:
logger.log("A passkey was used to sign in: \(credentialAssertion)")
// After the server verifies the assertion, sign in the user.
didFinishSignIn()
case let passwordCredential as ASPasswordCredential:
logger.log("A password was provided: \(passwordCredential)")
// After the server verifies the userName and password, sign in the user.
didFinishSignIn()
default:
fatalError("Received unknown authorization type.")
}

isPerformingModalReqest = false
}

III.III.III : signInWith(…)

Modal offering connection via a Passkey by biometrics
Modal offering connection via a Passkey by biometrics

Now, let’s focus on how Passkey handles authentication. Two functions support this aspect in this project: SignInWith(...) and beginAutoFillAssistedPasskeySignIn(...). We take a closer look at the SignInWith(...) function, which offers a more comprehensive approach.

This function informs us whether we should consider the user’s preferences, especially if they’ve already created passkeys before. The preferImmediatelyAvailableCredentials parameter, of boolean type, serves this purpose. If a preferred key is present, it will be used.

The subsequent approach resembles that of key creation. We call on a provider to establish a context, generate a challenge, and associate it with a type of request. All of this is then applied to a controller.

In the call to this function, a publicKeyCredentialProvider of type ASAuthorizationPlatformPublicKeyCredentialProvider is first declared, followed by the creation of a challenge.

Two requests are then prepared :

  • The first, createCredentialAssertionRequest, attempts to identify the private key from a public key provided by our site.
let assertionRequest = publicKeyCredentialProvider.createCredentialAssertionRequest(challenge: challenge)

The second uses another provider, ASAuthorizationPasswordProvider, to offer password authentication. It is independent of Passkey, so it doesn't require a challenge.

let passwordCredentialProvider = ASAuthorizationPasswordProvider()
let passwordRequest = passwordCredentialProvider.createRequest()

The controller is then called upon to handle the two possible scenarios (authentication via passkey or via password). Within the ASAuthorizationController, an array of requests is introduced, comprising the assertionRequest and the passwordRequest.

If preferImmediatelyAvailableCredentials is enabled, the controller prioritizes the use of a pre-existing key. In cases where there are multiple keys or none, the standard startup process is followed, causing a modal to appear.

If the response is positive and a matching key is found, the authorizationController(...) function is called. It offers two alternatives:

  • A validation via ASAuthorizationPlatformPublicKeyCredentialAssertion if a matching key is provided.
  • A password option via ASPasswordCredential.

After these steps, connecting to our account is possible.

Complete method :

func signInWith(anchor: ASPresentationAnchor, preferImmediatelyAvailableCredentials: Bool) {
self.authenticationAnchor = anchor
let publicKeyCredentialProvider = ASAuthorizationPlatformPublicKeyCredentialProvider(relyingPartyIdentifier: domain)

// Fetch the challenge from the server. The challenge needs to be unique for each request.
let challenge = Data()

let assertionRequest = publicKeyCredentialProvider.createCredentialAssertionRequest(challenge: challenge)

// Also allow the user to use a saved password, if they have one.
let passwordCredentialProvider = ASAuthorizationPasswordProvider()
let passwordRequest = passwordCredentialProvider.createRequest()

// Pass in any mix of supported sign-in request types.
let authController = ASAuthorizationController(authorizationRequests: [ assertionRequest, passwordRequest ] )
authController.delegate = self
authController.presentationContextProvider = self

if preferImmediatelyAvailableCredentials {
// If credentials are available, presents a modal sign-in sheet.
// If there are no locally saved credentials, no UI appears and
// the system passes ASAuthorizationError.Code.canceled to call
// `AccountManager.authorizationController(controller:didCompleteWithError:)`.
authController.performRequests(options: .preferImmediatelyAvailableCredentials)
} else {
// If credentials are available, presents a modal sign-in sheet.
// If there are no locally saved credentials, the system presents a QR code to allow signing in with a
// passkey from a nearby device.
authController.performRequests()
}
isPerformingModalReqest = true
}

Conclusion

Passkey offers multiple advantages in terms of credential security, providing concrete solutions to current issues with credential management.

Its significant strengths could well position it as the future standard for authentication. However, some improvements are necessary, especially concerning the sharing of passkeys between different ecosystems, which is currently complex. These challenges could slow down its widespread adoption.

At the time of writing this article, few applications have adopted this solution. This lack of enthusiasm can be explained for various reasons. Although promising, this solution still has gaps, especially in the sharing of private keys and the management of passkeys between different platforms, which remains complex.

Nevertheless, it is highly likely that Passkey will gain popularity in the coming years.

--

--