Detecting Real Users with AWS Amplify & Face Liveness

6 min read

  • AWS Amplify
  • Face Liveness
  • SIM Registration
  • Security
  • Web Development
Detecting Real Users with AWS Amplify & Face Liveness

Have you ever wondered how banking apps instantly verify your identity with just a selfie, how e-commerce platforms prevent sophisticated fraud attempts during account creation, or how telecom providers ensure secure SIM Card registration? The answer lies in advanced face liveness detection technology that can distinguish between real humans and spoofing attempts in milliseconds, enabling businesses to comply with regulations, prevent identity theft, and stop fraudulent account or SIM activations before they happen.

In today's digital landscape, where deepfakes and sophisticated fraud techniques are becoming increasingly common, traditional authentication methods are no longer sufficient. According to recent studies, facial recognition fraud attempts have increased by 350% in 2024 alone, making robust liveness detection not just a nice-to-have feature, but a critical security requirement.

Today, we'll dive deep into implementing AWS Amplify's Face Liveness detection in a Next.js application using the App Router, transforming your user verification process from vulnerable to virtually unbreachable.

Understanding Face Liveness Detection: Beyond Simple Facial Recognition

Face liveness detection goes far beyond simply recognizing a face. While traditional facial recognition answers "who is this person?", liveness detection tackles the crucial question: "is this a real, live person or a sophisticated fake?"

The technology works by analyzing multiple biometric indicators in real-time:

Physiological Indicators: Subtle skin texture variations, micro-expressions, and natural facial asymmetries that are nearly impossible to replicate artificially.

Behavioral Patterns: Natural head movements, eye blinking patterns, and involuntary facial muscle contractions that occur during live interaction.

Environmental Analysis: Lighting consistency, depth perception, and reflection patterns that help distinguish between real faces and photos, videos, or 3D masks.

AWS Amplify's Face Liveness leverages Amazon Rekognition's advanced machine learning models, trained on millions of samples to detect even the most sophisticated spoofing attempts including high-resolution photos, video replays, and 3D masks.

Step-by-Step Implementation Guide

Let me walk you through the exact implementation process I followed, based on AWS's official documentation:

Step 1: Project Setup

# Create Next.js app (without App Router for this example)
npx create-next-app@latest liveness-app --no-app

# Install required dependencies
npm install @aws-amplify/ui-react-liveness @aws-amplify/ui-react aws-amplify

# Install Amplify CLI globally
npm install @aws-amplify/cli -g

# Configure Amplify (first time only)
amplify configure

# Initialize Amplify project
amplify init

Step 2: Add Authentication

AWS Amplify requires authentication to use Face Liveness detection:

# Add Cognito authentication
amplify add auth

# Choose default configuration
# Push changes to AWS
amplify push

Step 3: Create REST API with Lambda Backend

# Add REST API
amplify add api

# Choose REST
# Provide friendly name: "liveness"
# Path: "/session"
# Choose: Create a new Lambda function
# Template: Serverless ExpressJS function

In the Lambda function directory (amplify/backend/function/liveness/src/), install the Rekognition client:

npm install @aws-sdk/client-rekognition

Setting Up the Foundation

First, let's establish our project structure and dependencies:

npx create-next-app@latest face-liveness-app --typescript --app
cd face-liveness-app
npm install @aws-amplify/ui-react @aws-amplify/ui-react-liveness aws-amplify

Configuring AWS Amplify

Create your Amplify configuration file (amplify_outputs.json):

{
  "version": "1",
  "auth": {
    "aws_region": "us-east-1",
    "user_pool_id": "us-east-1_XXXXXXXXX",
    "user_pool_client_id": "xxxxxxxxxxxxxxxxxxxxxxxxxx",
    "identity_pool_id": "us-east-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
  },
  "predictions": {
    "face_liveness": {
      "region": "us-east-1",
      "proxy": false
    }
  }
}

The Core Implementation

Based on the official AWS documentation, here's the correct implementation using AWS Amplify API with Express backend:

Backend Setup with AWS Lambda:

First, let's create the Lambda function endpoints. In the amplify/backend/function/liveness/src folder, we need the getRekognitionClient utility:

// amplify/backend/function/liveness/src/utils/getRekognitionClient.js
const { Rekognition } = require("@aws-sdk/client-rekognition");

const getRekognitionClient = () => {
  const rekognitionClient = new Rekognition({
    region: "us-east-1", // Update to match your region
  });
  return rekognitionClient;
};

module.exports = getRekognitionClient;

Then update your Express app.js file:

// amplify/backend/function/liveness/src/app.js
const getRekognitionClient = require("./utils/getRekognitionClient");

// Create liveness session endpoint
app.get("/session/create", async function (req, res) {
  const rekognition = getRekognitionClient();
  const response = await rekognition.createFaceLivenessSession({});

  return res.status(200).json({
    sessionId: response.SessionId,
  });
});

// Get liveness results endpoint
app.get("/session/get", async function (req, res) {
  const rekognition = getRekognitionClient();
  const response = await rekognition.getFaceLivenessSessionResults({
    SessionId: req.query.sessionId,
  });

  // AWS recommends confidence > 90 for liveness verification
  const isLive = response.Confidence > 90;
  res.status(200).json({
    isLive,
    confidence: response.Confidence,
  });
});

Frontend Implementation with Next.js App Router:

// app/components/LivenessDetector.tsx
"use client";

import { useEffect, useState } from "react";
import { FaceLivenessDetector } from "@aws-amplify/ui-react-liveness";
import { API } from "aws-amplify";

export function LivenessCheck() {
  const [loading, setLoading] = useState<boolean>(true);
  const [sessionId, setSessionId] = useState<{
    sessionId: string;
  } | null>(null);
  const [verificationResult, setVerificationResult] = useState("");

  // Create liveness session on component mount
  useEffect(() => {
    const fetchCreateLiveness = async () => {
      try {
        const response = await API.get("liveness", "/session/create", {});
        setSessionId(response);
        setLoading(false);
      } catch (error) {
        console.error("Error creating session:", error);
        setLoading(false);
      }
    };

    fetchCreateLiveness();
  }, []);

  const handleAnalysisComplete = async () => {
    try {
      const data = await API.get("liveness", "/session/get", {
        queryStringParameters: {
          sessionId: sessionId?.sessionId,
        },
      });

      if (data.isLive) {
        setVerificationResult(
          `✅ User is live (Confidence: ${data.confidence}%)`
        );
        // Redirect to authenticated area or next step
        window.location.href = "/dashboard";
      } else {
        setVerificationResult(
          `❌ Verification failed (Confidence: ${data.confidence}%)`
        );
        // Allow user to retry or handle failed verification
      }
    } catch (error) {
      console.error("Error verifying liveness:", error);
      setVerificationResult("Error occurred during verification");
    }
  };

  const handleError = (error: Error) => {
    console.error("Liveness detection error:", error);
    setVerificationResult("Camera access error. Please check permissions.");
  };

  if (loading) {
    return (
      <div className="flex items-center justify-center p-8">
        <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600 mr-4"></div>
        <span>Preparing liveness detection...</span>
      </div>
    );
  }

  return (
    <div className="max-w-md mx-auto p-4">
      {sessionId && (
        <FaceLivenessDetector
          sessionId={sessionId.sessionId}
          region="us-east-1"
          onAnalysisComplete={handleAnalysisComplete}
          onError={handleError}
        />
      )}
      {verificationResult && (
        <div className="mt-4 p-4 rounded-lg bg-gray-100">
          <h3 className="font-semibold">Verification Result:</h3>
          <p>{verificationResult}</p>
        </div>
      )}
    </div>
  );
}

Setting up the Main Application:

Configure your main app component with Amplify authentication:

// app/layout.tsx (for App Router) or pages/_app.tsx (for Pages Router)
"use client";

import { Amplify } from "aws-amplify";
import { withAuthenticator } from "@aws-amplify/ui-react";
import "@aws-amplify/ui-react/styles.css";
import awsExports from "../aws-exports";

Amplify.configure(awsExports);

function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>{children}</body>
    </html>
  );
}

export default withAuthenticator(RootLayout);

Required IAM Permissions:

You'll need to add these permissions to your Amplify auth role:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["rekognition:StartFaceLivenessSession"],
      "Resource": "*"
    }
  ]
}

Lambda Function Permissions:

Create the custom-policies.json file for your Lambda function:

[
  {
    "Action": [
      "rekognition:CreateFaceLivenessSession",
      "rekognition:GetFaceLivenessSessionResults"
    ],
    "Resource": ["*"]
  }
]

Conclusion

Face liveness detection is a pragmatic leap forward in biometric security. It closes the gap left by basic facial recognition by confirming there’s a real, live human behind the camera, not a photo, replay, or mask. Implemented with AWS Amplify and Rekognition, it’s practical to ship today without handling raw biometrics yourself.

Looking ahead, the strongest solutions will blend multiple signals (face, voice, behavior), verify continuously when risk is high, and preserve privacy by design. Your goal is not only to block fraud but to earn user trust with a secure, respectful experience.