Most two-factor authentication systems still rely on a dangerous assumption:
If the server is breached, authentication secrets can be protected.
TOTP breaks that assumption.
With TOTP, the server stores a shared secret. If your database leaks, attackers can generate valid OTP codes.
That is exactly the problem PulseProof Sentinel Protocol, or PPS, tries to solve.
PPS is an experimental open authentication protocol that replaces shared-secret TOTP codes with signed, time-bound, asymmetric proofs called Pulses.
Instead of this:
TOTP:
code = HMAC(shared_secret, time)
PPS uses this:
PPS:
Pulse = Sign(private_key, time + rp + nonce + counter + context + policy)
The server never stores a shared OTP secret.
It stores only public keys.
What Is PPS?
PulseProof Sentinel Protocol is an asymmetric authentication protocol designed for scenarios where traditional OTP, push authentication, and even WebAuthn are not enough.
It is especially useful for:
- offline authentication
- legacy OTP input forms
- QR-code and deep-link login
- constrained hardware terminals
- point-of-sale and IoT devices
- transaction signing with human-visible confirmation
- silent duress signaling
- offline multi-device threshold approval
PPS is not trying to replace WebAuthn/FIDO2.
WebAuthn remains the preferred standard for browser-based passkey authentication.
PPS is designed to complement WebAuthn by covering operational gaps where WebAuthn is unavailable or impractical.
You can explore the protocol here:
- Project website: https://pps-protocol.github.io
- Specification: https://pps-protocol.github.io/pulseproof-sentinel/SPEC.html
- Documentation: https://pps-protocol.github.io/pulseproof-sentinel/docs/
- IETF Internet-Draft: https://datatracker.ietf.org/doc/draft-hezami-pulseproof-sentinel/
- GitHub organization: https://github.com/pps-protocol
Why Not Just Use WebAuthn?
WebAuthn is excellent.
If you are building browser-based passwordless authentication, use WebAuthn.
But many real systems still need:
- OTP-style input fields
- offline verification
- hardware terminals without browser support
- transaction amount confirmation
- silent duress codes
- multi-device approval
- QR/deep-link authentication flows
That is where PPS fits.
Think of it like this:
| Scenario | Recommended |
|---|---|
| Browser passkey login | WebAuthn/FIDO2 |
| Legacy OTP form | PPS |
| Offline terminal authentication | PPS |
| High-value transaction signing | PPS |
| Silent duress authentication | PPS |
| Multi-device approval | PPS |
| IoT or constrained device authentication | PPS |
Core Features
PPS includes a small core protocol plus optional advanced modules.
Core
- Ed25519 signatures
- deterministic CBOR encoding
- time-bound Pulses
- nonce binding
- monotonic counter replay protection
- relying-party binding
- expiration enforcement
Optional Advanced Modules
- forward-secure key ratcheting
- silent duress / Honey-Pulse signaling
- offline n-of-m threshold approval
- transaction AmountMark verification
- dynamic policy binding
- environmental context binding
The protocol specification is available here:
https://pps-protocol.github.io/pulseproof-sentinel/SPEC.html
The PHP Implementation: pps-php
The core PHP implementation is available as a framework-agnostic package:
pps-protocol/pps-php
Links:
- GitHub: https://github.com/pps-protocol/pps-php
- Website: https://pps-protocol.github.io/pps-php/
- Documentation: https://pps-protocol.github.io/pps-php/docs/
- Packagist: https://packagist.org/packages/pps-protocol/pps-php
Install it with Composer:
composer require pps-protocol/pps-php
It supports:
- Pulse creation
- Pulse verification
- registration flows
- Trust Code generation
- AmountMark transaction codes
- duress keys
- threshold signatures
- offline mode
- memory, file, PDO, and Redis storage backends
Quick Example: Creating a Pulse
Here is a simplified client-side example:
use Pps\Client\AuthenticatorClient;
$client = new AuthenticatorClient($clientState);
$pulse = $client
->rpId('example.com')
->nonce($nonceFromServer)
->createPulse();
echo $pulse['token'];
echo $pulse['trust_code'];
The server verifies the Pulse using only the stored public key.
No shared secret is required.
Laravel Integration: laravel-pps
If you are using Laravel, there is a dedicated integration package:
pps-protocol/laravel-pps
Links:
- GitHub: https://github.com/pps-protocol/laravel-pps
- Website: https://pps-protocol.github.io/laravel-pps/
- Packagist: https://packagist.org/packages/pps-protocol/laravel-pps
Install it:
composer require pps-protocol/laravel-pps
Then run:
php artisan pps:install
This publishes the PPS config and migrations.
The package provides:
- service provider
- publishable configuration
- API routes
- HTTP controller
- facade
- Artisan commands
- storage backend integration
- transaction challenge endpoints
- silent duress handling support
Default routes:
| Method | Endpoint | Description |
|---|---|---|
| GET | /pps/health |
Health check |
| GET | /pps/challenge |
Create authentication challenge |
| POST | /pps/register |
Register a device |
| POST | /pps/verify |
Verify a Pulse Token |
| POST | /pps/transaction/challenge |
Create transaction challenge |
| POST | /pps/transaction/verify |
Verify transaction-bound Pulse |
Test the health endpoint:
curl http://localhost:8000/pps/health
Example response:
{
"status": "ok",
"protocol": "PulseProof Sentinel Protocol",
"version": 1,
"algorithm": "PPS-ED25519-CBOR30",
"epoch_seconds": 30,
"rp_id": "localhost"
}
Transaction Signing With AmountMark
One of the most useful PPS features is transaction signing.
Imagine a withdrawal:
Amount: 2,500,067 IRR
Trust Code: 49371867
The last two digits, 67, are derived from the transaction amount.
This allows the user to visually confirm that the signed transaction matches the displayed amount.
The client binds the transaction hash and amount to the Pulse:
use Pps\Crypto\Base64Url;
use Pps\Payload\ContextObject;
$context = new ContextObject();
$context->sessionId = Base64Url::decode($sessionId);
$context->txHash = Base64Url::decode($txHash);
$pulse = $client
->rpId('example.com')
->nonce($nonce)
->context($context)
->amountMinor(2500067)
->createPulse();
The server verifies:
- signature
- nonce
- counter
- transaction hash
- amount mark
- Trust Code
This is much stronger than sending a plain OTP for transaction confirmation.
Silent Duress Authentication
PPS also supports silent duress signaling.
If a user is forced to authenticate, the client can sign with a hidden duress key.
The server detects this internally but returns a normal-looking success response.
if ($result->honey) {
// Return normal response.
// Internally restrict account, alert security, delay settlement, etc.
}
This is useful for fintech, banking, crypto exchanges, and high-risk accounts.
The outward response should remain indistinguishable from a normal login.
How PPS Compares to TOTP
| Feature | TOTP | PPS |
|---|---|---|
| Shared secret on server | Yes | No |
| Asymmetric proof | No | Yes |
| Offline capable | Yes | Yes |
| Legacy OTP form support | Yes | Yes |
| Transaction binding | Weak | Strong |
| Amount confirmation | No | Yes |
| Silent duress | No | Optional |
| Threshold approval | No | Optional |
| Policy binding | No | Optional |
| Context binding | No | Optional |
Important Links
Here are the most important links if you want to explore PPS:
- Project website: https://pps-protocol.github.io
- Protocol repository: https://github.com/pps-protocol/pulseproof-sentinel
- Specification: https://pps-protocol.github.io/pulseproof-sentinel/SPEC.html
- Documentation: https://pps-protocol.github.io/pulseproof-sentinel/docs/
- IETF Internet-Draft: https://datatracker.ietf.org/doc/draft-hezami-pulseproof-sentinel/
- PHP core package: https://github.com/pps-protocol/pps-php
- PHP package docs: https://pps-protocol.github.io/pps-php/docs/
- Laravel package: https://github.com/pps-protocol/laravel-pps
- Laravel package website: https://pps-protocol.github.io/laravel-pps/
- Packagist core package: https://packagist.org/packages/pps-protocol/pps-php
- Packagist Laravel package: https://packagist.org/packages/pps-protocol/laravel-pps
Try It
If you are building:
- fintech authentication
- crypto withdrawal confirmation
- offline device authentication
- POS or IoT login
- high-security admin approval
- duress-aware accounts
- multi-device authorization
PPS may be worth exploring.
Start with the website:
https://pps-protocol.github.io
Then read the specification:
https://pps-protocol.github.io/pulseproof-sentinel/SPEC.html
If you use PHP or Laravel, install the packages:
composer require pps-protocol/pps-php
composer require pps-protocol/laravel-pps
PPS is experimental, so it is not recommended for production without security review. But if you are interested in authentication protocols, asymmetric OTP alternatives, or transaction signing, it is definitely worth a look.
If you find the idea useful, star the repositories, test the packages, and share feedback.
GitHub organization:
Top comments (0)