Face authentication with Android SDK
You can use face biometrics to reliably verify your customers' identity by biometrically matching a selfie to a known photo of the user. For example, face authentication can act as a step-up safeguard when a logged-in user wants to perform a money transfer or change their profile data. This guide describes how to quickly integrate face authentication into your Android application using our Android SDK, including both the client-side and backend integration.
How it works
Below is an example of a basic flow. Mosaic APIs are shown in pink, along with the relevant integration step.
After initializing the SDK (Step 3), your app starts a verification flow by creating a session in the backend that establishes a secure context and provides a reference image (Step 7 and Step 8) and then starting the session (Step 9). The SDK executes the verification process with the user using the Mosaic experience. Once the user's selfie is submitted, Mosaic starts processing the verification while the SDK polls for its status. Once processing is completed, the SDK notifies the app (Step 4) so it can obtain the verification result (Step 10) and proceed accordingly (Step 11).
Requirements
- Android 5+ (API level 21+)
Step 1: Configure your app
To integrate with Mosaic, you'll need to configure an application. From the Applications page, create a new application or use an existing one. From the application settings:
- For Client type , select native .
- For Redirect URI , enter your website URL. This is a mandatory field, but it isn't used for this flow.
- Obtain your client ID and secret, which are autogenerated upon app creation.
Step 2: Add SDK to project
Add the following lines in the shared build.gradle
file ("allprojects" scope):
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
maven {
url('https://transmit.jfrog.io/artifactory/transmit-security-gradle-release-local/')
}
mavenCentral()
google()
}
}
Add the following in the module build.gradle
file (project scope):
dependencies {
implementation("com.ts.sdk:identityverification:1.2.+")
}
Step 3: Initialize the SDK
Initialize using strings.xml configuration (recommended)
To do this, update the strings.xml file in your Application with the following content. The CLIENT_ID
should be replaced with your client ID from step 1(Step 1).
<resources>
<!-- Mosaic Credentials -->
<string name="transmit_security_client_id">"CLIENT_ID"</string>
<string name="transmit_security_base_url">https://api.transmitsecurity.io/</string>
</resources>
Note
The SDK can be configured to work with a different cluster by setting transmit_security_base_url
to https://api.eu.transmitsecurity.io/
(for EU) or https://api.ca.transmitsecurity.io/
(for Canada).
Add the code below to your Application Class
class MyApplication: Application() {
override fun onCreate() {
super.onCreate()
TSIdentityVerification.initializeSDK(this)
}
}
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
TSIdentityVerification.initializeSDK(this)
}
}
Initialize using SDK parameters
Configure the SDK using one of the snippets below, where CLIENT_ID
is your client ID (obtained in Step 1)
class MyApplication: Application() {
override fun onCreate() {
super.onCreate()
TSIdentityVerification.initialize(this, "CLIENT_ID", "https://api.transmitsecurity.io/")
}
}
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
TSIdentityVerification.initialize(this, "CLIENT_ID", "https://api.transmitsecurity.io/")
}
}
Note
The SDK can be configured to work with a different cluster by setting a third initialization parameter to baseUrl : 'https://api.eu.transmitsecurity.io/'
(for EU) or baseUrl : 'https://api.ca.transmitsecurity.io/'
(for Canada).
Step 4: Observe status updates
Once a face authentication process has been initiated (as described in Step 9), the process moves through different statuses. For example, the status will indicate if the process was completed successfully so the app can fetch the result.
To observe status changes, first register for the status by calling registerForFaceAuthStatus
on onStart
and then implement the ITSFaceAuthenticationStatus
shown below on the MainActivity
class of your app:
class MainActivity : AppCompatActivity(), ITSFaceAuthenticationStatus {
// Registers for status updates
override fun onStart() {
super.onStart()
TSIdentityVerification.registerForFaceAuthStatus(this)
}
// Notifies when user has started to capture a selfie
override fun faceAuthenticationStartCapturing() {
Log.d("faceAuthDidReceiveStatus", "faceAuthCapturing")
}
// Notifies when user has finished uploading a selfie and face authentication is being processed
override fun faceAuthenticationStartProcessing() {
Log.d("faceAuthDidReceiveStatus", "faceAuthProcessing")
}
// Notifies when authentication process completed, and the result can be obtained via backend (Step 10)
override fun faceAuthenticationCompleted() {
Log.d("faceAuthDidReceiveStatus", "faceAuthCompleted")
}
// Notifies when user has canceled the process
override fun faceAuthenticationCanceled() {
Log.d("faceAuthDidReceiveStatus", "faceAuthCanceled")
}
// Notifies when verification error occurs
override fun faceAuthenticationFail(error: TSIdentityVerificationError) {
Log.d("faceAuthDidFail", error.name)
}
}
public class MainActivity extends AppCompatActivity implements ITSFaceAuthenticationStatus {
@Override
protected void onStart() {
// Registers for status updates
super.onStart();
TSIdentityVerification.registerForFaceAuthStatus(this);
}
// Notifies when user has started to capture a selfie
@Override
public void faceAuthenticationStartCapturing() {
Log.d("faceAuthDidReceiveStatus", "faceAuthCapturing");
}
// Notifies when user has finished uploading a selfie and the face authentication is being processed
@Override
public void faceAuthenticationStartProcessing() {
Log.d("faceAuthDidReceiveStatus", "faceAuthProcessing");
}
// Notifies when authentication process completed, and the result can be obtained via backend (Step 10)
@Override
public void faceAuthenticationCompleted() {
Log.d("faceAuthDidReceiveStatus", "faceAuthCompleted");
}
// Notifies when user has canceled the process
@Override
public void faceAuthenticationCanceled() {
Log.d("faceAuthDidReceiveStatus", "faceAuthCanceled")
}
// Notifies when verification error occurs
@Override
public void faceAuthenticationFail(TSIdentityVerificationError error) {
Log.d("faceAuthDidFail", error.name());
}
}
Step 5: Add camera permission
Your app requires camera permissions in order to capture the images required for the verification process.
-
Open the
AndroidManifest.xml
file located in the app directory of your Android project. -
Add the following permission inside the
<manifest>
tag:
<uses-permission android:name="android.permission.CAMERA" />
- To handle camera permissions, add the following code snippet to the activity or fragment where you need to request camera permissions:
// Check if the camera permission is granted
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
// Camera permission granted, start face authentication here
} else {
// Request camera permission
ActivityCompat.requestPermissions(this, arrayOf(android.Manifest.permission.CAMERA), 101)
}
// Handle the result of the permission request
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
if (requestCode == 101) {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Camera permission granted, start face authentication here
} else {
// Camera permission denied, handle unauthorized state
}
}
}
// Check if the camera permission is granted
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
// Camera permission granted, start face authentication here
} else {
// Request camera permission
ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.CAMERA}, 101);
}
// Handle the result of the permission request
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (requestCode == 101) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Camera permission granted, start face authentication here
} else {
// Camera permission denied, handle unauthorized state
}
}
}
Step 6: Collect reference image
In the face authentication flow, a reference image is required to prove user's identity as Mosaic will compare the user's selfie against the reference. Your app should collect a reference image before starting the face authentication. This could be achieved by downloading the selfie created during the document verification flow, by fetching user ID photos from government databases, or using any other method of your choice.
For example, after a document verification flow, the selfie image can be retrieved by fetching all image IDs for the verification session (see Get all session images) and then fetching the selfie image itself by its ID (see Get image by ID).
Note
Mosaic stores document verification images for 90 days. Contact Mosaic to extend the retention period.
Step 7: Get access tokens
Since the access token is required to authorize the backend API calls, such as for creating a verification session (Step 8) and obtaining the result (Step 10), your app should be able to obtain these tokens from Mosaic.
import fetch from 'node-fetch';
async function run() {
const formData = {
client_id: '[CLIENT_ID]', // Client ID obtained in Step 1
client_secret: '[CLIENT_SECRET]', // Client secret obtained in Step 1
grant_type: 'client_credentials',
resource: 'https://verify.identity.security' // Targets IDV resource (required)
};
const resp = await fetch(
`https://api.transmitsecurity.io/oidc/token`,
{
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: new URLSearchParams(formData).toString()
}
);
const data = await resp.text();
console.log(data);
}
run();
Notes
-
The token must be requested for the
https://verify.identity.security
resource, which will appear in the audience claim of the generated token (in the future we’ll block access to tokens without this audience). - The token must remain secure on your server, and must only be used for backend requests.
Step 8: Create session
Before your mobile app can initiate the face auth process, your backend must create a session in order to provide a secure context for the flow and submit a reference image. To do this, send a request like the one below (see API reference):
Note
For optimal results, the image resolution should be HD to FHD (~1900x1000).
import fetch from 'node-fetch';
async function run() {
const resp = await fetch(
`https://api.transmitsecurity.io/verify/api/v1/face-auth`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer [CLIENT_ACCESS_TOKEN]' // Client access token generated in Step 7
},
body: JSON.stringify({
reference: {
type: 'raw',
content: '[IMAGE_CONTENT]', // Content of the image, as a base64 string
format: 'jpg' // Currently only jpeg is supported
}
})
}
);
const data = await resp.json();
console.log(data);
}
run();
The response contains device_session_id
that will be used to start the face authentication session on the client-side (in Step 9), and obtain the result (in Step 10). For example:
{
"device_session_id": "ca766ed78c8c0b7824dfea356ed30b72",
"session_id": "H1I12oskjzsdhskj4"
}
Step 9: Start session
Once a session is created, initiate the authentication process using the startFaceAuth()
SDK method. Add the code below to your mobile app, passing the device_session_id
value returned in the previous step. If successful, the SDK will start a face authentication process for the user and guide them through the flow using the Mosaic experience.
// Starts a face authentication process using the device session created in the backend
TSIdentityVerification.startFaceAuth(context, "DEVICE_SESSION_ID")
// Starts a face authentication process using the device session created in the backend
TSIdentityVerification.startFaceAuth(context, "DEVICE_SESSION_ID");
Step 10: Get results
Once the face authentication process starts, your mobile app can track its status using the extension added in Step 4. When the selfie is successfully submitted, Mosaic starts processing the verification and the SDK starts polling for the status. If the status is completed
, your backend should send the request below to obtain the verification result (see API reference):
import fetch from 'node-fetch';
async function run() {
const dsid = 'YOUR_dsid_PARAMETER'; // Device session ID returned in Step 8
const resp = await fetch(
`https://api.transmitsecurity.io/verify/api/v1/face-auth/${dsid}/result`,
{
method: 'GET',
headers: {
Authorization: 'Bearer [CLIENT_ACCESS_TOKEN]' // Client access token generated in Step 7
}
}
);
const data = await resp.text();
console.log(data);
}
run();
Step 11: Handle results
Your app should decide how to proceed based on the face authentication result returned in the previous step, which is indicated by the recommendation
field:
-
If
ALLOW
: the face authentication process was completed successfully. The user identity is confirmed. -
If
CHALLENGE
: the face authentication process didn't succeed, since at least one verification check didn't pass. Depending on your use case, proceed with other checks. -
If
DENY
: the face authentication indicates a high likelihood of attempted fraud. You should block the user or initiate an in-depth review to avoid fraudulent actions.
Here's an example response for a successful face authentication:
{
"status": "complete",
"recommendation": "ALLOW"
}