Easy serverless user validation: id + selfie

Lorenzo Panzeri
7 min readOct 15, 2023

Guess who is back? It’s-a me! After a long break made of half articles left uncomplished, I’m here again to tell you something about my beloved Serverless 😎

I was really interested in trying what AWS offers about ID document validation and data extraction. I never had the time to look into it but using AWS Step Functions and its Direct Integration features, the amount of time needed to get a working Proof Of Concept lowered a lot.

Yes, you need to invest some time understanding how Direct Integration works but I’ve already invested mine for you.

The project is an User ID validation service and is based on the check between a selfie and an ID card photo both taken by the user and uploaded (using presigned urls but more details later)

In this POC you will see some Lambdas but the interesting part is the Step Function where Direct Integration takes place without even write a single line of code. Connecting these services using AWS SDK and a lot of Lambdas would be messy, time consuming, hard and error prone.

You will see both AWS Rekognition and AWS Textract in action.

Another interesting thing is the EventBridge event that is created by the S3 Bucket of ID documents on the Create Object event and triggers directly the Step Function, even here without any code.

As usual you can find the project here on my Github

AWS Rekognition

Is the image recognition service from AWS that uses heavily machine learning to be able to identify objects in images, categorize photos, detect faces and labels and a lot more because can be customized by training your own machine learning model on a bunch of test images that you can upload and analyze.

In this project I will use the DetectFaces functions on both the Selfie and the ID Document photo and ask to Rekognition to comparing the result using CompareFaces. Seems working very well but I suggest you to try it out by yourself!

AWS Textract

Is an advanced Optical Character Recognition (OCR) service offered by AWS and powered by machine learning. It’s able to extract text from documents and handwritten notes. Is also able to auto-detect ID documents but at the moment the only international document supported is the Passport, all other documents are strongly biased to the USA layout. For example our Italian Electronic ID CARD (CIE), that adheres to the UE standard ID Card layout, is not well supported and for Textract seems an American Driving License. I think (and hope!) AWS will take care of this thing but for now if you need to easily get users data, is better to stick with the Passport (or use a Third Part Service like onfido, but this is another story and tradeoffs).

API

As usual I will leverage AWS SAM for this project and I invite you to read my previous articles to learn how to use it properly 😎.

The interaction with the service is managed by AWS API Gateway:

The [PUT] one is the first to call and creates the identification session, sending in response also the two Presigned Urls to allows the client to upload the selfie and the ID document.

The [POST] one is to inquiry the identification status. In this project at the beginning there was the idea to get the identification status back using a Webhook but i left this thing aside in order to be able to finish the article… Keep in mind that it would be an useful feature for your version of the project.

Step Function

Lets go deep on this part, first of all let me refresh to you how the AWS Step Function works.

You have to declare it in the SAM template.yaml file but the “real” Step Function core is in the statemachine/statemachine.asl.json file that contains all the steps workflow and connections.

About the template.yaml declaration, let me explain how you can inject parameters from the declaration into the statemachine.asl.json file:

The DefinitionSubstitutions part is what we need: use it like a key-value list where you can define the variables name and the value to put in it, always using the Intrinsic Functions like !Ref to be able to get the in-place resources.

About the statemachine.asl.json file, my advice is to create the Step Functions directly on the AWS Console and export fron there the definition: there is a new drag&drop editor that works like a charm.

In this Editor you can test the Direct Integration between AWS services. For a lot of them the Editor will suggest you the documentation to find out the correct parameters or request layout but for some others you have to search for it by yourself. As usual, AWS is always in evolution so things are getting better and better every day.

Lets understand how is possible to pass information between steps.

The first step gets the Json request that triggered the Step Functions but every response (output) of further Steps becomes the request (input) of the subsequent Step (Steps are also called States). Let’s see an example:

The dollar represents, if you are in the Parameters part the root of the JSON request, if you are in the ResultPath instead is the root of the JSON response.

"Bucket.$": "$.detail.bucket.name",

Pay attention to this part: I’m telling the State to retrieve the Bucket from the Json Request. If you need to populate a parameter with a value from the Json Request you need to add the .$ at the end of the parameter name.

To retrieve the parameter value from the Json Request you can leverage the Json notation, starting from the root object with $.<main_object>.<child>.<child_of_the_child> and so on.

Is important to keep in mind that each State will “throw away” the received Request and will give in Output only it’s processed results. If you need to keep the Request you have to tell the State to put its output in a specific place and keep the Request info as well:

"ResultPath": "$.comparedFaces"

Dynamo DB

You know that you can use also Dynamo DB with Direct Integration?

Without even a line of code we are able to update information in a record into DynamoDB with a known key! Nice, eh?

You can also leverage a field into DynamoDB record to store the whole process info you get from a “big” service like Textract’s AnalyzeID:

“States.” is the way to call some powerful functions (called Intrinsic Functions) that AWS created for you to ease the Direct Integration:

"S.$": "States.JsonToString($.analyzedId.IdentityDocuments[0].IdentityDocumentFields)"

Here I’m saving a whole json into a single field for processing it later (maybe…), see the result in the next screenshot:

I forgot about an important part about APIs: you may need to protect your APIs or count (or limit) how many calls you are getting from your customers: remember about API Keys and Usage plans, I have already explained them in another article:

One last thing about S3 Buckets: they are able to generate Events, this built-in functionality is pure gold in a Event Driver Architecture (EDA) solution.

To activate the Event publishing on EventBridge default Event Bus from the ID document bucket (idbucket) check the last 3 lines of code:

But these events are only published for now, we need also that some other component “listen to” them:

This part is placed in the Step Function declaration and enforce the activation only for the Object Created event from the S3 bucket with the proper name.

I hope that all these “tips and tricks” that I gave to you will save some of your time and allow you to create and validate solutions faster. 😎

See you the next time, hopefully not so far 😅

Ciao,

Lorenzo

--

--

Lorenzo Panzeri

Passionate Developer - Compulsive learner - Messy maker