Skip to main content

Set up the proxy

This guide shows you how to set up a proxy for your application. The proxy acts as an intermediary between your application and the Microblink API. This is necessary to protect your API keys and other sensitive data.

You can find a sample implementation of a proxy service in our GitHub repository.

The sample is a .NET minimal API that exposes the following routes, each of which maps directly to an Agent API endpoint:

Proxy routeAgent API endpoint
POST /transactionPOST api/v1/transaction
GET /initialize/{workflowId}/infoGET api/v1/initialize/{workflowId}/info
POST /initialize/{workflowId}/cancelPOST api/v1/initialize/{workflowId}/cancel

Why use a proxy?

A proxy adds a layer of security to your application. It prevents your API keys from being exposed client-side. The initial request from your application is routed through the proxy. The proxy then adds your API keys to the requests before forwarding them to the Microblink API.

This setup also allows you to implement custom logic. For example, you can add end-user authentication, rate limiting, or logging.

Deployment options

You have several options for deploying the proxy. You can:

  1. Run it as a separate service in a container or VM.
  2. Integrate it into your existing codebase.
  3. Deploy it as a serverless function.

Run as a container or VM

You can run the proxy as a separate service in a container or a virtual machine. This is a good option if you want to decouple the proxy from your application.

Docker container

You can use the provided Dockerfile to build a Docker image from our sample implementation. Then, you can run the image as a container.

# Build the Docker image
docker build -t mb-proxy .

# Run the Docker container
docker run -p 8081:8080 mb-proxy

Alternatively, you can package your own proxy implementation as a Docker container. This gives you the flexibility to use any language or framework you prefer. For example, you could containerize the Python class wrapper shown in the "Integrate into your codebase" section.

Nginx proxy

You can use Nginx as a reverse proxy. This is a good option if you are already using Nginx in your infrastructure.

# Example of an Nginx configuration for the Microblink proxy routes.
# Replace <your_access_token> with a token obtained from the auth endpoint,
# and replace <us-east> with your target region.
server {
listen 80;
server_name your-proxy.com;

location /transaction {
if ($request_method != POST) {
return 405 'Method Not Allowed';
}

proxy_pass https://api.us-east.platform.microblink.com/agent/api/v1/transaction;
proxy_set_header Authorization "Bearer <your_access_token>";
proxy_set_header Content-Type "application/json";
proxy_set_header Host api.us-east.platform.microblink.com;
}

location ~ ^/initialize/([^/]+)/info$ {
if ($request_method != GET) {
return 405 'Method Not Allowed';
}

proxy_pass https://api.us-east.platform.microblink.com/agent/api/v1/initialize/$1/info;
proxy_set_header Authorization "Bearer <your_access_token>";
proxy_set_header Host api.us-east.platform.microblink.com;
}

location ~ ^/initialize/([^/]+)/cancel$ {
if ($request_method != POST) {
return 405 'Method Not Allowed';
}

proxy_pass https://api.us-east.platform.microblink.com/agent/api/v1/initialize/$1/cancel;
proxy_set_header Authorization "Bearer <your_access_token>";
proxy_set_header Content-Type "application/json";
proxy_set_header Host api.us-east.platform.microblink.com;
}
}

Integrate into your codebase

You can add the proxy logic directly into your application's back end. This is a good option if you want to keep your architecture simple.

For example, create a class that encapsulates the logic for forwarding requests to the Microblink API. This class will be responsible for adding the API keys to the requests.

# Example of a Python class wrapper
import os
import requests
import time

class MicroblinkProxy:
def __init__(self):
self.client_id = os.environ.get("MB_CLIENT_ID")
self.client_secret = os.environ.get("MB_CLIENT_SECRET")
self.agent_api_url = "https://api.us-east.platform.microblink.com/agent"
self.auth_url = "https://account.platform.microblink.com/oauth/token"
self.access_token = None
self.token_expiry = 0

def get_access_token(self):
if self.access_token and time.time() < self.token_expiry:
return self.access_token

payload = {
"client_id": self.client_id,
"client_secret": self.client_secret,
"grant_type": "client_credentials",
"audience": "idv-api"
}
response = requests.post(self.auth_url, json=payload)
response.raise_for_status()
token_data = response.json()
self.access_token = token_data["access_token"]
# Refresh token 5 minutes before it expires
self.token_expiry = time.time() + token_data["expires_in"] - 300
return self.access_token

def create_transaction(self, transaction_data):
'''
Creates a transaction by forwarding the request to the Agent API.
The response contains the transactionId, ephemeralKey, and edgeApiUrl
needed by the SDK to continue the transaction.
'''
headers = {"Authorization": f"Bearer {self.get_access_token()}"}
response = requests.post(
f"{self.agent_api_url}/api/v1/transaction",
headers=headers,
json=transaction_data
)
return response.json()

def get_workflow_info(self, workflow_id):
'''
Returns initialization info for the given workflow.
'''
headers = {"Authorization": f"Bearer {self.get_access_token()}"}
response = requests.get(
f"{self.agent_api_url}/api/v1/initialize/{workflow_id}/info",
headers=headers
)
return response.json()

