Go-and-Facebox 03.2.18

Introducing Web Face ID, how to use HTML5, Go and Facebox to verify your face

Using your face to authorize to unlock your phone is going to became popular soon, but on the web it has not been seen a lot, maybe because it’s not trivial to implement. Is it possible to implement face verification using just HTML5, Javascript and some Go? Yes! I did it in an hour using Facebox, and released the code as open source project called Web Face ID.

How can you benefit from using Face Verification on a website?

  • You could use your face as a two factor authentication, for example to finish a payment.
  • You could prove that you are “not a robot”.
  • You could use your face to interact with services that requires a proof of identification like some banks, or insurance.
  • You can speed up your login system, for some use cases.
  • You could reduce fraud in your system, and impersonations.
Using Web Face ID by Machinebox to verify myself

How to implement it using standards

As a general approach we are going to capture the Webcam of the user, with HTML5 elements, and with Javascript we are going to send a photo to the server side.

Once it is on the server we are going to use Go to decode the photo and check it with Facebox, to be able to emit a response.

Let’s break it out in steps.

Prerequisites

You need Facebox up and running, for that you just need to sign up for an account to run Facebox as a Docker container in your machine. Also make sure that you teach Facebox, with the people you want to recognize, it only needs one-shot to get started, but with multiple examples it can become more accurate.

Capture the webcam with HTML5 and Javascript

For the website we can take advantage of the HTML5 video and canvas element:

<div class='options'>
   <button id="snap">
   <i class='camera icon'></i>
</button>
<video id="video" width="100%" autoplay></video>
<canvas id="canvas" width="400" height="225" style="display:none;"></canvas>

We are going to use the video element to capture the webcam, and use the canvas to take a photo and be able to send it to the server side. Here is the Javascript:

var video = document.getElementById('video');
if (navigator.mediaDevices && 
          navigator.mediaDevices.getUserMedia){
  navigator.mediaDevices.getUserMedia({video: true}).then(
function (stream) {
         video.src = window.URL.createObjectURL(stream);
         video.play();
  });
}
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var video = document.getElementById('video');
var button = $('#snap')
button.click(function(){
   button.addClass('loading')
   context.drawImage(video, 0, 0, 400, 225);
var dataURL = canvas.toDataURL();
   $.ajax({
       type: "POST",
       url: "/webFaceID",
       data: {
         imgBase64: dataURL
       },
       success: { // ommited }
   })
})

The code above basically says; when you click the button, capture the webcam into a canvas and send a photo to the endpoint /webFaceID. The photo will be a PNG encoded in base64.

Handle the face validation on the server side with Go

Now that we have the image with your face on the server side we only need to decode the image, send it to Facebox with the SDK to do the hard work, and get back a result to the front end.

Here we can write a Go http.Handler to do the job:

func (s *Server) handlewebFaceID(w http.ResponseWriter, r *http.Request) {
 img := r.FormValue("imgBase64")
 // remove the Data URI before decode
 b64data := img[strings.IndexByte(img, ',')+1:]
 imgDec, err := base64.StdEncoding.DecodeString(b64data)
 if err != nil {
    // omitted error handling 
 }
 // validate the face on facebox
 faces, err := s.facebox.Check(bytes.NewReader(imgDec))
 if err != nil {
   // omitted error handling
 }
 var response struct {
    FaceLen int    `json:"faces_len"`
    Matched bool   `json:"matched"`
    Name    string `json:"name"`
 }
 response.FaceLen = len(faces)
 if len(faces) == 1 {
    response.Matched = faces[0].Matched
    response.Name = faces[0].Name
 }
 w.Header().Set("Content-Type", "application/json")
 if err := json.NewEncoder(w).Encode(response); err != nil {
    http.Error(w, err.Error(), http.StatusInternalServerError)
    return
 }
}

In a few lines of code we have face verification working, on any website.

What about security?

Well, any type of biometric (like your face, iris or fingerprint) should be used only as a “username” and never as a “password”. So if you implement this for your website, it will be ideal as a second factor in authentication, or for certain low risk tasks, but it does not replace a password.

Also bear in mind that a malicious attacker could take a photo of you and use it to try and spoof your identity.

Top tip: Facebox is optimized to recognize people in any photo under all types of scenarios, but endpoint /check has an optional parameter tolerance that you can adjust. If your conditions for face verification don’t change (same position, same camera, and same ambient lighting for example), you can reduce the tolerance, making the system more strict when it does the validation.

If you want to have a look to the whole code, please check Web Face ID on github. It’s open source.