Security & Data Integrity

How Euler Stream OAuth protects user sessions with envelope encryption and zero-knowledge architecture.

Security is at the core of the Euler Stream OAuth system. This document explains our security architecture, why your users' TikTok sessions are protected even in worst-case scenarios, and what this means for your integration.

Zero-Knowledge Session Storage

When a user authenticates via QR code, their TikTok session credentials are never stored in plaintext—not in our database, not in logs, not anywhere. Here's why this matters:

The Problem with Traditional Storage

In a typical OAuth system, session credentials are stored in a database, possibly encrypted with a master key. If an attacker gains database access and the master key, they can decrypt all user sessions.

Our Solution: Envelope Encryption

Euler Stream uses envelope encryption where the decryption key is derived from the tokens themselves:

┌─────────────────────────────────────────────────────────────────┐
│                     Session Encryption                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   User's TikTok Session ID (sensitive)                          │
│            │                                                    │
│            ▼                                                    │
│   ┌─────────────────┐                                           │
│   │    Encrypt      │◄──── Encryption Key derived from:         │
│   └────────┬────────┘      • Access Token                       │
│            │               • Refresh Token                      │
│            ▼                                                    │
│   Encrypted Session Blob (stored in database)                   │
│                                                                 │
│   To decrypt, you MUST have:                                    │
│   • The encrypted blob (database)                               │
│   • The access token (client only)                              │
│   • The refresh token (client only)                             │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

What This Means

  1. Database breach = useless data: If an attacker compromises our database, they get encrypted blobs that cannot be decrypted without the corresponding tokens (which are only held by your application).

  2. The developer has no access: Even we, the developers of Euler Stream, cannot decrypt user sessions. We do not have access to the tokens stored in your application.

  3. Decryption only in memory: The session ID only exists in decrypted form in RAM during active API requests. It is never written to disk, logs, or persistent storage in plaintext.

  4. Per-session isolation: Each user's session has a unique encryption key. Compromising one doesn't affect others.

Security Implications for Your Application

Because of this architecture, you are responsible for secure token storage:

Token Security Best Practices

// ❌ BAD: Storing tokens in plaintext
await db.users.update({
  id: userId,
  tiktokAccessToken: tokens.access_token,
  tiktokRefreshToken: tokens.refresh_token,
});
 
// ✅ GOOD: Encrypt tokens at rest
import { createCipheriv, createDecipheriv, randomBytes } from 'crypto';
 
const ENCRYPTION_KEY = process.env.TOKEN_ENCRYPTION_KEY!; // 32 bytes
 
function encryptToken(token: string): string {
  const iv = randomBytes(16);
  const cipher = createCipheriv('aes-256-gcm', Buffer.from(ENCRYPTION_KEY, 'hex'), iv);
 
  let encrypted = cipher.update(token, 'utf8', 'hex');
  encrypted += cipher.final('hex');
 
  const authTag = cipher.getAuthTag();
 
  return `${iv.toString('hex')}:${authTag.toString('hex')}:${encrypted}`;
}
 
function decryptToken(encryptedData: string): string {
  const [ivHex, authTagHex, encrypted] = encryptedData.split(':');
 
  const decipher = createDecipheriv(
    'aes-256-gcm',
    Buffer.from(ENCRYPTION_KEY, 'hex'),
    Buffer.from(ivHex, 'hex')
  );
 
  decipher.setAuthTag(Buffer.from(authTagHex, 'hex'));
 
  let decrypted = decipher.update(encrypted, 'hex', 'utf8');
  decrypted += decipher.final('utf8');
 
  return decrypted;
}
 
// Store encrypted
await db.users.update({
  id: userId,
  tiktokAccessToken: encryptToken(tokens.access_token),
  tiktokRefreshToken: encryptToken(tokens.refresh_token),
});

Additional Security Measures

  1. Use environment variables for client secrets, never commit them
  2. Implement rate limiting on your OAuth callback endpoint
  3. Validate the state parameter to prevent CSRF attacks
  4. Use HTTPS everywhere (required for redirect URIs except localhost)
  5. Rotate your client secret periodically via the dashboard
  6. Audit access logs to detect suspicious activity

What Happens If...

Your Database Is Breached

If your application's database is compromised and tokens are stolen:

  1. The attacker can use the tokens to make API requests as your users
  2. Immediately regenerate your client secret in the Euler Stream dashboard
  3. All existing tokens become invalid
  4. Users will need to re-authorize

Euler Stream's Database Is Breached

If Euler Stream's database is compromised:

  1. Attackers get encrypted session blobs
  2. These cannot be decrypted without your users' tokens
  3. No user sessions are compromised
  4. No action required from you (but we'd notify you anyway)

A User's Tokens Are Leaked

If a specific user's tokens are leaked:

  1. Revoke those tokens immediately:
  2. The user must re-authorize
  3. Other users are unaffected

Token Transmission Security

HTTPS Requirement

All OAuth endpoints use HTTPS. Redirect URIs must also use HTTPS in production (localhost is exempt for development convenience).

Logging and Debugging

What We Log

  • Request metadata (timestamp, endpoint, response code)
  • Client ID (to identify your application)
  • Error messages (without sensitive data)

What We Never Log

  • Access tokens
  • Refresh tokens
  • Session IDs (encrypted or plaintext)
  • QR code contents
  • User credentials

Your Logging

Ensure your application doesn't accidentally log tokens:

// ❌ BAD: Logging the full response
console.log('Token response:', tokenResponse);
 
// ✅ GOOD: Log only safe data
console.log('Token exchange successful', {
  expiresIn: tokenResponse.expires_in,
  scopes: tokenResponse.scope,
});

Security Summary

LayerProtection
Session StorageEnvelope encryption with per-session keys
Database Breach (Euler Stream)Sessions unrecoverable without client tokens
Database Breach (Your App)Depends on your encryption implementation
Developer AccessZero-knowledge: we cannot access user sessions
MemorySessions decrypted only in RAM during requests

Compliance Considerations

GDPR / Data Privacy

  • User sessions are encrypted and cannot be accessed without tokens
  • Tokens can be revoked at any time, making data irrecoverable
  • Right to deletion: revoke tokens and delete from your database

Security Audits

If your organization requires security documentation:

  • Our OAuth implementation follows RFC 6749 (OAuth 2.0)
  • Envelope encryption provides defense-in-depth
  • Zero-knowledge architecture limits blast radius of breaches

Reporting Security Issues

If you discover a security vulnerability:

  1. Do not disclose it publicly
  2. Email security concerns to the development team
  3. Include steps to reproduce
  4. We'll respond within 48 hours

Key Takeaways

  1. We can't see your users' sessions - envelope encryption ensures this
  2. Database breaches don't expose sessions - encrypted data is useless without tokens
  3. You must secure your tokens - they're the keys to the kingdom
  4. Revocation is immediate and permanent - when tokens are revoked, sessions become unrecoverable