The Challenge
Our platform needs to:
- Securely collect and validate user credentials
- Make credentials available for automation scripts without storing them
- Support atomic credential updates and instant revocation
- Maintain complete audit trails without exposing sensitive data
- Handle all of this at scale across a distributed system
Zero-Persistence Token Architecture
Rather than storing credentials, we implemented a "zero-persistence" architecture where credentials exist only as encrypted tokens in memory, passed through our system using a capability-based security model.
Here's a simplified version of our token structure:
1interface CredentialToken {
2 userId: string;
3 serviceId: string;
4 capabilities: string[];
5 encryptedPayload: Buffer;
6 metadata: {
7 created: number;
8 ttl: number;
9 version: number;
10 };
11 hmac: string;
12}
The encryptedPayload
contains the actual credentials, encrypted using a combination of per-request ephemeral keys and hardware security module (HSM) master keys. The capabilities
array defines exactly what operations this token can perform, following the principle of least privilege.
Secure Token Propagation
To propagate tokens securely between services, we developed a lightweight protocol we call CapsulePassing
:
1interface Capsule {
2 tokenId: string;
3 keyring: {
4 version: number;
5 keys: EncryptedKeySet;
6 };
7 claims: {
8 issuer: string;
9 subject: string;
10 exp: number;
11 };
12 payload: EncryptedToken;
13}
Services can only decrypt tokens if they possess the necessary capability keys, which are rotated frequently. The keyring
contains service-specific keys encrypted for each downstream service that may need access.
Atomic Updates and Revocation
For credential updates and revocation, we use a distributed version vector system:
1class CredentialVersionVector {
2 private vector: Map<string, number> = new Map();
3
4 public bump(serviceId: string): void {
5 const current = this.vector.get(serviceId) || 0;
6 this.vector.set(serviceId, current + 1);
7 }
8
9 public isStale(token: CredentialToken): boolean {
10 return token.metadata.version <
11 (this.vector.get(token.serviceId) || 0);
12 }
13}
When credentials are updated or revoked, we increment the version vector. Services check the version vector before using any token, ensuring atomic updates without requiring persistent storage or blocking operations.
Implementation at Scale
Our system handles millions of credential tokens while maintaining strict security guarantees. Key to this is our ephemeral decryption
pattern:
async function useCredentials<T>(
token: CredentialToken,
operation: (creds: Credentials) => Promise<T>
): Promise<T> {
const context = await createSecureContext();
try {
const creds = await context.decrypt(token);
return await operation(creds);
} finally {
await context.destroy();
}
}
This pattern ensures credentials only exist in memory for the duration of a single operation. The secure context is bound to hardware-backed memory encryption where available.
Results
This architecture has allowed us to:
[list-check]
- Process millions of automation operations daily without persisting credentials
- Maintain sub-50ms p99 latency for credential access
- Achieve zero credential exposure in logs or persistent storage
- Support instant credential revocation across our entire platform
- Pass security audits with zero critical findings
Future Work
We're currently working on extending our architecture to support:
[list-task]
- Hardware-backed memory encryption for all credential operations
- Automated credential rotation based on usage patterns
- Enhanced audit capabilities using zero-knowledge proofs
- Cross-region token propagation with minimal latency impact
[cta]
The challenges of secure credential management at scale are ongoing, but our zero-persistence architecture has proven to be a robust foundation for building secure automation infrastructure.