mDL Server-Side Verification
The mDL Data Server-Side Verification flow is similar to the Server-Side Verification used for the physical ID documents, but it applies to mDL.
Let's consider the process step by step.
- Preparation
- Step 1: mDL Reading via NFC
- Step 2: Finalize Package
- Step 3: Reprocessing on Web Service
- Step 4: Retrieve Processed Data
Preparation
Enable the backend processing feature on the Mobile side.
let backendProcessingConfig = RGLBackendProcessingConfig()
backendProcessingConfig.url = "https://api.regulaforensics.com"
DocReader.shared.processParams.backendProcessingConfig = backendProcessingConfig
RGLBackendProcessingConfig *backendProcessingConfig = [[RGLBackendProcessingConfig alloc] init];
backendProcessingConfig.serviceURL = @"https://api.regulaforensics.com";
RGLDocReader.shared.processParams.backendProcessingConfig = backendProcessingConfig;
DocumentReader.Instance().processParams().backendProcessingConfig = BackendProcessingConfig("https://api.regulaforensics.com")
DocumentReader.Instance().processParams().backendProcessingConfig = new BackendProcessingConfig("https://api.regulaforensics.com");
DocumentReader.instance.processParams.backendProcessingConfig = BackendProcessingConfig("https://api.regulaforensics.com");
DocumentReader.instance.processParams.backendProcessingConfig = new BackendProcessingConfig("https://api.regulaforensics.com")
// Android
DocumentReader.Instance().ProcessParams().BackendProcessingConfig = new BackendProcessingConfig("https://api.regulaforensics.com");
// iOS
RGLBackendProcessingConfig backendProcessingConfig = new()
{
Url = "https://api.regulaforensics.com"
};
RGLDocReader.Shared.ProcessParams.BackendProcessingConfig = backendProcessingConfig;
DocumentReader.setProcessParams({
backendProcessingConfig: {
url: "https://api.regulaforensics.com"
}
}, _ => { }, _ => { })
DocumentReader.setProcessParams({
backendProcessingConfig: {
url: "https://api.regulaforensics.com"
}
})
DocumentReader.setProcessParams({
backendProcessingConfig: {
url: "https://api.regulaforensics.com"
}
}, function (m) { }, function (e) { })
For mDL Server-Side Verification, you need to run the Regula Web Service in your environment. Refer to the Web Service section for instructions on how to do that.
HTTP Headers
Since Regula Web Service is engaged when working with Regula Mobile SDK, you may need to adjust HTTP requests’ headers in your application to pass additional information to the Web Service. That can be achieved in the following way:
let backendProcessingConfig = RGLBackendProcessingConfig()
backendProcessingConfig.url = "https://api.regulaforensics.com"
backendProcessingConfig.httpHeaders = ["HttpHeader1": "value1", "HttpHeader2": "value2"]
DocReader.shared.processParams.backendProcessingConfig = backendProcessingConfig
RGLBackendProcessingConfig *backendProcessingConfig = [[RGLBackendProcessingConfig alloc] init];
backendProcessingConfig.serviceURL = @"https://api.regulaforensics.com";
backendProcessingConfig.httpHeaders = @{@"HttpHeader1": @"value1", @"HttpHeader2": @"value2"};
RGLDocReader.shared.processParams.backendProcessingConfig = backendProcessingConfig;
val httpHeaders: MutableMap<String, String> = HashMap()
httpHeaders["header1"] = "key1"
httpHeaders["header2"] = "key2"
val backendProcessingConfig = BackendProcessingConfig("https://api.regulaforensics.com")
backendProcessingConfig.httpHeaders = httpHeaders
DocumentReader.Instance().processParams().backendProcessingConfig = backendProcessingConfig
Map<String, String> httpHeaders = new HashMap<>();
httpHeaders.put("header1", "key1");
httpHeaders.put("header2", "key2");
BackendProcessingConfig backendProcessingConfig = new BackendProcessingConfig("https://api.regulaforensics.com");
backendProcessingConfig.setHttpHeaders(httpHeaders);
DocumentReader.Instance().processParams().backendProcessingConfig = backendProcessingConfig;
Map<String, String> httpHeaders = {};
httpHeaders["header1"] = "key1";
httpHeaders["header2"] = "key2";
BackendProcessingConfig backendProcessingConfig = BackendProcessingConfig(
"https://api.regulaforensics.com",
httpHeaders: httpHeaders
);
DocumentReader.instance.processParams.backendProcessingConfig = backendProcessingConfig;
const httpHeaders = { header1: "key1", header2: "key2" }
var backendProcessingConfig = new BackendProcessingConfig("https://api.regulaforensics.com", { httpHeaders: httpHeaders })
DocumentReader.instance.processParams.backendProcessingConfig = backendProcessingConfig
/// Android
var httpHeaders = new Dictionary<string, string>
{
["header1"] = "key1",
["header2"] = "key2"
};
var backendProcessingConfig = new BackendProcessingConfig("https://api.regulaforensics.com")
{
HttpHeaders = httpHeaders
};
DocumentReader.Instance().ProcessParams().BackendProcessingConfig = backendProcessingConfig;
// iOS
var httpHeaders = new NSMutableDictionary
{
["header1"] = new NSString("key1"),
["header2"] = new NSString("key1")
};
RGLBackendProcessingConfig backendProcessingConfig = new()
{
Url = "https://api.regulaforensics.com",
HttpHeaders = httpHeaders
};
RGLDocReader.Shared.ProcessParams.BackendProcessingConfig = backendProcessingConfig;
const httpHeaders = {
header1: 'key1',
header2: 'key2',
};
DocumentReader.setProcessParams({
backendProcessingConfig: {
url: "https://api.regulaforensics.com",
httpHeaders: httpHeaders
}
}, _ => { }, _ => { })
const httpHeaders: Record<string, string> = {
header1: 'key1',
header2: 'key2',
};
DocumentReader.setProcessParams({
backendProcessingConfig: {
url: "https://api.regulaforensics.com",
httpHeaders: httpHeaders
}
})
const httpHeaders = {
header1: 'key1',
header2: 'key2',
};
DocumentReader.setProcessParams({
backendProcessingConfig: {
url: "https://api.regulaforensics.com",
httpHeaders: httpHeaders
}
}, function (m) { }, function (e) { })
Step 1: mDL Reading
The first step is the mDL reading, performed on the mobile side.
To start the processing, follow the mDL Processing guide.
While reading is performed on the mobile via NFC or Bluetooth, Regula Web Service becomes engaged in generating session keys and challenges, which are subsequently saved to the Storage and Database.
For complete details about the backend configuration, see the Web Service Complete Server-Side Verification page.
Step 2: Finalize Package
The next step is to finalize results. It means that they are encrypted on the mobile side and then are transmitted to the Regula Web Service via the secure communication channel.
During transmission, Storage and Database become engaged in the saving transaction info, metadata, results and so on.
Once the package is sent to the Regula Web Service, the corresponding transaction ID is returned in the callback. See the following examples.
DocReader.shared.finalizePackage { action, transactionInfo, error in
if error != nil {
guard let error = error else {
return
}
print("Finalize failed. Error: \(error)")
} else {
if action == .complete, let transactionId = transactionInfo?.transactionId {
print("Finalize done. Transaction ID: \(transactionId)")
}
}
}
[[RGLDocReader shared] finalizePackageWithCompletion:^(RGLDocReaderAction action, RGLTransactionInfo * _Nullable info, NSError * _Nullable error) {
if (error != nil) {
NSLog(@"Finalize failed. Error: %@", error);
} else {
if (action == RGLDocReaderActionComplete) {
NSLog(@"Finalize done. Transaction ID: %@", info.transactionId);
}
}
}];
DocumentReader.Instance().finalizePackage(IDocumentReaderFinalizePackage { action, transactionInfo, error ->
error?.let {
Log.d("Activity", "Finalize failed. Error: " + error.message)
return@IDocumentReaderFinalizePackage
}
transactionInfo?.let {
if (action == DocReaderAction.COMPLETE) {
Log.d("Activity", "Finalize done. Transaction ID: " + transactionInfo.transactionId)
}
}
})
DocumentReader.Instance().finalizePackage(new IDocumentReaderFinalizePackage() {
@Override
public void onFinalizePackage(int action, @Nullable TransactionInfo transactionInfo, @Nullable DocumentReaderException error) {
if (error != null) {
Log.d("Activity","Finalize failed. Error: " + error.getMessage());
return;
}
if (action == DocReaderAction.COMPLETE && transactionInfo != null) {
Log.d("Activity", "Finalize done. Transaction ID: " + transactionInfo.transactionId);
}
}
});
var (action, info, error) = await DocumentReader.instance.finalizePackage();
if (error != null) {
print("Finalize failed. Error: " + error.message);
} else if (action == DocReaderAction.COMPLETE && info != null) {
print("Finalize done. Transaction ID: " + info.transactionId!);
}
var [action, info, error] = await DocumentReader.instance.finalizePackage()
if (error) {
console.log("Finalize failed. Error: " + error.message)
} else if (action == DocReaderAction.COMPLETE && info) {
console.log("Finalize done. Transaction ID: " + info.transactionId)
}
// Android
DocumentReader.Instance().FinalizePackage(this);
public void OnFinalizePackage(int action, TransactionInfo info, DocumentReaderException error)
{
if (error != null)
{
Console.WriteLine("Finalize failed. Error: " + error.Message);
return;
}
if (action == DocReaderAction.Complete && info != null)
{
Console.WriteLine("Finalize done. Transaction ID: " + info.TransactionId);
}
}
// iOS
RGLDocReader.Shared.FinalizePackageWithCompletion((action, info, error) => {
if (error != null)
Console.WriteLine("Finalize failed. Error: " + error.Description);
else if (action == RGLDocReaderAction.Complete)
Console.WriteLine("Finalize done. Transaction ID: " + info.TransactionId);
});
DocumentReader.finalizePackage(response => {
response = JSON.parse(response)
if (response["error"] != null) {
console.log("Finalize failed. Error: " + response["error"])
} else if (response["action"] == DocReaderAction.COMPLETE && response["info"] != null) {
console.log(("Finalize done. Transaction ID: " + response["info"]))
}
}, _ => { })
DocumentReader.finalizePackage().then(response => {
response = JSON.parse(response)
if (response["error"] != null) {
console.log("Finalize failed. Error: " + response["error"])
} else if (response["action"] == DocReaderAction.COMPLETE && response["info"] != null) {
console.log(("Finalize done. Transaction ID: " + response["info"]))
}
})
DocumentReader.finalizePackage(function (response) {
response = JSON.parse(response)
if (response["error"] != null) {
console.log("Finalize failed. Error: " + response["error"])
} else if (response["action"] == DocReaderAction.COMPLETE && response["info"] != null) {
console.log(("Finalize done. Transaction ID: " + response["info"]))
}
}, function (e) { })
Send this transaction ID to your backend to prepare the request that will be sent to the Regula Web Service for reprocessing later.
Step 3: Reprocessing on Web Service
Now that you have the encrypted results, you can start making up the request to do reprocessing on Regula Web Service.
The request body should include at least the mDL processing scenario and other settings depending on your needs:
{
"processParam": {
"scenario": "mDL"
}
}
Send the request to Regula Web Service to the following endpoint:
POST /api/v2/transaction/{transaction_id}/process
where {transaction_id} is what to get in the Step 2.
Request example using cURL
curl --request POST \
--url "http://localhost:8088/api/v2/transaction/76fa69d1-5ba6-4aa0-8dd5-477c8f81df91/process" \
--header "Content-Type: application/json" \
--data '{ "processParam": { "scenario": "mDL" } }'
Info
Note that the request demonstrated above doesn't contain any data, so you won't receive any results from the Regula Web Service if you run it.
The request demonstrates only the structure that should be followed.
Regula Web Service fetches raw data from the Database and Storage, processes it and then saves the reprocessed results back. This step may be time-consuming, so the results of the document's reprocessing are not returned in the same HTTP response. For getting the processed data, follow the next Step 4.
Step 4: Retrieve Processed Data
After the data has been processed on the Regula Web Service side and saved to the Database and Storage, you can retrieve the results.
Send the request to Regula Web Service to the following endpoint:
GET /api/v2/transaction/{transactionId}/results
where {transaction_id} is what to get in the Step 2 and what has been used in the reprocessing request, see the Step 3.
Request example using cURL
curl --request GET \
--url "http://localhost:8088/api/v2/transaction/76fa69d1-5ba6-4aa0-8dd5-477c8f81df91/results" \
--header "Content-Type: application/json"
This marks the final step of the mDL Server-Side Verification. Once the server-side reprocessing is completed, you can then handle the results appropriately and determine whether you should trust the mobile outcome or not.
Examples
See the sample projects, demonstrating how to set up the Complete Server-Side Verification on the Mobile side: