Crea una passkey

Prima che gli utenti possano autenticarsi con le passkey, la tua app deve prima registrare o creare la passkey per il loro account.

Per creare la passkey, recupera i dettagli necessari per la creazione dal server dell'app, quindi chiama l'API Credential Manager, che restituisce una coppia di chiavi pubblica e privata. La chiave privata restituita viene memorizzata in un provider di credenziali, come Gestore delle password di Google, come passkey. La chiave pubblica è archiviata sul server della tua app.

Le passkey vengono memorizzate in un provider di credenziali e le chiavi pubbliche vengono memorizzate sul server dell'app
Figura 1: creazione di passkey

Prerequisiti

Assicurati di aver configurato Digital Asset Links e di scegliere come target dispositivi con Android 9 (livello API 28) o versioni successive.

Panoramica

Questa guida si concentra sulle modifiche necessarie nell'app client relying party per creare una passkey e fornisce una breve panoramica dell'implementazione del server dell'app relying party. Per scoprire di più sull'integrazione lato server, consulta Registrazione della passkey lato server.

  1. Aggiungi dipendenze alla tua app: aggiungi le librerie di Credential Manager richieste.
  2. Instantiate Credential Manager: crea un'istanza di Credential Manager.
  3. Recupera le opzioni di creazione delle credenziali dal server dell'app: dal server dell'app, invia all'app client i dettagli necessari per creare la passkey, ad esempio informazioni sull'app, sull'utente, nonché un challenge e altri campi.
  4. Richiedi una passkey: nella tua app, utilizza i dettagli ricevuti dal server dell'app per creare un oggetto GetPublicKeyCredentialOption e utilizzalo per richiamare il metodo credentialManager.getCredential() per creare una passkey.
  5. Gestisci la risposta alla creazione della passkey: quando ricevi le credenziali nell'app client, devi codificare, serializzare e quindi inviare la chiave pubblica al server dell'app. Devi anche gestire ciascuna delle eccezioni che possono verificarsi in caso di creazione di passkey.
  6. Verifica e salva la chiave pubblica sul server: completa i passaggi lato server per verificare l'origine della credenziale, quindi salva la chiave pubblica.
  7. Notifica all'utente: notifica all'utente che la sua passkey è stata creata.

1. Aggiungere dipendenze all'app

Aggiungi le seguenti dipendenze al file build.gradle del modulo dell'app:

Kotlin

dependencies {
    implementation("androidx.credentials:credentials:1.6.0-beta03")
    implementation("androidx.credentials:credentials-play-services-auth:1.6.0-beta03")
}

Trendy

dependencies {
    implementation "androidx.credentials:credentials:1.6.0-beta03"
    implementation "androidx.credentials:credentials-play-services-auth:1.6.0-beta03"
}

2. Crea un'istanza di Credential Manager

Utilizza il contesto dell'app o dell'attività per creare un oggetto CredentialManager.

// Use your app or activity context to instantiate a client instance of
// CredentialManager.
private val credentialManager = CredentialManager.create(context)

3. Recuperare le opzioni di creazione delle credenziali dal server dell'app

Quando l'utente fa clic sul pulsante "Crea passkey" o quando un nuovo utente si registra, invia una richiesta dalla tua app al server dell'app per ottenere le informazioni necessarie per avviare la procedura di registrazione della passkey.

Utilizza una libreria conforme a FIDO nel server delle app per inviare all'app client le informazioni necessarie per creare una passkey, ad esempio informazioni sull'utente, sull'app e proprietà di configurazione aggiuntive. Per saperne di più, consulta la sezione Registrazione delle passkey lato server.

Nell'app client, decodifica le opzioni di creazione della chiave pubblica inviate dal server dell'app. Questi sono generalmente rappresentati in formato JSON. Per saperne di più su come viene eseguita questa decodifica per i client web, vedi Codifica e decodifica. Per le app client Android, devi gestire la decodifica separatamente.

Il seguente snippet mostra la struttura delle opzioni di creazione della chiave pubblica inviate dal server dell'app:

{
  "challenge": "<base64url-encoded challenge>",
  "rp": {
    "name": "<relying party name>",
    "id": "<relying party host name>"
  },
  "user": {
    "id": "<base64url-encoded user ID>",
    "name": "<user name>",
    "displayName": "<user display name>"
  },
  "pubKeyCredParams": [
    {
      "type": "public-key",
      "alg": -7
    }
  ],
  "attestation": "none",
  "excludeCredentials": [
    {
        "id": "<base64url-encoded credential ID to exclude>", 
        "type": "public-key"
    }
  ],
  "authenticatorSelection": {
    "requireResidentKey": true,
    "residentKey": "required",
    "userVerification": "required"
  }
}

I campi chiave nelle opzioni di creazione della chiave pubblica includono:

  • challenge: una stringa casuale generata dal server utilizzata per impedire attacchi di replay.
  • rp: dettagli sull'app.
    • rp.name: il nome dell'app.
    • rp.id: il dominio o il sottodominio dell'app.
  • user: Dettagli sull'utente.
    • id: l'ID univoco dell'utente. Questo valore non deve includere informazioni che consentono l'identificazione personale, ad esempio indirizzi email o nomi utente. Puoi utilizzare un valore casuale di 16 byte.
    • name: un identificatore univoco per l'account che l'utente riconoscerà, ad esempio il suo indirizzo email o nome utente. Verrà visualizzato nel selettore account. Se utilizzi un nome utente, usa lo stesso valore dell'autenticazione con password.
    • displayName: Un nome facoltativo e facile da ricordare per l'account destinato alla visualizzazione nel selettore di account.
  • authenticatorSelection: Dettagli sul dispositivo che verrà utilizzato per l'autenticazione.

    • authenticatorAttachment: indica l'autenticatore preferito. I valori possibili sono i seguenti: - platform: questo valore viene utilizzato per un autenticatore integrato nel dispositivo dell'utente, ad esempio un sensore di impronte. - cross-platform: questo valore viene utilizzato per i dispositivi in roaming, ad esempio i token di sicurezza. Non viene in genere utilizzato nel contesto delle passkey. - Non specificato (consigliato): se non specifichi questo valore, gli utenti hanno la flessibilità di creare passkey sui dispositivi che preferiscono. Nella maggior parte dei casi, l'opzione migliore è lasciare il parametro non specificato.
      • requireResidentKey: per creare una passkey, imposta il valore di questo campo Boolean su true.
      • residentKey: per creare una passkey, imposta il valore su required.
      • userVerification: utilizzato per specificare i requisiti per la verifica dell'utente durante la registrazione di una passkey. I valori possibili sono i seguenti: - preferred: utilizza questo valore se dai la priorità all'esperienza utente rispetto alla protezione, ad esempio in ambienti in cui la verifica dell'utente causa più attrito che protezione. - required: utilizza questo valore se è necessario richiamare un metodo di verifica dell'utente disponibile sul dispositivo. - discouraged: utilizza questo valore se l'utilizzo di un metodo di verifica dell'utente è sconsigliato.
        Per saperne di più su userVerification, consulta Approfondimento sulla verifica utente.
  • excludeCredentials: Elenca gli ID credenziali in un array per impedire la creazione di una passkey duplicata se ne esiste già una con lo stesso provider di credenziali.

4. Richiedere una passkey

Dopo aver analizzato le opzioni di creazione della chiave pubblica lato server, crea una passkey racchiudendo queste opzioni in un oggetto CreatePublicKeyCredentialRequest e chiamando createCredential().

Il createPublicKeyCredentialRequest include quanto segue:

  • requestJson: Le opzioni di creazione delle credenziali inviate dal server delle app.
  • preferImmediatelyAvailableCredentials: questo è un campo booleano facoltativo che definisce se utilizzare solo le credenziali disponibili localmente o sincronizzate con il provider di credenziali per soddisfare la richiesta, anziché le credenziali di token di sicurezza o flussi di chiavi ibride. I possibili utilizzi sono i seguenti:
    • false (predefinito): utilizza questo valore se la chiamata a Credential Manager è stata attivata da un'azione esplicita dell'utente.
    • true: utilizza questo valore se Credential Manager viene chiamato in modo opportunistico, ad esempio quando apri l'app per la prima volta.
      Se imposti il valore su true e non sono disponibili credenziali immediatamente, Credential Manager non mostrerà alcuna UI e la richiesta non andrà a buon fine immediatamente, restituendo NoCredentialException per le richieste di recupero e CreateCredentialNoCreateOptionException per le richieste di creazione.
  • origin: questo campo viene impostato automaticamente per le app per Android. Per i browser e le app con privilegi simili che devono impostare origin, vedi Effettuare chiamate a Credential Manager per conto di altre parti per le app con privilegi.
  • isConditional: questo è un campo facoltativo il cui valore predefinito è false. Quando imposti questo valore su true e se un utente non ha una passkey, ne crei automaticamente una per suo conto al successivo accesso con una password salvata. La passkey viene memorizzata nel provider di credenziali dell'utente. La funzionalità di creazione condizionale richiede l'ultima versione di androidx.credentials.

La chiamata alla funzione createCredential() avvia l'interfaccia utente del foglio inferiore integrata di Credential Manager che chiede all'utente di utilizzare una passkey e di selezionare un provider di credenziali e un account per l'archiviazione. Tuttavia, se isConditional è impostato su true, l'interfaccia utente del foglio inferiore non viene visualizzata e la passkey viene creata automaticamente.

5. Gestire la risposta

Dopo la verifica dell'utente tramite il blocco schermo del dispositivo, viene creata una passkey e memorizzata nel provider di credenziali selezionato dall'utente.

La risposta dopo aver chiamato correttamente createCredential() è un oggetto PublicKeyCredential.

Il codice PublicKeyCredential ha il seguente aspetto:

