Accedere con una passkey

Questa guida continua l'implementazione dell'utilizzo delle passkey per l'autenticazione. Prima che gli utenti possano accedere con le passkey, devi anche completare le istruzioni riportate in Creare passkey.

Per eseguire l'autenticazione con una passkey, devi prima recuperare le opzioni necessarie per recuperare la chiave pubblica dal server dell'app, quindi chiamare l'API Credential Manager per recuperare la chiave pubblica. Poi, gestisci la risposta di accesso in modo appropriato.

Panoramica

Questa guida si concentra sulle modifiche richieste nell'app client per consentire all'utente di accedere con una passkey e fornisce una breve panoramica dell'implementazione lato server dell'app. Per saperne di più sull'integrazione lato server, consulta Autenticazione con passkey lato server.

Per recuperare tutte le opzioni di passkey e password associate all'account dell'utente, completa questi passaggi:

  1. Recupera le opzioni di richiesta delle credenziali dal server: effettua una richiesta da lla tua app al server di autenticazione per avviare la procedura di accesso con passkey. Dal server, invia le opzioni necessarie per ottenere la credenziale della chiave pubblica, nonché una sfida univoca.
  2. Crea l'oggetto necessario per ottenere la credenziale della chiave pubblica: inserisci le opzioni inviate dal server in un oggetto GetPublicKeyCredentialOption.
  3. (Facoltativo) **Prepara getCredential** : in Android 14 e versioni successive, puoi ridurre la latenza mostrando il selettore account utilizzando il prepareGetCredential() metodo prima di chiamare getCredential().
  4. Avvia il flusso di accesso: chiama il metodo getCredential() per consentire a ll'utente di accedere.
  5. **Gestisci la risposta**: gestisci ciascuna delle possibili risposte delle credenziali.
  6. Gestisci le eccezioni: assicurati di gestire le eccezioni in modo appropriato.

Recupera le opzioni di richiesta delle credenziali dal server

Richiedi al server le opzioni necessarie per ottenere le credenziali della chiave pubblica, nonché la challenge, che è univoca per ogni tentativo di accesso. Per saperne di più sull'implementazione lato server, consulta Creare la challenge e Creare le opzioni di richiesta delle credenziali.

Le opzioni sono simili alle seguenti:

{
  "challenge": "<your app challenge>",
  "allowCredentials": [],
  "rpId": "<your app server domain>"
}

Per saperne di più sui campi, consulta il post del blog sull'accesso con una passkey.

Crea l'oggetto necessario per ottenere la credenziale della chiave pubblica

Nella tua app, utilizza le opzioni per creare un oggetto GetPublicKeyCredentialOption. Nell'esempio seguente, requestJson rappresenta le opzioni inviate dal server.

// Get password logins from the credential provider on the user's device.
val getPasswordOption = GetPasswordOption()

// Get passkeys from the credential provider on the user's device.
val getPublicKeyCredentialOption = GetPublicKeyCredentialOption(
    requestJson = requestJson
)

Poi, inserisci GetPublicKeyCredentialOption in un oggetto GetCredentialRequest.

val credentialRequest = GetCredentialRequest(
    // Include all the sign-in options that your app supports.
    listOf(getPasswordOption, getPublicKeyCredentialOption),
    // Defines whether you prefer to use only immediately available
    // credentials or hybrid credentials.
    preferImmediatelyAvailableCredentials = preferImmediatelyAvailableCredentials
)

(Facoltativo) Riduci la latenza di accesso

Su Android 14 o versioni successive, puoi ridurre la latenza quando mostri il selettore account utilizzando il prepareGetCredential() metodo prima di chiamare getCredential().

Il metodo prepareGetCredential() restituisce un PrepareGetCredentialResponse oggetto memorizzato nella cache. In questo modo, il metodo getCredential() nel passaggio successivo visualizza il selettore account con i dati memorizzati nella cache.

coroutineScope {
    val response = credentialManager.prepareGetCredential(
        GetCredentialRequest(
            listOf(
                // Include all the sign-in options that your app supports
                getPublicKeyCredentialOption, 
                getPasswordOption
            )
        )
    )
}

Avvia il flusso di accesso

Chiama il metodo getCredential() per mostrare all'utente il selettore account. Utilizza il seguente snippet di codice come riferimento per avviare il flusso di accesso:

// Use an activity-based context to avoid undefined system UI
// launching behavior.
val context = MutableContextWrapper(activityContext)
coroutineScope {
    try {
        result = credentialManager.getCredential(
            // Use MutableContextWrapper to avoid memory leak during configuration changes
            context = context,
            request = credentialRequest
        )
        handleSignIn(result)
    } catch (e: GetCredentialException) {
        // Handle failure
    }
}

Gestisci la risposta

Gestisci la risposta, che può contenere uno dei vari tipi di oggetti credenziali.

fun handleSignIn(result: GetCredentialResponse) {
    // Handle the successfully returned credential.
    val credential = result.credential

    when (credential) {
        is PublicKeyCredential -> {
            val responseJson = credential.authenticationResponseJson
            // Share responseJson i.e. a GetCredentialResponse on your server to
            // validate and  authenticate
        }

        is PasswordCredential -> {
            val username = credential.id
            val password = credential.password
            // Use id and password to send to your server to validate
            // and authenticate
        }

        is CustomCredential -> {
            // If you are also using any external sign-in libraries, parse them
            // here with the utility functions provided.
            if (credential.type == ExampleCustomCredential.TYPE) {
                try {
                    val ExampleCustomCredential =
                        ExampleCustomCredential.createFrom(credential.data)
                    // Extract the required credentials and complete the authentication as per
                    // the federated sign in or any external sign in library flow
                } catch (e: ExampleCustomCredential.ExampleCustomCredentialParsingException) {
                    // Unlikely to happen. If it does, you likely need to update the dependency
                    // version of your external sign-in library.
                    Log.e(TAG, "Failed to parse an ExampleCustomCredential", e)
                }
            } else {
                // Catch any unrecognized custom credential type here.
                Log.e(TAG, "Unexpected type of credential")
            }
        }
        else -> {
            // Catch any unrecognized credential type here.
            Log.e(TAG, "Unexpected type of credential")
        }
    }
}

La PublicKeyCredential restituita dall'autenticazione è essenzialmente un'asserzione firmata, strutturata come segue:

{
  "id": "<credential ID>",
  "type": "public-key",
  "rawId": "<raw credential ID>",
  "response": {
    "clientDataJSON": "<signed client data containing challenge>",
    "authenticatorData": "<authenticator metadata>",
    "signature": "<digital signature to be verified>",
    "userHandle": "<user ID from credential registration>"
  }
}

Sul server, devi verificare la credenziale. Per saperne di più, consulta Verificare e consentire l'accesso all'utente.

Gestisci le eccezioni

Devi gestire tutte le eccezioni di sottoclasse di GetCredentialException. Per scoprire come gestire ogni eccezione, consulta la guida alla risoluzione dei problemi.

coroutineScope {
    try {
        result = credentialManager.getCredential(
            context = activityContext,
            request = credentialRequest
        )
    } catch (e: GetCredentialException) {
        Log.e("CredentialManager", "No credential available", e)
    }
}

Passaggi successivi