UMFA APIs for Native Android Applications
Ideem's Universal MFA interfaces are used to integrate secure mutli-factor authentication into your application. The provided interfaces allow you to determine if a user has already been enrolled (cryptographically bound) to a device, create an enrollment if they have not, or authenticate them if they have. Enroll and authenticate operations provide a token upon successful completion, and that token must be passed back to customer's application server, and validated through a server-to-server API call to Ideem's infrastructure.
UMFA functions are used to provide a silent second factor after strong authentication, as well as reverification when needed for transactions requiring step up authentication.
Interface Definitions
Jump to: Kotlin, Java, Token Validation
Getting the version number of the SDK library: UMFAClient.versionString
To retrieve the version number of the SDK library use the class property UMFAClient.versionString. It will return the version number in semantic versioning format, major.minor.patch.
Kotlin
Check Enrollment: UMFAClient.checkEnrollment()
The checkEnrollment method checks if a user has previously enrolled in the Universal Multi-Factor Authentication (UMFA) process on the current device. This allows the application to determine whether to proceed with enrollment or authentication flows.
Usage
client.checkEnrollment(userId) { response, error ->
if (response != null) {
val rawId = response.getString("rawId")
// Handle retrieved enrollment data
} else {
Log.e("UMFAClient", "Error retrieving enrollment data: ${error?.localizedMessage}")
}
}
Parameters
| Parameter Name | Data Type | Description |
|---|---|---|
userId | String | The user ID to check enrollment for. |
completion | (JSONObject?, ZSMError?) -> Unit | A callback function that handles the response. |
Returns
The callback function returns the following parameters:
| Parameter Name | Data Type | Description |
|---|---|---|
response | JSONObject? | The retrieved enrollment data, if the user is enrolled. |
error | ZSMError? | Error details if enrollment retrieval fails. |
Enroll: UMFAClient.enroll()
The enroll method initiates the enrollment process for the Universal Multi-Factor Authentication (UMFA). This process binds the user's identity to the device, which is required for subsequent authentication operations.
Usage
client.enroll(userId) { response, error ->
if (response != null) {
// Handle successful enrollment, store or use the token
} else {
Log.e("UMFAClient", "Error during enrollment: ${error?.localizedMessage}")
}
}
Parameters
| Parameter Name | Data Type | Description |
|---|---|---|
userId | String | The user ID to enroll. |
completion | (JSONObject?, ZSMError?) -> Unit | A callback function that handles the response. |
Returns
The callback function returns the following parameters:
| Parameter Name | Data Type | Description |
|---|---|---|
response | JSONObject? | The enrollment response containing the authentication token. |
error | ZSMError? | Error details if enrollment fails. |
Authenticate: UMFAClient.authenticate()
The authenticate method performs an authentication operation using the credentials stored on the device. If the credentials are not present, authentication will fail.
Usage
client.authenticate(userId) { response, error ->
if (response != null) {
// Handle successful authentication
} else {
Log.e("UMFAClient", "Error during authentication: ${error?.localizedMessage}")
}
}
Parameters
| Parameter Name | Data Type | Description |
|---|---|---|
userId | String | The user ID to authenticate. |
completion | (JSONObject?, ZSMError?) -> Unit | A callback function that handles the response. |
Returns
The callback function returns the following parameters:
| Parameter Name | Data Type | Description |
|---|---|---|
response | JSONObject? | The authentication response containing the verified token. |
error | ZSMError? | Error details if authentication fails. |
Unenroll: UMFAClient.unenroll()
The unenroll method removes a specific user's UMFA credentials from the device.
Usage
client.unenroll(userId) { error ->
if (error == null) {
Log.d("UMFAClient", "Successfully unenrolled user")
} else {
Log.e("UMFAClient", "Error during unenrollment: ${error.localizedMessage}")
}
}
Parameters
| Parameter Name | Data Type | Description |
|---|---|---|
userId | String | The user ID to unenroll. |
completion | (ZSMError?) -> Unit | A callback function that handles the response. |
Returns
The callback function returns the following parameter:
| Parameter Name | Data Type | Description |
|---|---|---|
error | ZSMError? | Error details if unenrollment fails; null on success. |
Java
Check Enrollment: UMFAClient.checkEnrollment()
The checkEnrollment method checks if a user has previously enrolled in the Universal Multi-Factor Authentication (UMFA) process on the current device. This allows the application to determine whether to proceed with enrollment or authentication flows.
Usage
client.checkEnrollment(userId, (response, error) -> {
if (response != null) {
try {
String rawId = response.getString("rawId");
// Handle retrieved enrollment data
} catch (JSONException e) {
Log.e("UMFAClient", "Error parsing JSON response: " + e.getMessage());
}
} else {
Log.e("UMFAClient", "Error retrieving enrollment data: " + (error != null ? error.getLocalizedMessage() : "Unknown"));
}
});
Parameters
| Parameter Name | Data Type | Description |
|---|---|---|
userId | String | The user ID to check enrollment for. |
completion | JSONObjectCompletionHandler | A callback interface that handles the response. |
The JSONObjectCompletionHandler interface has a single method:
void onComplete(JSONObject result, ZSMError error);
Returns
The callback function returns the following parameters:
| Parameter Name | Data Type | Description |
|---|---|---|
result | JSONObject? | The retrieved enrollment data, if the user is enrolled. |
error | ZSMError? | Error details if enrollment retrieval fails. |
Enroll: UMFAClient.enroll()
The enroll method initiates the enrollment process for the Universal Multi-Factor Authentication (UMFA). This process binds the user's identity to the device, which is required for subsequent authentication operations.
Usage
client.enroll(userId, (response, error) -> {
if (response != null) {
// Handle successful enrollment, store or use the token
} else {
Log.e("UMFAClient", "Error during enrollment: " + (error != null ? error.getLocalizedMessage() : "Unknown"));
}
});
Parameters
| Parameter Name | Data Type | Description |
|---|---|---|
userId | String | The user ID to enroll. |
completion | JSONObjectCompletionHandler | A callback interface that handles the response. |
Returns
The callback function returns the following parameters:
| Parameter Name | Data Type | Description |
|---|---|---|
result | JSONObject? | The enrollment response containing the authentication token. |
error | ZSMError? | Error details if enrollment fails. |
Authenticate: UMFAClient.authenticate()
The authenticate method performs an authentication operation using the credentials stored on the device. If the credentials are not present, authentication will fail.
Usage
client.authenticate(userId, (response, error) -> {
if (response != null) {
// Handle successful authentication
} else {
Log.e("UMFAClient", "Error during authentication: " + (error != null ? error.getLocalizedMessage() : "Unknown"));
}
});
Parameters
| Parameter Name | Data Type | Description |
|---|---|---|
userId | String | The user ID to authenticate. |
completion | JSONObjectCompletionHandler | A callback interface that handles the response. |
Returns
The callback function returns the following parameters:
| Parameter Name | Data Type | Description |
|---|---|---|
result | JSONObject? | The authentication response containing the verified token. |
error | ZSMError? | Error details if authentication fails. |
Unenroll: UMFAClient.unenroll()
The unenroll method removes a specific user's UMFA credentials from the device.
Usage
client.unenroll(userId, error -> {
if (error == null) {
Log.d("UMFAClient", "Successfully unenrolled user");
} else {
Log.e("UMFAClient", "Error during unenrollment: " + error.getLocalizedMessage());
}
});
Parameters
| Parameter Name | Data Type | Description |
|---|---|---|
userId | String | The user ID to unenroll. |
completion | Function interface taking a ZSMError? | A callback function that handles the response. |
Returns
The callback function returns the following parameter:
| Parameter Name | Data Type | Description |
|---|---|---|
error | ZSMError? | Error details if unenrollment fails; null on success. |
Out-of-Band Token Validation
For out-of-band validation of the token returned by enroll() and authenticate(), use the /api/umfa/validate-token endpoint.
HTTP Method
POST
URL
$ZSM_AUTHENTICATOR_HOST/api/umfa/validate-token
Request Headers
| Header | Value | Description |
|---|---|---|
Content-Type | application/json | Indicates the payload format |
Authorization | Bearer XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX | Authorizes the API (API Key expected) |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
application_id | string | Yes | The unique identifier for the request's (server-to-server) application, parsed as a UUID. |
user_id | string | Yes | The unique identifier for the user. |
token | string | Yes | The token received from a previous UMFA authentication operation. |
token_type | string | No | An optional token type specifying the type of validation. Can be "credential" to validate a get() PublicKeyCredential. |
trace_id | string | No | An optional identifier for the validate-token operation. If a trace_id is not provided, then a random trace_id will be generated. |
Successful Response (HTTP 200)
{
"user_id": "janedoe@gmail.com",
"trace_id": "7a626fe9-ce25-4b87-8eb2-b12a7ee20143"
}
| Field | Type | Description |
|---|---|---|
user_id | string | The unique identifier for the user that was validated. |
trace_id | string | The trace identifier for the validate-token operation. |
Error Responses
{
"status": 400,
"trace_id": "7a626fe9-ce25-4b87-8eb2-b12a7ee20143",
"message": "Validate token failed with: MFA login JWT was invalid: Invalid JWT: There is no user_id claim"
}
| Field | Type | Description |
|---|---|---|
status | integer | The HTTP response code. |
trace_id | string | The trace identifier for the verification operation. |
message | string | Additional information about the validation failure. |
| Status Code | Description | Example Response |
|---|---|---|
400 Bad Request | Incorrectly formed request | { ... "message": "No data provided." } |
401 Unauthorized | Invalid or expired token | { ... "message": "Validate token failed with: MFA login JWT was invalid: Invalid JWT: There is no webauthn_time claim" } |
500 Internal Server Error | Server encountered an issue | { ... "message": "Server encountered an internal error" } |
Example cURL Commands
HTTP Success (200) JWT Validation
$ curl -s - X POST -H "Content-Type: application/json"
-H "Authorization: Bearer XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
-d '{"application_id": "bf468b21-308f-49d2-9031-83556e0781d2",
"user_id": "janedoe@gmail.com", "token": "eyJ0eX ... Nk9uWg"}'
$ZSM_AUTHENTICATOR_HOST/api/umfa/validate-token | jq
{
"user_id": "c7d7d44b-385e-4e83-bdd5-37e4fb3c8b7d",
"trace_id": "7a626fe9-ce25-4b87-8eb2-b12a7ee20143"
}
HTTP Success (200) Credential Validation
$ curl -s - X POST -H "Content-Type: application/json"
-H "Authorization: Bearer XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
-d '{"application_id": "bf468b21-308f-49d2-9031-83556e0781d2",
"user_id": "janedoe@gmail.com",
"token":
{
"id":"",
"rawId":"rF2kHiKUQCO0d0Y4Wek9kA",
"response":
{
"clientDataJSON":"eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiNWtMb2tjOXpkZzhuU2RFT2hzV1o5MUwzZTNGdjlqbERlRU9KcF93SnRkayIsIm9yaWdpbiI6Imh0dHBzOi8venNtLmFwcCJ9","authenticatorData":"ZxcNEwlh6TBKTTC5FMSFPTOboOZWzGeOSiYY7rm67WUFAAAAAQ","signature":"UOOoSBAwemLSPvqLVG2MDw41cqKLcHEUp4LAFGuvrVPsR1GWBYTWtmpqG_Jtjn-DXq5tGGAE58SYvu7uvcw7oHqquoNG4VEdm4Tz7UNe5kdSoc3RFpEGGDLCIz28iKXaBPbv3jdHi4xGoCIJKIIeHyh0-g7LUb4ZjYFIZHyXds7cdH9ozXRt5ERWUVvH1axDnPDKpntGQXG8FC4VXd0Rc01-4bBklNSGHOVgbO-Rpm8HgeFj3J4uOZDJ0xP7pnIkwOo5Uw_0ZO9xI66S8NQEtVzXVUKXs98f38LpLiLGEPlWtr_RIdf9xgsmHx-oVRJxC37gzV2ydSGKJaV6bNsXOw"},
"type":"public-key"
}
},
"token-type": "credential"}'
$ZSM_AUTHENTICATOR_HOST/api/umfa/validate-token | jq
{
"user_id": "c7d7d44b-385e-4e83-bdd5-37e4fb3c8b7d",
"trace_id": "7a626fe9-ce25-4b87-8eb2-b12a7ee20143"
}
Bad Request (400)
$ curl -s - X POST -H "Content-Type: application/json"
-H "Authorization: Bearer XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
-d '{"application_id": "bf468b21-308f-49d2-9031-83556e0781d2",
"user_id": "janedoe@gmail.com"}'
$ZSM_AUTHENTICATOR_HOST/api/umfa/validate-token | jq
{
"status": 400,
"trace_id": "7a626fe9-ce25-4b87-8eb2-b12a7ee20143",
"message": "Invalid data provided"
}
Unauthorized (401)
$ curl -s - X POST -H "Content-Type: application/json"
-H "Authorization: Bearer XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
-d '{"application_id": "bf468b21-308f-49d2-9031-83556e0781d2",
"user_id": "janedoe@gmail.com", "token": "eyJ0eX ... Nk9uWg"}'
$ZSM_AUTHENTICATOR_HOST/api/umfa/validate-token | jq
{
"status": 401,
"trace_id": "7a626fe9-ce25-4b87-8eb2-b12a7ee20143",
"message": "Validate token failed with: MFA login JWT was invalid: Invalid JWT: Invalid claim: The token has expired: 2024-12-10 18:41:03.0 +00:00:00"
}
Validate Token Failures
The server's token validation can fail for two general reasons:
- HTTP 400 Response: The request was malformed (i.e.,
tokenwas not included) - HTTP 401 Response: The token was invalid, which could have various causes
- Token's
user_iddid not match the supplieduser_id - Token has expired (the token's "exp" claim has passed)
- Token was missing required claims ("iss", "sub", "iat", "exp", "user_id", "webauthn_time")
- Token was not signed by the expected ZSM server's certificate
- Token was not a valid PublicKeyCredential when supplied
"token_type" = "credential"
- Token's
Decoded JWT
Below, we illustrate an example of a decoded UMFA JWT (Header and Payload).
The validation performs standard JWT validation like signature, liveness,
and structure. The validation also ensures that the payload claim user_id
matches that of the supplied user_id.
{
"typ": "JWT",
"alg": "RS256",
"iss": "Ideem::Authenticator"
}
{
"sub": "UMFA_login",
"iss": "Ideem::Authenticator",
"aud": [
"Ideem::Authenticator",
"Ideem::ZSM",
"Ideem::ZSM_CLI"
],
"iat": 1729280408,
"exp": 1729366808,
"jti": "042142c1-40c8-4d9b-bf5e-1fa84e0f3f03",
"user_id": "c7d7d44b-385e-4e83-bdd5-37e4fb3c8b7d",
"userpw_time": "2024-10-18T19:40:07.053364351+00:00",
"webauthn_time": "2024-10-18T19:40:08.053364351+00:00"
}