def cancel_workflow(self, workflow_id):
'''
Cancels an in-progress workflow initialization.
'''
headers = {"Authorization": f"Bearer {self.get_access_token()}"}
response = requests.post(
f"{self.agent_api_url}/api/v1/initialize/{workflow_id}/cancel",
headers=headers
)
return response.json()

Run as a serverless function

You can deploy the proxy as a serverless function. This is a good option if you want to minimize infrastructure management.

A common pattern is to cache the access token in a global variable to reuse it across function invocations until it expires.

AWS Lambda

This function is designed to be triggered by an API Gateway endpoint. It routes incoming requests to the appropriate Agent API endpoint based on the request path.

// Example of an AWS Lambda function (Node.js) acting as a Microblink proxy
const fetch = require('node-fetch');

const AGENT_API_BASE = "https://api.us-east.platform.microblink.com/agent";

// Cache the token outside the handler to reuse across invocations
let cachedToken = null;
let tokenExpiry = 0;

async function getAccessToken() {
if (cachedToken && Date.now() < tokenExpiry) {
return cachedToken;
}

const authUrl = "https://account.platform.microblink.com/oauth/token";
const payload = {
client_id: process.env.MB_CLIENT_ID,
client_secret: process.env.MB_CLIENT_SECRET,
grant_type: "client_credentials",
audience: "idv-api"
};

const response = await fetch(authUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});

if (!response.ok) {
throw new Error('Failed to get access token');
}

const tokenData = await response.json();
// Refresh token 5 minutes before it expires
tokenExpiry = Date.now() + (tokenData.expires_in * 1000) - 300000;
cachedToken = tokenData.access_token;
return cachedToken;
}

// Map proxy paths to Agent API paths
function resolveAgentUrl(path) {
if (path === '/transaction') return `${AGENT_API_BASE}/api/v1/transaction`;
const infoMatch = path.match(/^\/initialize\/([^/]+)\/info$/);
if (infoMatch) return `${AGENT_API_BASE}/api/v1/initialize/${infoMatch[1]}/info`;
const cancelMatch = path.match(/^\/initialize\/([^/]+)\/cancel$/);
if (cancelMatch) return `${AGENT_API_BASE}/api/v1/initialize/${cancelMatch[1]}/cancel`;
return null;
}

exports.handler = async (event) => {
const agentUrl = resolveAgentUrl(event.path);
if (!agentUrl) {
return { statusCode: 404, body: 'Not Found' };
}

try {
const accessToken = await getAccessToken();

const response = await fetch(agentUrl, {
method: event.httpMethod,
headers: {
"Authorization": `Bearer ${accessToken}`,
"Content-Type": "application/json"
},
body: event.body || undefined
});

const data = await response.json();

return {
statusCode: response.status,
body: JSON.stringify(data)
};
} catch (error) {
return {
statusCode: 500,
body: JSON.stringify({ message: 'Internal server error' })
};
}
};

Netlify function

The logic for a Netlify function is very similar to the Lambda example above. The getAccessToken and resolveAgentUrl helpers are identical; only the entry point changes to match the Netlify function signature.

For a detailed example of how to implement a Netlify function that also injects data into the request, see the Match face images against selfies how-to guide.

// Example of a Netlify function (Node.js) acting as a Microblink proxy
const fetch = require('node-fetch');

// getAccessToken and resolveAgentUrl are the same as in the Lambda example above.
// ...

exports.handler = async (event) => {
const agentUrl = resolveAgentUrl(event.path);
if (!agentUrl) {
return { statusCode: 404, body: 'Not Found' };
}

// The rest of the handler logic is identical to the AWS Lambda example above.
// It should get the access token and forward the request to the resolved Agent API URL.
};

Secure your proxy

A proxy that is open to the public can be abused. It's critical to add a layer of authentication to ensure that only legitimate users from your application can create transactions. This protects your API quota and prevents malicious actors from creating transactions on your behalf.

A common approach is to have your client application (web or mobile) send a credential along with the request to the proxy. The proxy then validates this credential before proceeding.

For example, using an Express.js server, you could implement a middleware to check for a valid JSON Web Token (JWT) in the Authorization header.

// Example of a JWT authentication middleware in Express.js
const jwt = require('jsonwebtoken');

function authenticateToken(req, res, next) {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];

if (token == null) {
return res.sendStatus(401); // Unauthorized
}

jwt.verify(token, process.env.YOUR_JWT_SECRET, (err, user) => {
if (err) {
return res.sendStatus(403); // Forbidden
}
req.user = user;
next();
});
}

// Apply this middleware to your transaction creation route
app.post('/create-transaction', authenticateToken, (req, res) => {
// If we get here, the user is authenticated.
// Now we can proceed with creating the Microblink transaction.
// ...
});

Rate limiting

To prevent abuse, you should limit the number of requests a single user or IP address can make to your proxy.

// Example of rate limiting in Express.js
const rateLimit = require('express-rate-limit');

const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // Limit each IP to 100 requests per window
standardHeaders: true,
legacyHeaders: false,
});

// Apply the rate limiter to your route
app.post('/create-transaction', limiter, authenticateToken, (req, res) => {
// ...
});