Web API

Access the BioID Web Service with RESTful Web API

For a simplified access to the BWS we provide a HTTP based RESTful Web API (also called the BWS Extension). This web API is accessible via standard HTTP methods by a variety of HTTP clients including browsers and mobile devices.

In addition to the web API a unified user interface is provided, where the developers can redirect their users to perform various biometric tasks. This user interface is carried out as an application of the BWS Web API and even provides source code with documentation and a jQuery module that developers can use in their own user interface implementation.

Before you begin

You need to have access to an existing BWS installation. If you don't have this access, you can register for a trial instance. For this you need a BioID account with a confirmed email address.

To use the BWS Web API you need to have at least one BWS client application registered. You register client applications in the BWS Portal.

For calling BWS you need to create a Web API key within your client configuration and use the App ID and Secret for authentication.

Please go to the BioID Helpdesk or contact our support for questions.

BWS Web API base URI

The base URI of the BWS Web API is the combination of the URL of the BWS installation for which your BWS client is registered followed by the extension resource name. To this base URI you simply have to add the name of the web API you want to access. With a trial instance for example, your client is running on the BWS multitenant installation and the BWS Web API base URI is https://bws.bioid.com/extension

Authentication & API workflow overview

When designing your implementation, two different authentication workflows must be considered: Either, you need to do HTTP basic authentication if calling the BioID Web Service from your own servers, or you need to use BWS Token Authentication if calling BWS from a client directly.

HTTP Basic Authentication: You have to provide an HTTP authorization header using the authorization method Basic and the base64 encoded string App-ID:App-Secret (therefore the transport is secured using TLS/SSL). To receive the necessary BWS WebAPI access data (App-ID and App-Secret) you have to register your application on the BWS Portal first. This requires a valid BWS subscription. HTTP Basic Authentication can be used with the PhotoVerify API as well as the LiveDetection API for instance.

BWS Token Authentication: You have to provide an HTTP authorization header using the authorization method Bearer (for compatibility issues you can also use the JWT identifier) and a previously issued BWS token, which can be requested using the Token Web API. To carry out APIs with BWS Token Authentication, you need the associated user’s BCID. BWS Token authentication is required for most APIs like Enroll API, Verify API, Identify API, LivenessDetection API and so on.

CORS: Requesting a BWS token from the browser side is not allowed. You will receive the error 'CORS is blocked'. Only API calls with BWS token authentication (i.e. Enroll API, Verify API, Identify API, LivenessDetection API ) allow CORS. API calls which require basic authentication (like Token or PhotoVerify) do not allow CORS. This means that each API call which doesn't allow CORS must come from a confidential app (e.g. web server).




There are two different APIs for liveness detection (presentation attack detection) which differ in upload and authentication but not in quality and functionality. Depending on your workflow, please use the adequate one:

  • The LivenessDetection API will send images asynchronously as soon as they have been taken. The images will be analysed on the server as soon as all required images have been uploaded. Thus it needs a BWS Token Authentication.
  • The LiveDetection API will first capture all images and then send them synchronously. The LiveDetection API therefore requires HTTP Basic Authentication.

Example use cases and associated APIs

Use Case

APIs

Web API Authentication

BCID

Biometric verification of ID ownership - KYC

PhotoVerify

Basic HTTP authentication

No BCID required

User presence check

LiveDetection

Basic HTTP authentication

No BCID required

Onboarding with biometrics

Token, Upload, Enroll

BioID Token authentication

BCID required

Login/Authentication 

Token, Upload, Verify

BioID Token authentication

BCID required

Walkthrough

We encourage you to use the BWS Web API Demo which supports you with experimenting the workflow. Also, you can test your access to the BWS trial instance.

In addition, BioID provides sample code to test all Web API calls to the BioID Web Service. All API calls are explained and executed with sample images, e.g. images from a live person as well as recordings (fakes). Please follow the instructions below to have a first look at the API.

First install .NET Core SDK (2.2) on your machine to compile. 

Then open a terminal, initialize the .NET Core environment and copy the two file from below into the test folder.

mkdir TestBWSWebApi
cd TestBWSWebApi
dotnet new console
dotnet add package Newtonsoft.Json
// Edit Program.cs and copy the sample code below or simply download the Program.cs and overwrite the existing one.
// Download the TestImages.cs and copy to the Program.cs location.
// Fill out the required configuration data.
dotnet run

