getPasswordOrPasskey method

Future<PasswordOrPasskeyResponseType> getPasswordOrPasskey(
  1. AuthenticateRequestType? passkeyRequest, {
  2. bool? preferImmediatelyAvailableCredentials,
})

Shows the platform credential manager with the user's saved passwords and, when passkeyRequest is given, their passkeys, and returns the one the user picks.

A returned password has not been checked by anyone: sign in with it as if the user had typed it. A returned passkey assertion must be sent to the relying party server exactly like the result of authenticate.

With preferImmediatelyAvailableCredentials no sheet is shown when nothing is saved on the device, which suits showing it unprompted. When it is omitted, the value from passkeyRequest is used, or false when there is no passkeyRequest. The mediation of passkeyRequest does not apply here.

Passkeys need Android 9 (API 28) or newer. Below that only saved passwords are offered, even when passkeyRequest is given.

Throws PasskeyAuthCancelledException when the user dismisses the sheet, CredentialNotAuthenticatedException when none of the allowed credentials could be used, NoCredentialsAvailableException when nothing is saved, and PasswordCredentialUnsupportedException on platforms other than Android.

Implementation

Future<PasswordOrPasskeyResponseType> getPasswordOrPasskey(
  AuthenticateRequestType? passkeyRequest, {
  bool? preferImmediatelyAvailableCredentials,
}) async {
  if (debugMode && passkeyRequest != null) {
    await _doctor?.check(passkeyRequest.relyingPartyId);
  }

  try {
    await _platform.cancelCurrentAuthenticatorOperation();

    if (passkeyRequest != null) {
      _isValidChallenge(passkeyRequest.challenge);
      if (passkeyRequest.allowCredentials != null) {
        for (final credential in passkeyRequest.allowCredentials!) {
          _isValidCredentialID(credential.id);
        }
      }
    }

    return await _platform.getPasswordOrPasskey(
      passkeyRequest,
      preferImmediatelyAvailableCredentials:
          preferImmediatelyAvailableCredentials ??
          passkeyRequest?.preferImmediatelyAvailableCredentials ??
          false,
    );
  } on PlatformException catch (e, stackTrace) {
    if (debugMode) {
      _doctor?.recordException(e);
    }

    switch (e.code) {
      case 'password-credential-unsupported':
        throw PasswordCredentialUnsupportedException(e.message);
      case 'cancelled':
        throw PasskeyAuthCancelledException(e.message);
      case 'android-credential-not-authenticated':
        throw CredentialNotAuthenticatedException(e.message);
      case 'android-no-credential':
        throw NoCredentialsAvailableException();
      case 'domain-not-associated':
        throw DomainNotAssociatedException(e.message);
      case 'android-sync-account-not-available':
        throw SyncAccountNotAvailableException();
      case 'android-timeout':
        throw TimeoutException(e.message);
      default:
        if (e.code.startsWith('android-unhandled')) {
          throw UnhandledAuthenticatorException(e.code, e.message, e.details);
        }
        Error.throwWithStackTrace(e, stackTrace);
    }
  }
}