October 19th, 2015

Easily Authenticate Users with Android’s Confirm Credential

James Montemagno
Principal Manager, Tech PM

There are a number of ways to authenticate users on mobile devices, from traditional passwords and pins to new biometric fingerprint sensors. Most users are already using one of the most secure mobile authentication implementations, the device lock screen. With Android Marshmallow and the new Confirm Credential API, it’s now possible to utilize the lock screen to detect when the user last unlocked their device and even re-prompt them to confirm their identity without having to remember yet another app-specific password. All authentication is securely stored in a crypto key from the Android KeyStore with a customizable timeout period that’s carried across multiple applications.

confirm-980x576

Getting Started

It’s important to note that your user must have his or her lock screen already secured in Android’s settings before it’s possible to use the Confirm Credential API. Most Android users will have already done this, but it’s possible to check before even attempting by getting access to the KeyguardManager and prompting users to secure their lock screen:

//Create private KeyguardManager that will be used later on for Confirm Credentials
KeyguardManager keyguardManager;

protected override void OnCreate(Bundle bundle)
{
  //...Activity creation
  keyguardManager = (KeyguardManager)GetSystemService(Context.KeyguardService);
  if (!keyguardManager.IsKeyguardSecure)
  {
    // Show a message that the user hasn't set up a lock screen.
    Toast.MakeText(this, "Secure lock screen isn't set up.\n"
                    + "Go to 'Settings -> Security -> Screen lock' to set up a lock screen",
                    ToastLength.Short).Show();
  }
  else
  {
    //We are free to create our Cyrpto Key
    CreateKey();
  }
}

Creating Crypto Key

Once it’s verified that the user has set up a secure lock screen, it’s possible to attempt to create a crypto key with a specified timeout policy that’s used to see when the user last logged in. This timeout is set for a number of seconds, and developers are free to set it to any amount necessary for the app.

const string KeyName = "my_special_key";
void CreateKey()
{
  // Generate a key to decrypt payment credentials, tokens, etc.
  // This will most likely be a registration step for the user when they are setting up your app.
  var keyStore = KeyStore.GetInstance("AndroidKeyStore");
  keyStore.Load(null);
  var keyGenerator = KeyGenerator.GetInstance(KeyProperties.KeyAlgorithmAes, "AndroidKeyStore");

  // Set the alias of the entry in Android KeyStore where the key will appear
  // and the constrains (purposes) in the constructor of the Builder
  keyGenerator.Init(new KeyGenParameterSpec.Builder(KeyName, KeyStorePurpose.Decrypt | KeyStorePurpose.Encrypt)
					   .SetBlockModes(KeyProperties.BlockModeCbc)
					   .SetUserAuthenticationRequired(true)
                                           // Require that the user has unlocked in the last 30 seconds
					   .SetUserAuthenticationValidityDurationSeconds(30)
					   .SetEncryptionPaddings(KeyProperties.EncryptionPaddingPkcs7)
					   .Build());
  keyGenerator.GenerateKey();
}

Testing Last Unlock

When your code needs to authenticate the user, it simply needs to attempt to encrypt any data with the key that was created earlier. If the data can be encrypted with the key, then the user has logged in within our timeout period. If not, an UserNotAuthenticatedException is thrown and it’s time to confirm credentials. Here’s how to test encrypting a bit of data.

static readonly byte[] SecretData = new byte[] { 1, 2, 3, 4, 5, 6 };
void TryEncrypt()
{
  try
  {
    var keyStore = KeyStore.GetInstance("AndroidKeyStore");
    keyStore.Load(null);
    var secretKey = keyStore.GetKey(KeyName, null);
    var cipher = Cipher.GetInstance(KeyProperties.KeyAlgorithmAes + "/" + KeyProperties.BlockModeCbc + "/"  + KeyProperties.EncryptionPaddingPkcs7);
    cipher.Init(CipherMode.EncryptMode, secretKey);
    //attempt encrypting data
    cipher.DoFinal(SecretData);
    // If the user has recently authenticated, you will reach here.
  }
  catch (UserNotAuthenticatedException)
  {
    // User is not authenticated, let's authenticate with device credentials.
    ShowAuthenticationScreen();
  }
}

Showing the Authentication Screen

If the user is already authenticated, the app can move on to a checkout screen or log the user in. Otherwise, it’s time to prompt the user to confirm their credentials by simply creating a new Confirm Device Credential Intent from the KeyguardManager.

static readonly int ConfirmRequestId = 1;
void ShowAuthenticationScreen()
{
  var intent = keyguardManager.CreateConfirmDeviceCredentialIntent((string)null, (string)null);
  if (intent != null)
  {
    StartActivityForResult(intent, ConfirmRequestId);
  }
}

Android will automatically launch the lock screen that the user has specified when the Confirm Credential Intent is activated, whether it be a pin, password, or any other type of security such as a fingerprint. Personally I use a pin on my devices, so here’s what it looks like on my Nexus 9 when the intent is launched:

Pin Screen

At this point the user can do one of two things:

  • Enter the correct credentials.
  • Cancel the unlock screen.

The Activity will get a callback with a return code when one of these occur, which can be checked if the correct credentials were entered.

protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
  if (requestCode == ConfirmRequestId)
  {
    // Credentials entered successfully!
    if (resultCode == Result.Ok)
    {
      ShowPurchaseConfirmation();
    }
    else
    {
      // The user canceled or didn’t complete the lock screen
      // operation. Go to error/cancellation flow.
    }
  }
}

There you have it! No more passwords to remember, completely customized timeouts, and a workflow that’s familiar to your users.

Learn More

To learn more about getting started with Android Marshmallow, be sure to read through the getting started documentation. You can also find this sample and other Android Marshmallow samples on our Sample Gallery.

Category
Developers
Topics
Android

Author

James Montemagno
Principal Manager, Tech PM

James Montemagno is a Principal Lead Program Manager for Developer Community at Microsoft. He has been a .NET developer since 2005, working in a wide range of industries including game development, printer software, and web services. Prior to becoming a Principal Program Manager, James was a professional mobile developer and has now been crafting apps since 2011 with Xamarin. In his spare time, he is most likely cycling around Seattle or guzzling gallons of coffee at a local coffee shop. He ...

More about author

0 comments

Discussion are closed.