# Security

## PIN Security

### Storage

Cashier PINs are **never stored in plain text**. The system uses:

* **SHA-256 hashing** with a per-cashier salt
* **32-byte random salt** generated for each cashier (64 hex characters)
* **Timing-safe comparison** to prevent timing attacks during verification

```
Stored: SHA-256(pin + ":" + salt)
```

Even if the database were compromised, PINs cannot be recovered from the hashes.

### PIN Rules

| Rule               | Detail                                  |
| ------------------ | --------------------------------------- |
| Minimum length     | 8 digits                                |
| Allowed characters | Digits only (0-9)                       |
| Uniqueness         | Each cashier must have a unique PIN     |
| Reset              | Only the merchant can reset a PIN       |
| Retrieval          | Not possible -- PINs are one-way hashed |

### Why Unique PINs?

The system identifies cashiers by their PIN during login. When a cashier enters their PIN, the system searches all allowed cashiers for a match. If two cashiers shared the same PIN, the system couldn't tell them apart.

## Session Security

### Token Generation

* **32 bytes** of cryptographically random data (`crypto.getRandomValues()`)
* Stored as a 64-character hex string
* Only the **hash** of the token is stored in the database

### Token Storage

* Primary: **httpOnly secure cookie** (cannot be accessed by JavaScript)
* Backup: **localStorage** (for session recovery if cookie is lost)

### Session Expiration

* Sessions last **15 minutes** from last activity
* Activity (creating payments, navigating) resets the timer
* Expired sessions are automatically cleaned up by a background job

### Session Termination

Sessions are ended when:

* The 15-minute inactivity timer expires
* The cashier manually logs out
* The merchant resets the cashier's PIN
* The merchant deactivates the cashier
* The merchant deactivates the terminal

## Terminal Access Control

### Public vs Private Information

| Information                         | Accessible By                                        |
| ----------------------------------- | ---------------------------------------------------- |
| Terminal name, code                 | Anyone with the terminal URL (needed for login page) |
| Terminal settings, allowed cashiers | Merchant only (requires dashboard authentication)    |
| Cashier names (for login display)   | Anyone at the terminal URL                           |
| Cashier PINs                        | Nobody (hashed)                                      |
| Payment history                     | Merchant only                                        |

### Terminal URL Security

* Terminal URLs contain a system-generated ID (`term_<random>`), not the short code
* Terminal IDs are not easily guessable
* Knowing the URL only gives access to the login screen, not to any payment functions
* A valid PIN is still required to create payments

## Payment Security

* Every payment requires a valid, non-expired session
* Payments are attributed to the authenticated merchant (terminal owner)
* Order IDs create an audit trail linking payments to terminals and cashiers
* Chain, token, and amount are validated server-side before payment creation


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.makapay.io/point-of-sale-pos/security.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