{
  "id": "<identifier>",
  "type": "public-key",
  "rawId": "<identifier>",
  "response": {
    "clientDataJSON": "<ArrayBuffer encoded object with the origin and signed challenge>",
    "attestationObject": "<ArrayBuffer encoded object with the public key and other information.>"
  },
  "authenticatorAttachment": "platform"
}

Nell'app client, serializza l'oggetto e invialo al server dell'app.

Aggiungi il codice per gestire gli errori come mostrato nel seguente snippet:

fun handleFailure(e: CreateCredentialException) {
    when (e) {
        is CreatePublicKeyCredentialDomException -> {
            // Handle the passkey DOM errors thrown according to the
            // WebAuthn spec.
        }
        is CreateCredentialCancellationException -> {
            // The user intentionally canceled the operation and chose not
            // to register the credential.
        }
        is CreateCredentialInterruptedException -> {
            // Retry-able error. Consider retrying the call.
        }
        is CreateCredentialProviderConfigurationException -> {
            // Your app is missing the provider configuration dependency.
            // Most likely, you're missing the
            // "credentials-play-services-auth" module.
        }
        is CreateCredentialCustomException -> {
            // You have encountered an error from a 3rd-party SDK. If you
            // make the API call with a request object that's a subclass of
            // CreateCustomCredentialRequest using a 3rd-party SDK, then you
            // should check for any custom exception type constants within
            // that SDK to match with e.type. Otherwise, drop or log the
            // exception.
        }
        else -> Log.w(TAG, "Unexpected exception type ${e::class.java.name}")
    }
}

6. Verifica e salva la chiave pubblica sul server dell'app

Sul server delle app, devi verificare la credenziale della chiave pubblica e poi salvare la chiave pubblica.

Per verificare l'origine della credenziale della chiave pubblica, confrontala con un elenco consentito di app approvate. Se una chiave ha un'origine non riconosciuta, rifiutala.

Per ottenere l'impronta SHA-256 dell'app:

  1. Stampa il certificato di firma dell'app di rilascio eseguendo questo comando in un terminale:

    keytool -list -keystore <path-to-apk-signing-keystore>
    

    Nella risposta, identifica l'impronta SHA 256 del certificato di firma, indicata come Certificate fingerprints block : SHA256.

  2. Codifica l'impronta SHA256 con la codifica base64url. Questo esempio Python mostra come codificare correttamente l'impronta:

    import binascii
    import base64
    fingerprint = '<SHA256 finerprint>' # your app's SHA256 fingerprint
    print(base64.urlsafe_b64encode(binascii.a2b_hex(fingerprint.replace(':', ''))).decode('utf8').replace('=', ''))
    
  3. Aggiungi android:apk-key-hash: all'inizio dell'output del passaggio precedente in modo da ottenere un risultato simile al seguente:

    android:apk-key-hash:<encoded SHA 256 fingerprint>
    

    Il risultato deve corrispondere a un'origine consentita sul server dell'app. Se hai più certificati di firma, ad esempio certificati per il debug e il rilascio, o più app, ripeti la procedura e accetta tutte le origini come valide sul server delle app.

7. Notificare all'utente

Una volta creata la passkey, comunica agli utenti che possono gestirle dall'app del provider di credenziali o dalle impostazioni dell'app. Avvisa gli utenti utilizzando una finestra di dialogo, una notifica o uno snackbar personalizzati. Poiché la creazione imprevista di una passkey da parte di un'entità dannosa richiede un avviso di sicurezza immediato, valuta la possibilità di integrare questi metodi in-app con una comunicazione esterna, ad esempio un'email.

Migliorare l'esperienza utente

Per migliorare l'esperienza utente durante l'implementazione della registrazione con Credential Manager, valuta la possibilità di aggiungere funzionalità per il ripristino delle credenziali e la soppressione delle finestre di dialogo di compilazione automatica.

Aggiungere la funzionalità per ripristinare le credenziali su un nuovo dispositivo

Per consentire agli utenti di accedere facilmente ai propri account su un nuovo dispositivo, implementa la funzionalità Ripristina credenziali. L'aggiunta delle credenziali di ripristino con BackupAgent consente agli utenti di accedere quando aprono l'app ripristinata su un nuovo dispositivo, consentendo loro di utilizzare subito l'app.

(Facoltativo) Disattivare la compilazione automatica nei campi delle credenziali

Per le schermate delle app in cui gli utenti devono utilizzare l'interfaccia utente del foglio inferiore di Credential Manager per l'autenticazione, aggiungi l'attributo isCredential ai campi nome utente e password. In questo modo, le finestre di dialogo di compilazione automatica (FillDialog e SaveDialog) non si sovrappongono all'interfaccia utente del riquadro inferiore di Gestore delle credenziali.

L'attributo isCredential è supportato su Android 14 e versioni successive.

L'esempio seguente mostra come aggiungere l'attributo isCredential ai campi pertinenti di nome utente e password nelle visualizzazioni pertinenti per la tua app:

<TextView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:isCredential="true" />

Passaggi successivi