xLock: Universal Passwordless Authenticator
Password managers are a band-aid. xLock is the cure. DID-based push auth + XorIDA-split passkeys via xStore. No master password. No password database. Approve login with one tap.
Enterprise toolkit shipped:
@private.me/xlock-cli — reference auth server, 3-role RBAC, Docker deployment. 47 enterprise tests. Part of the Enterprise CLI Suite — 21 self-hosted servers, Docker-ready, air-gapped capable.
The Problem
Passwords are broken. TOTP is phishable. Password managers are a band-aid that manages a broken system. They store secrets on one device — a single point of failure. One breach = everything.
The average person manages 100+ passwords. Password managers like 1Password and LastPass consolidate them behind a single master password. That master password protects a vault — a centralized database of every credential you own. When LastPass was breached in 2022, attackers exfiltrated encrypted vaults for millions of users. The encryption held, but the architecture was exposed: one database, one key, one target.
TOTP (Google Authenticator, Authy) generates a 6-digit code from a shared symmetric secret stored on both the server and the user's device. A server breach exposes every user's TOTP seed. The attacker can generate valid codes indefinitely, from anywhere, without the user's device. The 30-second window and manual code entry create friction and phishing opportunities.
Apple Passkeys and FIDO2 hardware keys improve on TOTP with asymmetric cryptography, but they introduce new problems: platform lock-in (Apple Passkeys live in iCloud Keychain, unusable on Android), no recovery path (lose your FIDO2 key, lose your accounts), and device dependency (your authentication is only as available as your hardware).
The Core Failure
The PRIVATE.ME Solution
DID-based push auth + XorIDA-split passkeys via xStore. No master password. No password database. Ed25519 passkeys split across independent storage nodes. Approve login with one tap. No keys to steal. No database to breach.
xLock eliminates the password vault entirely. Instead of encrypting credentials behind a master password, xLock generates an Ed25519 keypair for each service. The private key (passkey) is immediately XorIDA-split into shares and distributed across independent storage backends via xStore. No single backend ever holds enough information to reconstruct the passkey.
When you need to authenticate, xLock reconstructs the passkey on-demand in memory, signs the authentication challenge, and immediately purges the key material. The passkey exists in plaintext for approximately 30 microseconds — long enough to sign, short enough that memory scraping is impractical.
Push-based approval means no TOTP codes, no code entry, no phishing surface. A third-party service sends a challenge to your DID via the xLink gateway. Your device shows a prompt: Approve or Deny. One tap. The Ed25519 signature covers the exact challenge ID, timestamp, and action — replay is impossible, forgery requires the private key that never persists anywhere.
The New Way
Architecture
Three storage nodes. 2-of-3 threshold. xStore pluggable backends. Passkeys reconstructed on-demand, signed, and purged. Zero plaintext persistence.
xLock uses xStore to distribute passkey shares across three independent storage backends. Any two of three shares are sufficient to reconstruct the passkey (2-of-3 threshold). Each backend is pluggable — local encrypted storage, cloud provider, hardware security module, or even a paper QR code. The backends are operationally independent: compromising one reveals zero information about the passkey.
Authentication Flow
Security Model
Information-theoretic split. HMAC integrity verification before reconstruction. Zero-knowledge backends. Ed25519 + Web Crypto API. AES encrypts and hopes. XorIDA splits and guarantees.
xLock's security rests on information-theoretic guarantees, not computational assumptions. XorIDA threshold sharing over GF(2) ensures that any single share reveals zero bits of information about the passkey — not "hard to crack" but mathematically impossible to learn anything. This holds regardless of the attacker's computational power, including quantum computers.
Security Properties
| Property | Mechanism | Guarantee |
|---|---|---|
| Confidentiality | XorIDA 2-of-3 splitting | Single share = zero information (information-theoretic) |
| Integrity | HMAC-SHA256 per share | Tampered shares rejected before reconstruction |
| Authentication | Ed25519 challenge-response | Private key never persists — reconstructed on-demand |
| Zero Knowledge | Independent storage backends | No single backend has enough to reconstruct |
| Anti-Replay | Challenge-bound signatures | Signature covers challengeId + timestamp + action |
| Quantum Safety | GF(2) operations only | No lattice/factoring assumptions — unconditional |
HMAC Before Reconstruction
Every share carries an HMAC-SHA256 integrity tag computed at split time. Before XorIDA reconstruction, both shares are independently HMAC-verified. If either tag fails, reconstruction is aborted and the share is rejected. This prevents tampered shares from producing corrupted passkeys. The HMAC verification uses timingSafeEqual() to eliminate timing side-channels.
The Fundamental Difference
XorIDA splits and guarantees. Your passkey is split into shares using information-theoretic secret sharing over GF(2). A single share contains zero information about the passkey — not "computationally infeasible" but mathematically impossible. No amount of computation, classical or quantum, can extract the passkey from a single share.
Comparison
How xLock compares to existing authentication solutions across security, usability, and recovery.
| Feature | 1Password | Google Auth | Apple Passkeys | FIDO2 | xLock |
|---|---|---|---|---|---|
| Master password | Yes | N/A | No | No | No |
| Split storage | No | No | No | No | Yes (2-of-3) |
| Push auth | No | No | No | No | Yes |
| Quantum-proof | No | No | No | No | Yes (IT-secure) |
| Recovery | Cloud backup | Backup codes | iCloud | No recovery | K-of-N QR |
| Air-gap capable | No | Yes | No | Yes | Yes |
Integration
QR scan registration, xlock:// deep links, WebAuthn API compatibility. Drop-in replacement for existing authentication flows.
xlock:// URI Format
// Registration xlock://register?service=acme.com&challenge=base64url&callback=https://acme.com/auth/callback // Authentication xlock://auth?service=acme.com&challenge=base64url&did=did:key:z6Mk... // Recovery initiation xlock://recover?service=acme.com&did=did:key:z6Mk...
Registration Flow
import { XlockVerifier } from '@private.me/xlock'; // 1. Generate a registration challenge const verifier = new XlockVerifier({ origin: 'https://acme.com' }); const challenge = await verifier.createRegistrationChallenge(); // 2. Display QR code or open xlock:// deep link // User scans QR → xLock generates Ed25519 keypair // → XorIDA-splits private key across xStore backends // → Returns public key (DID) to service // 3. Verify the registration response const result = await verifier.verifyRegistration(response); if (result.ok) { // Store result.value.did as the user's identity // did:key:z6Mk... — the Ed25519 public key await saveUserDid(userId, result.value.did); }
import { XlockVerifier } from '@private.me/xlock'; // 1. Create auth challenge for a known DID const challenge = await verifier.createAuthChallenge({ did: userDid, action: 'Sign in to Acme Dashboard', metadata: { ip: '203.0.113.42', location: 'San Francisco' } }); // 2. Challenge is pushed to user's device via xLink gateway // User sees: "Acme Dashboard wants to sign you in" // User taps Approve → xLock reconstructs passkey → signs → purges // 3. Verify the signed response const result = await verifier.verifyAuth(challenge.id); if (result.ok && result.value.approved) { // Signature verified — user authenticated grantAccess(userId); }
navigator.credentials.create() and navigator.credentials.get() APIs. No server-side changes required for WebAuthn-compatible services.
Enhanced Identity with Xid
xLock can optionally integrate with Xid to enable unlinkable authentication sessions — verifiable for the current session, but uncorrelatable across different devices, locations, or time periods.
Three Identity Modes
How Ephemeral Sessions Work
In xLock+ mode, each authentication session derives a unique DID via HKDF from the user's XorIDA-split master seed:
// User initiates authentication on mobile device const challenge = await xlock.createChallenge({ resource: 'https://app.example.com/dashboard', ephemeral: true // Enable Xid integration }); // User approves via biometric (Face ID / Touch ID) const proof = await xlock.approve(challenge); // Result: unique DID for this device + resource + epoch proof.did // did:key:z6MkY... (ephemeral, ~50µs derivation) // Same user auth from laptop → different DID // Same user auth next week → different DID (epoch rotation)
Key Benefits
| Capability | Without Xid (Basic) | With Xid (Plus/Enterprise) |
|---|---|---|
| Session tracking | Same DID across all devices — full correlation possible | Unique DID per device/session — cross-device correlation impossible |
| Location linkage | Persistent identifier enables movement tracking over time | Epoch rotation breaks temporal linkage across locations |
| Account sharing prevention (Anti-Piracy) | Shared credentials work across devices — no prevention | Per-device biometric binding — prevents credential sharing across users. Revenue assurance for SaaS vendors. |
| High-assurance auth | Single biometric (Face ID or Touch ID) | K-of-N multi-factor (Face ID + Touch ID + TPM + location + time) |
Enterprise
RBAC, append-only audit logs, compliance-ready, Docker deployment, air-gapped capable. Everything an enterprise needs to deploy passwordless authentication on their own infrastructure.
3-Role RBAC
| Role | Permissions |
|---|---|
| Admin | Create/revoke user passkeys, manage API keys, configure storage backends, rotate shares, read audit logs |
| Operator | Register new users, monitor auth challenges, read system health |
| Auditor | Read authentication logs, export compliance reports, verify HMAC chains |
CLI Commands
# Start the xLock auth server xlock serve --port 4500 → HTTP server on :4500 with RBAC + JSONL stores # Register a new user passkey xlock register --did "did:key:z6Mk..." --service "acme.com" → Generates Ed25519 keypair, XorIDA-splits, stores shares # Verify an audit log chain xlock verify --audit-log ./auth-audit.json → Replays HMAC chain, reports integrity # Export compliance report xlock export --from "2026-01-01" --to "2026-04-01" --format json → Authentication events, challenge outcomes, anomalies # Rotate storage backend shares xlock rotate --did "did:key:z6Mk..." --backend "node-c" → Re-splits passkey with new random shares, updates backend
Deployment
Multi-stage Alpine Docker build. Non-root user. Read-only filesystem. Health checks. docker compose up and your auth server is running on port 4500. Air-gapped deployment supported via docker save/load for environments with no internet connectivity.
Append-Only Audit Logs
Every authentication event is recorded in an append-only JSONL log with HMAC-SHA256 chain integrity. Each entry links to the previous via hash chain — tampering with any entry breaks the chain. Auditors can independently verify the entire log history using the xlock verify command.
Feature Tiers
Consumer tier is free during beta. Enterprise tier adds compliance, RBAC, and self-hosted deployment.
| Feature | Consumer (Free Beta) | Enterprise |
|---|---|---|
| Unlimited passkeys | Included | Included |
| Push auth | Included | Included |
| K-of-N QR recovery | Included | Included |
| XorIDA split storage | 2-of-3 | Configurable threshold |
| RBAC | — | Admin / Operator / Auditor |
| Audit logs | — | Append-only HMAC chain |
| SSO integration | — | SAML / OIDC |
| Compliance export | — | SOC 2 / ISO 27001 / HIPAA |
| Self-hosted deployment | — | Docker / air-gapped |
| Custom storage backends | — | HSM / on-prem / cloud |
| Support | Community | Dedicated + SLA |
Verifiable Authentication
Every xLock authentication produces a verifiable audit trail via xProve. HMAC-chained integrity proofs confirm that passkeys were split correctly, reconstructed faithfully, and purged completely.
Read the xProve white paper →
Benchmarks
Performance characteristics measured on Node.js 22, Apple M2. xLock completes the entire authentication pipeline in under 2 seconds — dominated by human tap latency, not cryptography.
| Operation | Time | Notes |
|---|---|---|
| Challenge generation | <1ms | Cryptographic nonce + metadata binding |
| Push notification delivery | ~200–500ms | Platform-dependent (APNs/FCM) |
| User tap (human latency) | ~500–2000ms | Biometric unlock + conscious approval |
| Passkey reconstruction | ~30µs | XorIDA reconstruct from split shares |
| Ed25519 signature | <1ms | Sign challenge with reconstructed key |
| Key material purge | <1µs | Zero-fill reconstructed key from memory |
| Response verification | <1ms | Ed25519 verify + nonce check + expiry |
| Full pipeline (crypto only) | ~1ms | Challenge → reconstruct → sign → verify |
| Full pipeline (with human) | ~1–3 seconds | Dominated by push delivery + human reaction |
Authentication Method Comparison
| Property | Password Manager | TOTP (Authenticator) | FIDO2/WebAuthn | xLock |
|---|---|---|---|---|
| Shared secrets | Yes (password hash) | Yes (TOTP seed) | No (public key) | No (split key) |
| Phishable | Yes | Yes | No (origin-bound) | No (push-based) |
| Recovery | Master password | Backup codes | Platform-specific | xStore split backup |
| Auth latency | ~2s (autofill) | ~10s (manual code) | ~1s (biometric) | ~1–3s (push + tap) |
| Quantum resistant | No | No | No (ECDSA/RSA) | IT-secure shares |
Developer Experience
Progressive feedback for every operation. 19 error codes across 5 categories guide developers to correct failures fast. UX helpers via @private.me/ux-helpers.
Progress Callbacks
All asynchronous operations support progress callbacks via the unified onProgress handler:
interface ProgressUpdate {
operation: string; // e.g., "requestXlockAuth", "respondXlockChallenge"
step: string; // Current step name
progress: number; // 0–100 percentage
message: string; // Human-readable status
}
type ProgressCallback = (update: ProgressUpdate) => void;
| Function | Progress Steps | Total Steps |
|---|---|---|
requestXlockAuth() |
Generating challenge → Sending push notification → Awaiting response | 3 |
respondXlockChallenge() |
Reconstructing passkey → Signing challenge → Purging key material → Sending response | 4 |
generatePasskey() |
Generating Ed25519 keypair → Splitting into shares → Distributing to xStore → Verifying storage | 4 |
signChallenge() |
Fetching shares → Reconstructing key → Signing → Purging ephemeral key | 4 |
Error Codes
19 error codes across 5 categories. Every error includes a code, message, category, and actionable resolution:
DetailedError interface from @private.me/ux-helpers:
interface DetailedError extends Error {
code: string; // Unique error code
category: string; // Error category
resolution?: string; // Suggested fix
details?: any; // Additional context
}
Challenge Management (4 codes)
| Code | Message | Resolution |
|---|---|---|
CHALLENGE_EXPIRED |
Authentication challenge expired (5-minute TTL) | Request new challenge via requestXlockAuth() |
CHALLENGE_INVALID |
Challenge signature verification failed | Ensure challenge was generated by trusted server |
CHALLENGE_ALREADY_USED |
Challenge nonce already consumed (replay attack) | Request fresh challenge — nonces are single-use |
CHALLENGE_GENERATION_FAILED |
Failed to generate cryptographic challenge | Check server entropy source and Ed25519 key availability |
Response Validation (4 codes)
| Code | Message | Resolution |
|---|---|---|
RESPONSE_SIGNATURE_INVALID |
Ed25519 signature verification failed | Verify passkey integrity and reconstruction |
RESPONSE_TIMEOUT |
User did not respond within timeout window (default: 2 minutes) | Re-request authentication or increase timeout |
RESPONSE_DEVICE_MISMATCH |
Response came from different device than registered | User must respond from the registered device |
RESPONSE_USER_REJECTED |
User explicitly rejected authentication request | User denied push notification — retry or use fallback |
Passkey Operations (5 codes)
| Code | Message | Resolution |
|---|---|---|
PASSKEY_NOT_FOUND |
No passkey shares found in xStore | Verify passkey exists before authentication — call generatePasskey() if missing |
PASSKEY_RECONSTRUCTION_FAILED |
XorIDA reconstruction failed (insufficient shares or HMAC mismatch) | Verify at least K-of-N shares are available and uncorrupted |
PASSKEY_GENERATION_FAILED |
Ed25519 keypair generation failed | Check Web Crypto API availability and entropy source |
PASSKEY_STORAGE_FAILED |
Failed to store shares in xStore backends | Verify xStore backends are reachable (requires K-of-N success) |
PASSKEY_HMAC_MISMATCH |
Share integrity check failed (HMAC verification) | Share corruption detected — attempt recovery from alternate backend |
Recovery (3 codes)
| Code | Message | Resolution |
|---|---|---|
RECOVERY_SHARES_INSUFFICIENT |
Fewer than K shares available for recovery | Contact support or re-register device if all backends failed |
RECOVERY_VERIFICATION_FAILED |
Recovery attempt signature verification failed | Ensure recovery shares match original registration |
RECOVERY_BACKEND_UNAVAILABLE |
All xStore backends unreachable | Check network connectivity — requires at least K-of-N backends |
Platform Integration (3 codes)
| Code | Message | Resolution |
|---|---|---|
BIOMETRIC_REQUIRED |
Biometric authentication required but not available | Enable biometric unlock (Face ID / Touch ID / fingerprint) for this device |
PUSH_NOTIFICATION_DISABLED |
Push notifications are disabled for this app | Enable push notifications in device settings |
PLATFORM_CRYPTO_UNAVAILABLE |
Web Crypto API or platform keychain unavailable | Upgrade browser/OS or check for restrictive security policies |
Code Example: 1-Tap Push Authentication
import { requestXlockAuth, respondXlockChallenge } from '@private.me/xlock';
// SERVER: Request authentication from user
async function serverRequestAuth(userId: string) {
const challenge = await requestXlockAuth({
userId,
timeout: 120000, // 2 minutes
onProgress: (update) => {
console.log(\`[\${update.progress}%] \${update.message}\`);
// 0%: Generating challenge
// 50%: Sending push notification
// 100%: Awaiting response
}
});
// Challenge sent — wait for user response
return challenge;
}
// CLIENT: Respond to push notification
async function clientRespondToPush(challenge: string) {
try {
const response = await respondXlockChallenge({
challenge,
onProgress: (update) => {
console.log(\`[\${update.progress}%] \${update.message}\`);
// 0%: Reconstructing passkey
// 25%: Signing challenge
// 50%: Purging key material
// 100%: Sending response
}
});
console.log('✓ Authentication successful');
return response;
} catch (error) {
// Typed error with category and resolution
if (error.code === 'PASSKEY_NOT_FOUND') {
console.error(\`Error: \${error.message}\`);
console.log(\`→ \${error.resolution}\`);
// Resolution: "Verify passkey exists before authentication"
// Generate new passkey
await generatePasskey({
userId,
onProgress: (update) => console.log(update.message)
});
} else if (error.code === 'BIOMETRIC_REQUIRED') {
console.error('Biometric unlock required');
console.log(\`→ \${error.resolution}\`);
// Resolution: "Enable biometric unlock for this device"
} else if (error.code === 'CHALLENGE_EXPIRED') {
console.error('Challenge expired — requesting new one');
// Request fresh challenge from server
} else {
console.error(\`Unexpected error: \${error.message}\`);
}
}
}
// TYPICAL FLOW (1-3 seconds total)
// Server: Generate challenge → ~1ms
// Server: Send push → ~200-500ms
// Client: Receive push → ~0ms (platform handles)
// User: Tap notification + biometric → ~500-2000ms (human latency)
// Client: Reconstruct passkey → ~30µs
// Client: Sign challenge → ~1ms
// Client: Purge key material → ~1µs
// Server: Verify signature → ~1ms
// ✓ Authenticated
2. Surface error resolutions to users: Display
error.resolution in UI — not just error.message.3. Pre-verify biometric availability: Check
navigator.credentials before requesting auth to fail fast.4. Implement retry logic: Auto-retry on
PUSH_NOTIFICATION_DISABLED with exponential backoff.5. Provide fallback auth: Offer SMS/email challenge delivery if push notifications fail.
Ship Proofs, Not Source
xLock generates cryptographic proofs of correct execution without exposing proprietary algorithms. Verify integrity using zero-knowledge proofs — no source code required.
- Tier 1 HMAC (~0.7KB)
- Tier 2 Commit-Reveal (~0.5KB)
- Tier 3 IT-MAC (~0.3KB)
- Tier 4 KKW ZK (~0.4KB)
Use Cases
Honest Limitations
Six known limitations documented transparently. xLock’s push-based model trades offline capability for phishing resistance.
| Limitation | Impact | Mitigation |
|---|---|---|
| Requires network for push | The authenticating device must have an active network connection to receive push notifications. Offline authentication is not possible. | Pre-derived one-time codes (via xID ephemeral derivation) can serve as offline fallback. These are generated in advance and stored in xStore split backup. |
| Human-in-the-loop latency | Total auth time is 1–3 seconds, dominated by push delivery and human reaction. This is slower than password autofill (~200ms). | The security guarantee (zero shared secrets, no phishing) justifies the latency trade-off. For automated systems, use xLink M2M authentication instead. |
| Push notification dependency | Relies on platform push services (APNs for iOS, FCM for Android). Push service outages block authentication. | Fallback to SMS or email challenge delivery. Multiple registered devices provide redundancy. Enterprise deployments can use direct WebSocket push. |
| xStore availability for recovery | Account recovery requires accessing split backup shares from xStore. If all xStore backends are unavailable, recovery is blocked. | 2-of-3 xStore configuration means any 2 backends suffice. Cross-region backend placement ensures geographic redundancy. |
| No batch authentication | Each authentication request requires a separate push + tap cycle. Batch approvals (sign 10 requests at once) are not supported. | Session tokens issued after initial auth allow subsequent operations without re-authentication. Token TTL is configurable (default 24 hours). |
| Platform-specific push setup | Each mobile platform (iOS, Android) requires separate push notification configuration (APNs certificates, FCM keys). Setup complexity scales with platform count. | Standard push setup tooling (Firebase Console, Apple Developer Portal) is well-documented. Enterprise CLI provides automated push configuration for managed deployments. |
Ready to deploy xLock?
Talk to Sol, our AI platform engineer, or book a live demo with our team.