---
title: "13. Permission Model & Security"
space: "CAMS Biometric Integration"
url: "https://docs.navari.co.ke/cams-biometric/permission-model-security"
updated: "2026-05-27"
---

### 13.0 Endpoint Access

The `attendance()` callback endpoint is whitelisted as a guest-accessible API method using Frappe's `@frappe.whitelist(allow_guest=True)` decorator. This is necessary because the CAMS Gateway does not have a FrappeHR user account and it is an external system making unauthenticated HTTP POST requests.

### 13.1 Authentication via AuthToken

The security mechanism is the `AuthToken` in the JSON body. Every incoming request is checked:

1. The `AuthToken` is extracted from `RealTime.AuthToken` in the payload
2. It is compared against the `auth_token` stored in CAMS Biometric Settings using a direct database query
3. If it doesn't match, the request is rejected and logged

This means an attacker who discovers your callback URL cannot forge punch records without also knowing your AuthToken. Keep your AuthToken confidential and rotate it if you suspect it has been compromised.



### 13.2 Direct DB Queries vs. ORM

A key architectural decision in this app is using `frappe.db.get_value()` and `frappe.db.sql()` for certain operations rather than the standard `frappe.get_doc()` ORM calls. This was a deliberate choice:

- The guest-accessible endpoint cannot use standard document permission checks (the request has no session user)
- Rather than disabling permissions system-wide with `frappe.flags.ignore_permissions = True`, the app queries the database directly for the specific data it needs
- This minimises the attack surface: even if the endpoint is probed, it can only create Employee Checkin records for employees that actually exist in the system



### 13.3 AuthToken Storage

The `auth_token` field in CAMS Biometric Settings is stored as a `Password` type field in Frappe, meaning it is masked in the UI and not exposed in standard list views. Only users with access to the CAMS Biometric Settings doctype can read it.