You have to edit the file Program.cs to insert some parameters specific to your trial instance before you can run the script!

Downloads:

Program.cs

TestImages.cs

Below is the content of the file Program.cs:

TestBWSWebApi
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Specialized;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace BioID.BWSWebApi.Demo
{
    /// <summary>
    /// If you do not have access to a BWS instance yet, you can request a
    /// <a href="https://bwsportal.bioid.com/register"> BWS trial instance here (requires login)</a>.
    /// With your account you can then create and manage BWS applications and secrets in the
    /// <a href="https://bwsportal.bioid.com/"> BWS Portal (requires login)</a>.
    /// </summary>
    class Program
    {
        #region BWS Client Configuration

        /// <summary>
        /// Use your provided endpoint here.
        /// You can find this information in our BWS Portal - Configuration.
        /// </summary>
        const string ENDPOINT = "https://bws.bioid.com/extension/";

        /// <summary>
        /// You need to have created an app in our BWS Portal to get the identifier.
        /// You can find this information in our BWS Portal - Configuration.
        /// </summary>
        /// <remarks>YOU NEED TO PUT YOUR INFO HERE!</remarks>
        const string APP_IDENTIFIER = "your-BWS-appID";

        /// <summary>
        /// You need to have created an app in our BWS portal to get the app secret.
        /// You can find this information in our BWS Portal - Configuration.
        /// </summary>
        /// <remarks>YOU NEED TO PUT YOUR INFO HERE!</remarks>
        const string APP_SECRET = "your-BWS-appSecret";

        /// <summary>
        /// Use your provided storage here. 
        /// You can find this information in our BWS Portal - Configuration.
        /// </summary>
        /// <remarks>YOU NEED TO PUT YOUR INFO HERE!</remarks>
        const string STORAGE = "bioid";

        /// <summary>
        /// Use your provided partition here.
        /// You can find this information in our BWS Portal - Configuration.
        /// </summary>
        /// <remarks>YOU NEED TO PUT YOUR INFO HERE!</remarks>
        const int PARTITION = 0;

        /// <summary>
        /// This integer value is finally the ID of the class, which clearly defines a user within a Storage and Partition. 
        /// </summary>
        /// <remarks>
        /// This value is defined by yourself!
        /// </remarks>
        static int classId = 1;

        #endregion

        #region Sample Images

        /// The data-URL using the data URI scheme - data:[<media type>][;base64],<data>
        
        /// <summary>
        /// This is a fake image (printed image)! 
        /// </summary>
        public static string dataUrlFakeImage1 = TestImages.DataUrlFakeImage1;

        /// <summary>
        /// This is a fake image (printed image)! 
        /// </summary>
        public static string dataUrlFakeImage2 = TestImages.DataUrlFakeImage2;
        
        /// <summary>
        /// This image was recorded from a live person.
        /// </summary>
        public static string dataUrlLiveImage1 = TestImages.DtaUrlLiveImage1;
        
        /// <summary>
        /// This image was recorded from a live person.
        /// </summary>
        public static string dataUrlLiveImage2 = TestImages.DataUrlLiveImage2;
        
        /// <summary>
        /// This image contains the ID Photo.
        /// </summary>
        public static string dataUrlIdPhotoImage = TestImages.DataUrlIdPhotoImage;
       
        /// <summary>
        /// This image is in high resolution.
        /// </summary>
        static string dataUrlHighResImage = TestImages.DataUrlHighResImage;
        
        /// <summary>
        /// This image contains multiple faces.
        /// </summary>
        static string dataUrlMultipleFacesImage = TestImages.DataUrlMultipleFacesImage;

        /// <summary>
        /// This image contains no suitable face (only half of the face is displayed).
        /// </summary>
        public static string dataUrlNoSuitableFaceImage = TestImages.DataUrlNoSuitableFaceImage;

        #endregion

        /// <summary>
        /// The traits that shall be used for the biometric operation.
        /// </summary>
        public enum Trait { Face, Periocular };

        /// <summary>
        /// Specifies the task the issued token shall be used for.
        /// </summary>
        public enum TokenFor { enroll, verify, identify, livenessdetection };


        static async Task Main(string[] args)
        {
            var arguments = new Arguments(args);
            if (arguments["help"] != null || arguments["h"] != null)
            {
                Usage();
                return;
            }

            try
            {
                string filePath = string.Empty;
                if (arguments["live1"] != null)
                {
                    filePath = arguments["live1"];
                    dataUrlLiveImage1 = await ConvertToDataUrlImageAsync(filePath);
                }
                if (arguments["live2"] != null)
                {
                    filePath = arguments["live2"];
                    dataUrlLiveImage2 = await ConvertToDataUrlImageAsync(filePath);
                }
                if (arguments["fake1"] != null)
                {
                    filePath = arguments["fake1"];
                    dataUrlFakeImage1 = await ConvertToDataUrlImageAsync(filePath);
                }
                if (arguments["fake2"] != null)
                {
                    filePath = arguments["fake2"];
                    dataUrlFakeImage2 = await ConvertToDataUrlImageAsync(filePath);
                }
                if (arguments["id"] != null)
                {
                    filePath = arguments["id"];
                    dataUrlIdPhotoImage = await ConvertToDataUrlImageAsync(filePath);
                }
                if (arguments["highRes"] != null)
                {
                    filePath = arguments["highRes"];
                    dataUrlHighResImage = await ConvertToDataUrlImageAsync(filePath);
                }
                if (arguments["noFace"] != null)
                {
                    filePath = arguments["noFace"];
                    dataUrlNoSuitableFaceImage = await ConvertToDataUrlImageAsync(filePath);
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("Could not parse/load arguments:");
                Console.WriteLine(e.Message);
                Usage();
                return;
            }

            string bwsToken;
            string bcid = STORAGE + "." + PARTITION + "." + classId;
            bool accepted, success, isLive = false;


            // Test PhotoVerify
            bool match = await PhotoVerifyAsync(4, dataUrlLiveImage1, dataUrlLiveImage2, dataUrlIdPhotoImage);

            // Test liveness detection on two images
            isLive = await LiveDetectionAsync(dataUrlLiveImage1, dataUrlLiveImage2);

            // Test QualityCheck
            string qualityCheckResult = await QualityCheckAsync(true, "ICAO", dataUrlHighResImage);


            // Test Enrollment
            Console.WriteLine("\n\nTest enrollment");
            // Get token
            bwsToken = await TokenAsync(bcid, TokenFor.enroll);
            // Upload images
            accepted = await UploadAsync(bwsToken, dataUrlLiveImage1);
            accepted &= await UploadAsync(bwsToken, dataUrlLiveImage2);
            // Biometric task - Enroll
            if (accepted) { success = await EnrollAsync(bwsToken); }


            // Test Verification
            Console.WriteLine("\n\nTest verification");
            // Get token
            bwsToken = await TokenAsync(bcid, TokenFor.verify);
            // Upload images
            accepted = await UploadAsync(bwsToken, dataUrlLiveImage1);
            accepted &= await UploadAsync(bwsToken, dataUrlLiveImage2);
            // Biometric task - Verify
            if (accepted) {  success = await VerifyAsync(bwsToken); }


            // Test Identification
            Console.WriteLine("\n\nTest identification");
            // Get token
            bwsToken = await TokenAsync(bcid, TokenFor.identify);
            // Upload images
            accepted = await UploadAsync(bwsToken, dataUrlLiveImage1);
            accepted &= await UploadAsync(bwsToken, dataUrlLiveImage2);
            // Biometric task - Identify
            if (accepted) { success = await IdentifyAsync(bwsToken); }


            // Test upload with multiple faces.
            Console.WriteLine("\n\nTest with multiple faces...");
            // Get token
            bwsToken = await TokenAsync(bcid, TokenFor.livenessdetection);
            // Upload image
            accepted = await UploadAsync(bwsToken, dataUrlMultipleFacesImage);


            // Test upload with no suitable face.
            Console.WriteLine("\n\nTest with no suitable face...");
            // Get token
            bwsToken = await TokenAsync(bcid, TokenFor.livenessdetection);
            // Upload image
            accepted = await UploadAsync(bwsToken, dataUrlNoSuitableFaceImage);


            // Test Liveness Detection with live images.
            Console.WriteLine("\n\nTest with live images...");
            // Get token
            bwsToken = await TokenAsync(bcid, TokenFor.livenessdetection);
            // Upload images
            accepted = await UploadAsync(bwsToken, dataUrlLiveImage1);
            accepted &= await UploadAsync(bwsToken, dataUrlLiveImage2);
            // Biometric task - LivenessDetection
            if (accepted) { isLive = await LivenessDetectionAsync(bwsToken); }


            // Test Liveness Detection with fake images.
            Console.WriteLine("\n\nTest with fake images...");
            // Get token
            bwsToken = await TokenAsync(bcid, TokenFor.livenessdetection);
            // Upload images
            accepted = await UploadAsync(bwsToken, dataUrlFakeImage1);
            accepted &= await UploadAsync(bwsToken, dataUrlFakeImage2);
            // Biometric task - LivenessDetection should fail!
            if (accepted) { isLive = await LivenessDetectionAsync(bwsToken); }


            // Fetches the result of the last biometric operation
            Console.WriteLine("\n\nTest fetch last result");
            string result = await ResultAsync(bwsToken);

            // Find out whether a user is already enrolled for a specific trait.
            Console.WriteLine("\nTest is enrolled");
            bool isEnrolled = await IsEnrolledAsync(bcid, Trait.Face);

            // Deletes all biometric data associated with a Biometric Class ID(bcid)from the system.
            Console.WriteLine("\nTest delete class");
            bool isDeleted = await DeleteClassAsync(bcid);

            // Find out whether a user is already enrolled for a specific trait.
            Console.WriteLine("\nTest is enrolled");
            isEnrolled = await IsEnrolledAsync(bcid, Trait.Face);

            // Requests status information from a BWS installation
            Console.WriteLine("\nTest get BWS status");
            string status = await BWSStatusAsync();


            Console.WriteLine("Press any key to stop...");
            Console.ReadKey();
        }

        #region Biometric tasks without associated user (BCID)

        /// <summary>
        /// Performs a liveness detection on the uploaded samples to verify whether they are recorded from a live person. 
        /// Then performs a one-to-one comparison with the ID photo submitted in 
        /// order to verify whether the live images and ID photo belong to the same person.
        /// </summary>
        /// <param name="accuracy">The desired accuracy level</param>
        /// <param name="dataUrlLiveImage1">The first image recorded from a live person.</param>
        /// <param name="dataUrlLiveImage2">The second image recorded form a live person.</param>
        /// <param name="dataUrlIdPhoto">The ID photo of the recorded live person.</param>
        /// <returns>The live images match the ID photo or not with regard to the applied accuracy level.</returns>
        private static async Task<bool> PhotoVerifyAsync(int accuracy, string dataUrlLiveImage1, string dataUrlLiveImage2, string dataUrlIdPhoto)
        {
            using (var client = new HttpClient())
            {
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes($"{APP_IDENTIFIER}:{APP_SECRET}")));

                string mediaType, images;
                
                // using the application/json media type
                mediaType = "application/json";
                images = $@"{{""liveimage1"":""{dataUrlLiveImage1}"""
                      + $@",""liveimage2"":""{dataUrlLiveImage2}"""
                      + $@",""idphoto"":""{dataUrlIdPhoto}""}}";


                // or using application/x-www-form-urlencoded
                /*
                mediaType = "application/x-www-form-urlencoded";
                images = string.Format("liveimage1={0}&liveimage2={1}&idphoto={2}", HttpUtility.UrlEncode(dataUrlLiveImage1), HttpUtility.UrlEncode(dataUrlLiveImage2), HttpUtility.UrlEncode(dataUrlIdPhoto));
                */

                using (var content = new StringContent(images, Encoding.ASCII, mediaType))         
                using (var response = await client.PostAsync(ENDPOINT + $"photoverify?accuracy={accuracy}", content))
                {
                    Console.Write("PhotoVerify Response... ");
                    string result = await response.Content.ReadAsStringAsync();
                    if (response.StatusCode == HttpStatusCode.OK)
                    {
                        if (bool.TryParse(result, out var match))
                        {
                            Console.WriteLine(match);
                            return match;
                        }
                    }

                    Console.WriteLine(response.StatusCode.ToString());
                    Console.WriteLine(result);
                    return false;
                }
            }
        }

        /// <summary>
        /// Performs a face liveness detection on two images.
        /// </summary>
        /// <param name="dataUrlLiveImage1">The first image recorded from a live person.</param>
        /// <param name="dataUrlLiveImage2">The second image recorded form a live person.</param>
        /// <returns>Is recorded from a live person or not.</returns>
        private static async Task<bool> LiveDetectionAsync(string dataUrlLiveImage1, string dataUrlLiveImage2)
        {
            using (var client = new HttpClient())
            {
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes($"{APP_IDENTIFIER}:{APP_SECRET}")));

                string mediaType, images;

                // using the application/json media type
                mediaType = "application/json";
                images = $@"{{""liveimage1"":""{dataUrlLiveImage1}"""
                       + $@",""liveimage2"":""{dataUrlLiveImage2}""}}";

                // or using application/x-www-form-urlencoded
                /*
                mediaType = "application/x-www-form-urlencoded";
                images = string.Format("liveimage1={0}&liveimage2={1}", HttpUtility.UrlEncode(dataUrlLiveImage1), HttpUtility.UrlEncode(dataUrlLiveImage2));
                */

                using (var content = new StringContent(images, Encoding.UTF8, mediaType))
                using (var response = await client.PostAsync(ENDPOINT + "livedetection", content))
                {
                    Console.Write("LiveDetection Response... ");
                    string result = await response.Content.ReadAsStringAsync();
                    if (response.StatusCode == HttpStatusCode.OK)
                    {
                        if (bool.TryParse(result, out var isLive))
                        {
                            Console.WriteLine(isLive);
                            return isLive;
                        }
                    }

                    Console.WriteLine(response.StatusCode.ToString());
                    Console.WriteLine(result);
                    return false;
                }
            }
        }

        /// <summary>
        /// Performs a rigorous quality check according to ICAO (International Civil Aviation Organization) requirements 
        /// for machine readable travel documents (MRTDs).
        /// </summary>
        /// <param name="full">Full document mode otherwise token data mode is used.</param>
        /// <param name="issuer">Document-issuer specific settings.</param>
        /// <param name="dataUrlImage">The image for the quality check.</param>
        /// <returns>
        /// Returns a QualityCheckResult object, which informs about the Success of the check and 
        /// lists Errors that occurred during the check.
        /// </returns>
        private static async Task<string> QualityCheckAsync(bool full, string issuer, string dataUrlImage)
        {
            using (var client = new HttpClient())
            {
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes($"{APP_IDENTIFIER}:{APP_SECRET}")));
                using (var content = new StringContent(dataUrlImage))
                using (var response = await client.PostAsync(ENDPOINT + $"qualitycheck?full={full}&issuer={issuer}", content))
                {
                    Console.Write("QualityCheck Response... ");
                    if (response.StatusCode == HttpStatusCode.OK)
                    {
                        string result = await response.Content.ReadAsStringAsync();
                        var json = JObject.Parse(result);
                        bool success = (bool)json["Success"];

                        var errors = json["Errors"];
                        var eyeCenters = json["EyeCenters"];
                        string base64ProcessSample = (string)json["ProcessedSample"];

                        Console.WriteLine(success);
                        return json.ToString();
                    }

                    Console.WriteLine(response.StatusCode.ToString());
                    return string.Empty;
                }
            }
        }

        #endregion

        #region Basic biometric tasks for Enroll, Verify, Identify associated with a user (BCID) and pure Liveness Detection 

        /// <summary>
        /// Get a BWS token to be used for authorization.
        /// </summary>
        /// <param name="bcid">The Biometric Class ID (BCID) of the person.</param>
        /// <param name="forTask">The task the issued token shall be used for.</param>
        /// <returns>A string containing the issued BWS token.</returns>
        private static async Task<string> TokenAsync(string bcid, TokenFor forTask = TokenFor.verify)
        {
            using (var client = new HttpClient())
            {
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes($"{APP_IDENTIFIER}:{APP_SECRET}")));
                using (var response = await client.GetAsync(ENDPOINT + $"token?id={APP_IDENTIFIER}&bcid={bcid}&task={forTask}"))
                {
                    Console.Write("Get BWS token for " + forTask + "... ");
                    if (response.StatusCode == HttpStatusCode.OK)
                    {
                        Console.WriteLine("succeeded");
                        return await response.Content.ReadAsStringAsync();
                    }
                 
                    Console.WriteLine(response.StatusCode.ToString());
                    return string.Empty;
                }
            }
        }

        /// <summary>
        /// Asynchronous upload for the images that are associated with a token and can later be used 
        /// for various biometric operations.
        /// </summary>
        /// <param name="bwsToken">The previously issued BWS token.</param>
        /// <param name="dataUrlImage">The image for the upload.</param>
        /// <returns>The image has passed the quality-check or not.</returns>
        private static async Task<bool> UploadAsync(string bwsToken, string dataUrlImage)
        {
            using (var client = new HttpClient())
            {
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", bwsToken);
                using (var content = new StringContent(dataUrlImage))
                using (var response = await client.PostAsync(ENDPOINT + $"upload", content))
                {
                    Console.Write("Uploading image... ");
                    if (response.StatusCode == HttpStatusCode.OK)
                    {
                        Console.WriteLine("succeeded");
                        string result = await response.Content.ReadAsStringAsync();
                        var json = JObject.Parse(result);
                        bool accepted = (bool)json["Accepted"];
                        string error = (string)json["Error"];
                        if (!string.IsNullOrEmpty(error)) { Console.WriteLine(error);  }
                        var warnings = json["Warnings"];
                        return accepted;
                    }

                    Console.WriteLine(response.StatusCode.ToString());
                    return false;
                }
            }
        }

        /// <summary>
        /// Performs a biometric enrollment (or training) of the user with the uploaded images 
        /// that are associated with the token provided for authorization.
        /// </summary>
        /// <param name="bwsToken">The previously issued BWS token.</param>
        /// <returns>The enrollment succeeded or not.</returns>
        private static async Task<bool> EnrollAsync(string bwsToken)
        {
            using (var client = new HttpClient())
            {
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", bwsToken);
                using (var response = await client.GetAsync(ENDPOINT + $"enroll"))
                {
                    Console.Write("Enrollment response... ");
                    if (response.StatusCode == HttpStatusCode.OK)
                    {
                        string result = await response.Content.ReadAsStringAsync();
                        var json = JObject.Parse(result);
                        bool success = (bool)json["Success"];
                        Console.Write("Success: " + success);

                        if (!success)
                        {
                            // read out the error
                            string error = (string)json["Error"];
                            Console.WriteLine(" - Error: " + error);
                        }
                        return success;
                    }

                    Console.WriteLine(response.StatusCode.ToString());
                    return false;
                }
            }
        }

        /// <summary>
        /// Performs a one-to-one comparison of the uploaded samples with a stored biometric template in 
        /// order to verify whether the individual is the person he or she claims to be.
        /// </summary>
        /// <param name="bwsToken">The previously issued BWS token.</param>
        /// <returns>The verification succeeded or not.</returns>
        private static async Task<bool> VerifyAsync(string bwsToken)
        {
            using (var client = new HttpClient())
            {
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", bwsToken);
                using (var response = await client.GetAsync(ENDPOINT + $"verify"))
                {
                    Console.Write("Verification response... ");
                    if (response.StatusCode == HttpStatusCode.OK)
                    {
                        string result = await response.Content.ReadAsStringAsync();
                        var json = JObject.Parse(result);
                        bool success = (bool)json["Success"];
                        Console.Write("Success: " + success);

                        if (!success)
                        {
                            // read out the error
                            string error = (string)json["Error"];
                            Console.WriteLine(" - Error: " + error);
                        }
                        return success;
                    }

                    Console.WriteLine(response.StatusCode.ToString());
                    return false;
                }
            }   
        }

        /// <summary>
        /// Performs a one-to-many comparison of the uploaded samples with stored biometric templates in order to 
        /// identify the individuals that are most likely represented by the given samples.
        /// </summary>
        /// <param name="bwsToken">The previously issued BWS token.</param>
        /// <returns>The identification could be performed or not.</returns>
        private static async Task<bool> IdentifyAsync(string bwsToken)
        {
            using (var client = new HttpClient())
            {
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", bwsToken);
                using (var response = await client.GetAsync(ENDPOINT + $"identify"))
                {
                    Console.Write("Identification response... ");
                    if (response.StatusCode == HttpStatusCode.OK)
                    {
                        string result = await response.Content.ReadAsStringAsync();
                        var json = JObject.Parse(result);
                        bool success = (bool)json["Success"];
                        Console.Write("Success: " + success);

                        if (!success)
                        {
                            // read out the error
                            string error = (string)json["Error"];
                            Console.WriteLine(" - Error: " + error);
                        }
                        return success;
                    }
               
                    Console.WriteLine(response.StatusCode.ToString());
                    return false;
                }
            }
        }

        /// <summary>
        /// Performs a liveness detection on the previously uploaded samples that are associated 
        /// with the token provided for authorization.
        /// </summary>
        /// <param name="bwsToken">The previously issued BWS token.</param>
        /// <returns>The liveness detection succeeded or not.</returns>
        private static async Task<bool> LivenessDetectionAsync(string bwsToken)
        {
            using (var client = new HttpClient())
            {
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", bwsToken);
                using (var response = await client.GetAsync(ENDPOINT + $"livenessdetection"))
                {
                    Console.Write("LivenessDetection response... ");
                    if (response.StatusCode == HttpStatusCode.OK)
                    {
                        string result = await response.Content.ReadAsStringAsync();
                        var json = JObject.Parse(result);
                        bool success = (bool)json["Success"];
                        Console.Write("Success: " + success);

                        if (!success)
                        {
                            // read out the error
                            string error = (string)json["Error"];
                            Console.WriteLine(" - Error: " + error);
                        }
                        return success;
                    }
     
                    Console.WriteLine(response.StatusCode.ToString());
                    return false;
                }
            }
        }

        #endregion

        #region User management (BCID) and BWS status and results of a biometric operation

        /// <summary>
        /// Find out whether a user is already enrolled for a specific trait.
        /// </summary>
        /// <param name="bcid">The Biometric Class ID (BCID) of the person for which to find out whether he or she is already enrolled or not.</param>
        /// <param name="trait">The biometric trait (e.g. face, or any other of the supported traits) for which to look for a template belonging to the specified person.</param>
        /// <returns>A template for the specified BCID and trait is available or not.</returns>
        private static async Task<bool> IsEnrolledAsync(string bcid, Trait trait)
        {
            using (var client = new HttpClient())
            {
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes($"{APP_IDENTIFIER}:{APP_SECRET}")));
                using (var response = await client.GetAsync(ENDPOINT + $"isenrolled?bcid={bcid}&trait={trait}"))
                {
                    Console.Write("IsEnrolled response... ");
                    if (response.StatusCode == HttpStatusCode.OK)
                    {
                        Console.WriteLine(true);
                        return true;
                    }

                    Console.WriteLine(response.StatusCode.ToString());
                    return false;
                }
            }
        }

        /// <summary>
        /// Deletes all biometric data associated with a Biometric Class ID from the system.
        /// </summary>
        /// <param name="bcid">The Biometric Class ID (BCID) of the class that shall get deleted.</param>
        /// <returns>The class has been deleted or not.</returns>
        private static async Task<bool> DeleteClassAsync(string bcid)
        {
            using (var client = new HttpClient())
            {
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes($"{APP_IDENTIFIER}:{APP_SECRET}")));
                using (var response = await client.DeleteAsync(ENDPOINT + $"deleteclass?bcid={bcid}"))
                {
                    Console.WriteLine("DeleteClass response... " + response.IsSuccessStatusCode);
                    return response.IsSuccessStatusCode;
                }
            }
        }

        /// <summary>
        /// Fetches the result of the last biometric operation
        /// (i.e. verification, identification, enrollment or liveness detection).
        /// </summary>
        /// <param name="bwsToken">The BWS web token that was used to perform the biometric task.</param>
        /// <returns>Returns an OperationResult object describing the result of the last biometric operation.</returns>
        private static async Task<string> ResultAsync(string bwsToken)
        {
            using (var client = new HttpClient())
            {
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes($"{APP_IDENTIFIER}:{APP_SECRET}")));
                using (var response = await client.GetAsync(ENDPOINT + $"result?access_token={bwsToken}"))
                {
                    Console.Write("Result response... ");
                    if (response.StatusCode == HttpStatusCode.OK)
                    {
                        string result = await response.Content.ReadAsStringAsync();
                        var json = JObject.Parse(result);
                        bool success = (bool)json["Success"];
                        string action = (string)json["Action"];
                        string bcid = (string)json["BCID"];

                        // For identify we receive the matches
                        if (action == TokenFor.identify.ToString())
                        {
                            // we can see the matches
                            var matches = json["Matches"];

                        }
                        if (!success)
                        {
                            // read out the error
                            string error = (string)json["Error"];
                            Console.WriteLine(error);
                        }
                        Console.WriteLine(json.ToString());
                        return json.ToString();
                    }

                    Console.WriteLine(response.StatusCode.ToString());
                    return string.Empty;
                }
            }
        }

        /// <summary>
        /// Requests status information from a BWS installation.
        /// </summary>
        /// <returns>
        /// Returns a StatusResult object, containing information about the running BWS installation.
        /// </returns>
        private static async Task<string> BWSStatusAsync()
        {
            using (var client = new HttpClient())
            {
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes($"{APP_IDENTIFIER}:{APP_SECRET}")));
                using (var response = await client.GetAsync(ENDPOINT + $"status"))
                {
                    Console.Write("BWSStatus response... ");
                    if (response.StatusCode == HttpStatusCode.OK)
                    {
                        string result = await response.Content.ReadAsStringAsync();
                        var json = JObject.Parse(result);

                        // read out status information
                        string version = (string)json["Version"];
                        string label = (string)json["Label"];
                        var features = json["Features"];

                        Console.WriteLine(json.ToString());
                        return json.ToString();
                    }

                    Console.WriteLine(response.StatusCode.ToString());
                    return string.Empty;
                }
            }
        }

        #endregion

        #region Helper functions

        /// <summary>
        /// The usage description for the command line tool.
        /// </summary>
        private static void Usage()
        {
            Console.Error.Write(@"
TestBWSWebApi is a simple BWS command line tool that executes all available commands
at the specified BioID Web Service. Default images for live recorded images
and fake images are available. You can specify other images for live and fake images per command line.

Syntax: 
      TestBWSWebApi /help | /h
      TestBWSWebApi [/live1:<imageFilePath>] [/live2:<imageFilePath>] | [/fake1:<imageFilePath>] [/fake2:<imageFilePath>] 
| [/id:<imageFilePath>] | [/highRes:<imageFilePath>] | [/noFace:<imageFilePath>]
");
        }

        /// <summary>
        /// Converts an image to a data url presentation.
        /// </summary>
        /// <param name="imageFilePath">The file path of the image.</param>
        /// <returns>The image in data url format.</returns>
        private static async Task<string> ConvertToDataUrlImageAsync(string imageFilePath)
        {
            byte[] image = await File.ReadAllBytesAsync(imageFilePath);
            string imageType = Path.GetExtension(imageFilePath).ToLower().Replace(".", "");
            return $"data:image/{imageType};base64," + Convert.ToBase64String(image);
        }

        #endregion
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="Arguments"/> class to parse command lines.
    /// </summary>
    /// <param name="args">The command line to parse.</param>
    public class Arguments
    {
        /// <summary>
        /// List of prefixed arguments
        /// </summary>
        private StringDictionary prefixedParams = new StringDictionary();

        /// <summary>
        /// Initializes a new instance of the <see cref="Arguments"/> class to parse command lines.
        /// </summary>
        /// <param name="args">The command line to parse.</param>
        public Arguments(string[] args)
        {
            Regex spliter = new Regex(@"^([/-]|--){1}(?<name>\w+)([:=])?(?<value>.+)?$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
            char[] trimChars = { '"', '\'' };
            Match part;

            foreach (string arg in args)
            {
                part = spliter.Match(arg);
                if (part.Success)
                    prefixedParams[part.Groups["name"].Value] = part.Groups["value"].Value.Trim(trimChars);
            }
        }

        /// <summary>
        /// Retrieves the parameter with the specified name.
        /// </summary>
        /// <param name="name">
        /// The name of the parameter. The name is case insensitive.
        /// </param>
        /// <returns>
        /// The parameter or <c>null</c> if it cannot be found.
        /// </returns>
        public string this[string name]
        {
            get
            {
                return prefixedParams[name];
            }
        }
    }
}