Security Architecture
PoW-anchored session security with cryptographic binding
Three-Tier Security Model
Memescale implements a comprehensive three-tier security architecture built on Proof of Work gating, cryptographic session binding, and continuous validation.
Our security architecture requires three independent proofs for every authenticated request. This triplet approach ensures that even if one component is compromised, additional layers continue to protect your account.
| Tier | Name | Primary Function | Key Components |
|---|---|---|---|
| Tier 1 | Entry Gate | Proof of Work verification | PoW challenge, pow_valid cookie, computational proof |
| Tier 2 | Identity | User authentication & session binding | JWT token, powxd derivation, browser fingerprint |
| Tier 3 | Enforcement | Continuous validation & revocation | HMAC reconstruction, session management, WebSocket sync |
Tier 1: Entry Gate
Every visitor must complete a Proof of Work challenge before accessing the site. This computational barrier blocks automated attacks and bots while being nearly invisible to legitimate users.
- PoW Challenge: Server issues random challenge requiring 4 leading zeros in SHA-256 hash
- Web Worker Computation: Browser computes nonce in background thread
- pow_valid Cookie: HMAC-signed cookie proves work was completed, contains powId
- Challenge-Nonce-Result Storage: Server stores proof for session binding
Tier 2: Identity Binding
When you log in, your identity becomes cryptographically bound to your PoW proof. The powxd cookie is mathematically derived from your PoW computation, user ID, and session ID - it cannot be forged.
- JWT Session: Contains userId, username, and unique session ID (sid)
- powxd Derivation: HMAC-SHA256 of challenge|nonce|resultHash|userId|sid|timestamp
- Browser Fingerprint: Browser name + truncated major version stored with session
- 128-bit Secret: powxd is 32 hex characters, cryptographically secure
Tier 3: Continuous Enforcement
Every API request validates all three cookies and reconstructs the expected powxd to verify authenticity. Sessions can be revoked instantly via WebSocket notification.
- HMAC Reconstruction: Server rebuilds powxd from stored components, compares to cookie
- Browser Validation: Current browser fingerprint must match stored fingerprint
- Session Management: View all sessions, revoke individually or all at once
- WebSocket Revocation: Instant logout notification when session is terminated
Each tier operates independently. Missing any cookie blocks access. Browser mismatch blocks access. HMAC mismatch blocks access. An attacker must defeat all three tiers simultaneously.
Defense in Depth Strategy
Defense in depth means that compromising one security control doesn't grant full access. The session triplet requires all three cookies, cryptographic reconstruction, and browser validation to pass.
Our defense in depth strategy requires multiple independent validations before any request proceeds. An attacker would need to defeat all validations simultaneously, which is computationally infeasible.
Attack Surface Reduction
We minimize attack surface by using httpOnly cookies (JavaScript cannot access), constant-time signature comparison (prevents timing attacks), and reconstruction-based validation (Redis tampering is detected).
| Attack Vector | Primary Defense | Secondary Defense | Tertiary Defense |
|---|---|---|---|
| Session Hijacking | httpOnly cookies | Browser fingerprint validation | HMAC reconstruction |
| Credential Stuffing | Proof of Work gate | Rate limiting (10 failures/60s) | 5-minute block after limit |
| Session Fixation | New powxd per login | sid in JWT unique per session | Browser binding |
| Replay Attacks | Timestamp in HMAC | 7-day session TTL | Browser mismatch detection |
| Brute Force powxd | 128-bit entropy | 2^128 attempts needed | Rate limiting |
Our architecture assumes any single control can be bypassed. The session triplet means stealing the JWT alone, or pow_valid alone, or even both together without powxd, grants zero access.
Zero Trust Principles
Memescale operates on zero trust principles: never trust, always verify. Every request must prove its legitimacy through all three cookies, matching browser fingerprint, and successful HMAC reconstruction.
Zero trust means we don't trust any request by default. Every API call must present all three cookies, pass browser validation, and survive HMAC reconstruction. There are no shortcuts.
Core Zero Trust Principles
- Verify Explicitly: Every request validated through withApiAuth middleware with full triplet check
- Least Privilege Access: Sessions only access resources owned by that userId
- Assume Breach: Browser mismatch instantly blocks access, no grace period
- Continuous Validation: HMAC reconstruction happens on every single request, not just login
- No Stored Trust: Server reconstructs powxd rather than trusting stored value
Validation Flow Per Request
| Step | Check | Failure Result | HTTP Status |
|---|---|---|---|
| 1 | pow_valid cookie exists and valid | POW_REQUIRED | 429 |
| 2 | JWT session exists | NOT_AUTHENTICATED | 401 |
| 3 | powxd cookie exists | MISSING_POWXD | 401 |
| 4 | Session exists in Redis | SESSION_NOT_FOUND | 401 |
| 5 | userId matches session | SESSION_REBIND_NEEDED | 401 |
| 6 | Browser fingerprint matches | BROWSER_MISMATCH | 403 |
| 7 | HMAC reconstruction matches | INVALID_PROOF | 401 |
| 8 | PoW still valid (4 zeros) | POW_FAILED | 401 |
All validation happens server-side in milliseconds. Legitimate users experience seamless access while attackers are blocked at multiple checkpoints.
The withApiAuth middleware wraps every protected API route, automatically performing all validation steps. Routes can optionally require folder ownership or bot ownership for additional authorization.
Security Boundaries
Clear security boundaries separate unauthenticated entry, authenticated access, and sensitive operations. Each boundary requires passing specific validation gates.
Security boundaries define where trust ends and verification begins. Moving from one zone to another requires passing through validation gates that verify the appropriate level of authentication.
Trust Zones
Boundary Enforcement
- PoW-only routes use withPowOnly wrapper - only checks pow_valid cookie
- Authenticated routes use withApiAuth wrapper - validates full session triplet
- Bot routes use requireBotOwnership option - verifies user owns the bot
- Admin routes require ADMIN_ACCESS_CODE and IP in ADMIN_ALLOWED_IPS
Data Isolation
User data is strictly isolated using Redis key prefixing. A session for user A cannot access data belonging to user B. All security keys use the {auth} prefix for Redis cluster slot co-location.
{auth}:pow_session:{powId} -> Session data with binding components
{auth}:pow_proof:{powId} -> PoW challenge, nonce, resultHash
{auth}:user:{userId} -> User profile
{auth}:user_pow_sessions:{id} -> Set of user's active powIdsThe {auth} prefix ensures all security-related keys are stored in the same Redis cluster slot, enabling atomic operations across related data while maintaining isolation between users.
Two-Factor Authentication
Your most important account protection
Why 2FA is Critical
Two-Factor Authentication (2FA) is the single most effective protection against unauthorized account access. Even if your password is compromised, 2FA prevents attackers from logging in.
Your password is only the first line of defense. Passwords can be stolen through phishing, data breaches at other services, or malware. Two-Factor Authentication adds a second, independent verification that only you possess: a time-based code from your phone.
We strongly recommend enabling 2FA on your account immediately. Accounts with 2FA enabled are virtually immune to password-based attacks, which represent over 80% of account compromises.
How 2FA Protects You
| Attack Type | Without 2FA | With 2FA |
|---|---|---|
| Password Stolen | Full account access | Blocked - attacker lacks code |
| Phishing Attack | Credentials captured | Blocked - code expires in 30 seconds |
| Data Breach | Password may be exposed | Blocked - secret key not in breach |
| Credential Stuffing | If password reused, compromised | Blocked - unique codes per account |
| Session Hijacking | May succeed | Blocked - new logins require 2FA |
The Statistics
- 99.9% of automated attacks are blocked by 2FA (Google Security Research)
- Accounts with 2FA are 50x less likely to be compromised
- Most successful breaches occur on accounts without 2FA enabled
- 2FA provides protection even if the same password is used elsewhere
Enabling 2FA takes less than 2 minutes and provides permanent protection. There is no security measure with a better effort-to-protection ratio.
How TOTP Works
Memescale uses Time-based One-Time Passwords (TOTP), the industry standard for 2FA. A secret key shared between your authenticator app and our servers generates synchronized 6-digit codes.
TOTP (Time-based One-Time Password) is an open standard used by banks, tech companies, and security-conscious organizations worldwide. It generates a new 6-digit code every 30 seconds based on the current time and a shared secret.
The TOTP Algorithm
- During setup, a unique 32-character secret key is generated for your account
- You scan a QR code that transfers this secret to your authenticator app
- Both your app and our server use the same formula: HMAC-SHA1(secret, time/30)
- This produces a 6-digit code that changes every 30 seconds
- Codes are only valid for a short window (typically 30-60 seconds)
Security Properties
TOTP codes are generated entirely on your device. Your authenticator app doesn't need internet access to generate valid codes, and the secret never leaves your device after initial setup.
Why TOTP is Secure
- Codes expire in 30 seconds - stolen codes become useless almost immediately
- The secret key is never transmitted after initial setup
- Each code can only be used once (replay protection)
- Time synchronization prevents code reuse from the past
- The secret is stored encrypted, never in plaintext
Setting Up 2FA
Enable 2FA in your Account Settings. You'll need an authenticator app like 2FA Authenticator (iOS), Aegis Authenticator (Android), or KeePassXC (Desktop) to scan the QR code and generate codes.
Setting up 2FA is straightforward and takes about 2 minutes. Once enabled, you'll need both your password and a code from your authenticator app to log in.
Step-by-Step Setup
- Navigate to Account Settings by clicking your username
- Select the '2FA' tab in the Account Modal
- Click 'Setup 2FA' to begin the process
- A QR code will appear on screen
- Open your authenticator app and scan the QR code
- Enter the 6-digit code displayed in your app
- 2FA is now active on your account
Recommended Authenticator Apps
We recommend open-source, privacy-respecting authenticator apps that don't require accounts or collect telemetry. These apps keep your secrets local and under your control.
Mobile Apps
| App | Platform | Backup Feature | Why We Recommend |
|---|---|---|---|
| 2FA Authenticator (2FAS) | iOS | iCloud backup | Open source, no account required, clean interface, audited code |
| Aegis Authenticator | Android | Encrypted local export | Open source, local-first storage, strong encryption, no cloud dependency |
Desktop Apps (Local/Offline)
| App | Platform | Backup Feature | Why We Recommend |
|---|---|---|---|
| KeePassXC | MacOS | Local encrypted vault | Open source, offline-only, integrates with password management, highly audited |
| KeePassXC | Windows | Local encrypted vault | Open source, offline-only, no network access required, maximum privacy |
All recommended apps are open source, meaning their code can be publicly audited for security. They don't require creating accounts with third parties, don't phone home with telemetry, and keep your TOTP secrets encrypted locally or with zero-knowledge cloud sync. This contrasts with proprietary alternatives that may collect usage data or store secrets on servers they control.
When you see the QR code during setup, consider taking a secure screenshot or writing down the text secret. Store this backup in a secure location (like a safe or encrypted file). If you lose your phone, this backup allows you to restore 2FA access.
After Setup
Once 2FA is enabled, every login will require both your password and the current 6-digit code from your authenticator app. The code changes every 30 seconds, so make sure to enter the current code displayed.
KeePassXC Setup Walkthrough
KeePassXC is a desktop password manager that supports TOTP authentication. Unlike mobile apps that scan QR codes, KeePassXC requires manual entry of your secret key. This guide walks you through the complete setup process for both Windows and MacOS.
KeePassXC handles TOTP differently from mobile authenticator apps. Instead of scanning a QR code with your camera, you'll manually enter the secret key that's displayed below the QR code during 2FA setup. This approach offers maximum security since your TOTP secrets never leave your local machine and are stored in an encrypted vault.
Step 1: Create a Root Entry
Before you can configure TOTP, you need to create an entry in your KeePassXC database to store your Memescale credentials and authentication codes.
- Open KeePassXC and unlock your database (or create a new one if you haven't already)
- In the main window, click 'Entries' in the menu bar, then select 'New Entry' (or press Ctrl+N on Windows, Cmd+N on MacOS)
- In the 'Title' field, enter a recognizable name such as 'Memescale' or 'Memescale 2FA'
- Optionally fill in the 'Username' and 'URL' fields for reference
- Click 'OK' to save the entry
Step 2: Configure TOTP for the Entry
Now that you have an entry, you'll configure it to generate TOTP codes using the secret key provided during Memescale's 2FA setup process.
- Locate your newly created entry in the entry list
- Right-click on the entry to open the context menu
- Hover over the 'TOTP' option in the context menu
- Click 'Set Up TOTP...' from the submenu
- A dialog box will appear asking for the Secret Key
- Copy the 'Manual' key displayed below the QR code on the Memescale 2FA setup screen
- Paste the secret key into the 'Secret Key' field in KeePassXC
- Leave the default settings (6 digits, 30 second interval)
- Click 'OK' to save the TOTP configuration
During Memescale's 2FA setup, you'll see a QR code and below it a 'Manual' field with a long alphanumeric string. This is your secret key. Click the 'Copy' button next to it to copy the key to your clipboard, then paste it into KeePassXC.
Step 3: Generate and Copy TOTP Codes
Once TOTP is configured, you can generate 6-digit codes whenever you need to log in to Memescale with 2FA enabled.
- In your KeePassXC database, locate the Memescale entry you created
- Double-click on the entry to open it, or right-click to access the context menu
- Hover over the 'TOTP' option in the context menu
- Click 'Copy TOTP' to copy the current 6-digit code to your clipboard
- Paste this code into the 2FA verification field on Memescale
- Note: TOTP codes refresh every 30 seconds, so enter the code promptly after copying
For faster access, you can use the keyboard shortcut Ctrl+T (Windows) or Cmd+T (MacOS) to copy the TOTP code for the currently selected entry. This is especially useful when logging in frequently.
Verifying Your Setup
After configuring TOTP in KeePassXC, you'll need to verify it works by entering a generated code back on the Memescale 2FA setup screen.
- Generate a TOTP code from KeePassXC using the steps above
- Enter the 6-digit code in the verification field on Memescale's 2FA setup page
- If the code is accepted, your 2FA setup is complete
- If the code is rejected, double-check that you copied the secret key correctly and try again with a fresh code
Your KeePassXC database contains your TOTP secrets. Make sure to back up your .kdbx database file securely. If you lose access to this file and don't have the secret key backed up elsewhere, you may be locked out of your account. Store backups in a secure location separate from your main computer.
Logging In with 2FA
When 2FA is enabled, login becomes a two-step process. First enter your password, then enter the code from your authenticator app.
The 2FA login flow adds minimal friction while dramatically improving security. You'll enter your password first, then be prompted for your authenticator code.
Login Sequence with 2FA
- Enter your username and password on the login page
- If credentials are correct and 2FA is enabled, you'll see the 2FA prompt
- Open your authenticator app and find the Memescale entry
- Enter the 6-digit code displayed (it changes every 30 seconds)
- If the code is valid, you're logged in successfully
Code Timing
TOTP codes change every 30 seconds. If your code is about to expire (shown in most apps with a countdown), wait for the new code to appear. We accept codes from the current period and one previous period to account for minor time differences.
If your code is rejected, check that your phone's time is set to automatic. TOTP relies on synchronized time between your device and our servers. A clock that's off by more than 30 seconds can cause code validation failures.
Failed Attempts
Multiple failed 2FA attempts are logged and may trigger security alerts. This protects against attackers who have your password but are trying to guess or brute-force your 2FA codes.
2FA Recovery
If you lose access to your authenticator app, recovery options are available. Proper backup of your 2FA secret during setup prevents lockout scenarios.
Losing access to your authenticator app doesn't have to mean losing access to your account. However, recovery requires proof of identity since 2FA is specifically designed to prevent unauthorized access.
Prevention is Best
- Use an authenticator app with backup support (Aegis or KeePassXC for local encrypted exports)
- Save the text secret or QR code during setup in a secure location
- Consider using multiple devices with the same secret for redundancy
- Test your backup by verifying codes match on both devices
If You're Locked Out
- If you have your backup secret: Add it to a new authenticator app manually
- If you have another device with the secret: Use that device to generate codes
- If neither option works: Contact support with proof of account ownership
Account recovery without 2FA codes requires verification of your identity and account ownership. This process is intentionally thorough to prevent social engineering attacks where someone impersonates you to disable your 2FA.
Disabling 2FA
If you have access to your account and want to disable 2FA (not recommended), you can do so from Account Settings. You'll need to enter your password and a valid 2FA code to confirm the action. This prevents attackers who might have stolen your session from disabling 2FA.
2FA Security Events
All 2FA-related actions are logged in your security audit trail. You can review when 2FA was enabled, disabled, or when login attempts with invalid codes occurred.
Every 2FA interaction is recorded for security and transparency. These logs help you identify unauthorized access attempts and verify that your 2FA configuration hasn't been tampered with.
Logged Events
| Event | Details Recorded | Alert Generated |
|---|---|---|
| 2FA Enabled | Timestamp, IP, Device | Yes - confirmation |
| 2FA Disabled | Timestamp, IP, Device | Yes - warning |
| Successful 2FA Login | Timestamp, IP, Device | No |
| Failed 2FA Attempt | Timestamp, IP, Attempt count | After 3 failures |
| 2FA Code Brute Force | IP, Attempt pattern | Immediate + lockout |
Monitoring Your Account
- Review your active sessions regularly in Account Settings
- Check for sessions from unfamiliar locations or devices
- If you see suspicious activity, revoke sessions and change your password
- Failed 2FA attempts from unknown IPs indicate someone has your password - change it immediately
When we detect unusual 2FA activity (like repeated failures from a new location), you'll receive a security alert. These alerts help you respond quickly to potential compromise attempts.
Real-Time Session Protection
Instant security with WebSocket technology
Instant Session Revocation
When you revoke a session from your account settings, that session is terminated immediately - not in seconds, but in milliseconds. This instant protection is powered by WebSocket technology.
Traditional session management relies on periodic checks - your browser asks the server 'am I still logged in?' every few seconds. This creates a dangerous window where a compromised session could continue to operate after you've revoked it.
When you click 'Revoke Session', the target device receives the notification in under 100 milliseconds - that's faster than the blink of an eye. Compare this to traditional polling which could take 5-30 seconds.
The Revocation Timeline
| Event | Time | What Happens |
|---|---|---|
| You click 'Revoke' | 0ms | Request sent to server |
| Server processes | 10-50ms | Session marked as revoked in database |
| WebSocket broadcast | 50-100ms | All connected tabs notified instantly |
| Session terminated | 100-150ms | User sees 'Session Ended' modal |
| Fallback check | 5000ms | Heartbeat confirms revocation (backup) |
This speed matters in security emergencies. If you suspect someone has access to your account, every second counts. Instant revocation ensures that the moment you take action, the threat is neutralized.
How WebSocket Protection Works
WebSockets create a persistent, two-way connection between your browser and our servers. This allows us to push security notifications to you instantly, rather than waiting for your browser to ask.
When you log in, your browser establishes a WebSocket connection alongside your regular session. This connection stays open, allowing the server to send you messages at any time - including the critical 'your session has been revoked' notification.
Connection Lifecycle
- You log in successfully with your credentials (and 2FA if enabled)
- Your browser establishes a secure WebSocket connection
- The connection authenticates using your session credentials
- The server registers your connection for security notifications
- If any security event occurs, you're notified immediately
- On logout or session end, the connection closes cleanly
Security Events Delivered via WebSocket
| Event Type | Trigger | Your Experience |
|---|---|---|
| Session Revoked | You revoke a session from another device | Target device shows 'Session Ended' modal |
| All Sessions Revoked | You click 'Logout Everywhere' | All other devices logged out instantly |
| Security Alert | Suspicious activity detected | Warning notification displayed |
| Forced Logout | Password changed or 2FA enabled | All sessions terminated for security |
If you have multiple tabs open, all of them receive the revocation notification simultaneously. You won't have a 'stale' tab that stays logged in after you've revoked the session.
Connection Security
WebSocket connections are protected by multiple security layers: encryption, authentication, zombie detection, and connection limits prevent abuse while ensuring reliable delivery.
Every WebSocket connection must prove its identity before receiving security notifications. This prevents attackers from listening in on your revocation events or establishing unauthorized connections.
Authentication Requirements
- Connections must authenticate within 10 seconds or be terminated
- Authentication uses the same secure session token as your regular browsing
- Invalid or expired tokens result in immediate connection rejection
- Each connection is tied to a specific session - no cross-session access
Zombie Connection Detection
Sometimes connections appear open but are actually dead - the network dropped, the device went to sleep, or the browser crashed. These 'zombie' connections could receive notifications that never reach you.
If your connection doesn't respond to a ping within 10 seconds, we know it's a zombie and terminate it. This ensures that when we send a revocation notification, it actually reaches a live connection.
Connection Limits
To prevent resource abuse, we limit the number of WebSocket connections per session and per user:
| Limit Type | Maximum | What Happens When Exceeded |
|---|---|---|
| Per Session (same browser) | 10 connections | Oldest connection evicted |
| Per User (all sessions) | 50 connections | Oldest connection evicted |
When you exceed connection limits, we don't reject new connections - we close the oldest one. This ensures your most recent tabs always have real-time protection.
Fallback Protection
WebSocket is our primary notification channel, but we maintain a heartbeat fallback to ensure you're protected even if WebSocket connections fail.
No technology is perfect. Network issues, firewalls, or proxy servers might block WebSocket connections. That's why we implement a defense-in-depth strategy with multiple protection layers.
Two-Layer Protection
- Primary: WebSocket for instant notification (< 100ms)
- Fallback: Heartbeat polling every 5 seconds
- If WebSocket fails, heartbeat continues protecting you
- If heartbeat detects revocation, session ends immediately
Even in the worst case where WebSocket is unavailable, a revoked session will be terminated within 5 seconds. This is still much faster than traditional session management.
Automatic Reconnection
If your WebSocket connection drops unexpectedly, your browser automatically attempts to reconnect with exponential backoff:
| Attempt | Delay | Notes |
|---|---|---|
| 1st retry | 3 seconds | Most drops are temporary |
| 2nd retry | 6 seconds | Increasing delay |
| 3rd retry | 12 seconds | Network may be recovering |
| 4th retry | 24 seconds | Extended wait |
| 5th retry | 48 seconds | Final attempt before giving up |
After 5 failed attempts, we stop retrying to avoid battery drain and unnecessary network requests. The heartbeat fallback continues protecting you during this time.
Enterprise-Grade Reliability
Our infrastructure is designed to scale across multiple servers while maintaining instant revocation guarantees. Redis Pub/Sub ensures revocation messages reach all servers simultaneously.
As our platform grows, your WebSocket connection might be handled by any one of our servers. When you revoke a session, we need to notify all servers instantly so the notification reaches the right connection.
How Multi-Server Revocation Works
- You click 'Revoke Session' from Server A
- Server A marks the session as revoked in the database
- Server A publishes to Redis: 'Session XYZ revoked for User 123'
- All servers (A, B, C, D) receive this message instantly
- Each server checks if it has WebSocket connections for that session
- The server with the connection sends the revocation notification
Redis Pub/Sub provides sub-millisecond message delivery between servers. This ensures that no matter which server handles your revocation request, the notification is delivered instantly.
Reliability Guarantees
| Scenario | Outcome | Fallback |
|---|---|---|
| Target server online | Instant notification via Pub/Sub | N/A |
| Target server offline | No WebSocket delivery | Heartbeat catches it in 5s |
| Redis temporarily unavailable | Direct notification if same server | Heartbeat fallback |
| Network partition | Revocation stored in database | Heartbeat validates against DB |
Our architecture prioritizes safety: even if real-time delivery fails, the session is always revoked in the database. The heartbeat ensures this revocation is eventually enforced.
What You See When Sessions Are Revoked
When a session is revoked, the affected device sees a clear modal explaining what happened and providing next steps.
We designed the revocation experience to be informative without being alarming. You'll know exactly what happened and what to do next.
The Revocation Modal
When your session is revoked (either by you from another device, or by our security systems), you'll see a modal with:
- Clear explanation: 'Your session has been ended'
- Reason: 'Revoked from another device' or 'Security policy'
- Next steps: Option to log in again
- Security recommendation: Change password if you didn't initiate this
If you see a revocation modal and you didn't revoke the session yourself, this could indicate someone else accessed your account and is now locked out. Change your password immediately and enable 2FA if you haven't already.
After Revocation
Once revoked, the session cannot be restored. Any attempt to use that session's credentials will fail. You'll need to log in fresh with your current password (and 2FA code if enabled).
Protecting Your Account
Using your security tools effectively
Your Sessions Dashboard
The Sessions tab in your Account Settings shows every device and browser currently logged into your account. This is your command center for monitoring and controlling account access.
Every time you log in from a new device or browser, a session is created. The Sessions tab gives you complete visibility into all active sessions, helping you spot unauthorized access and take immediate action.
What You'll See
Each session entry displays:
- Device type (Desktop, Mobile, Tablet)
- Browser name and version (Chrome, Firefox, Safari, etc.)
- Operating system (Windows, macOS, iOS, Android, Linux)
- IP address (partially masked for privacy)
- When the session was created
- Last activity timestamp
- Risk level indicator (Safe, Suspicious, Dangerous)
Your current session is always marked with a 'Current' badge and appears at the top of the list. You cannot revoke your current session - use 'Logout' for that.
Risk Level Indicators
| Level | Indicator | Meaning |
|---|---|---|
| Safe | Green | Session fingerprint matches - normal activity |
| Suspicious | Yellow | Minor fingerprint changes detected - could be VPN or browser update |
| Dangerous | Red | Multiple fingerprint anomalies - possible session hijacking |
A 'Dangerous' risk level doesn't always mean your account is compromised, but it's worth investigating. Review the device details and revoke the session if you don't recognize it.
Responding to a Breach
If you suspect unauthorized access, act quickly and methodically. Here's the step-by-step process for securing your account.
Time is critical when responding to a potential breach. Follow these steps in order to minimize damage and secure your account.
Immediate Response Steps
- Go to Account Settings > Sessions
- Review all active sessions for anything you don't recognize
- Click 'Revoke All Other Sessions' to terminate all sessions except your current one
- Change your password immediately to a strong, unique password
- Enable Two-Factor Authentication if not already enabled
- Review your security log for any suspicious activity
- Check your account for any unauthorized changes
Revoking sessions terminates the attacker's access instantly - within 100ms. Changing your password takes longer and the attacker might be actively using the stolen session during that time. Revoke first to stop the bleeding, then change your password to prevent re-entry.
After Securing Your Account
- Review your recent activity for any actions you didn't take
- Check if your email address has been changed
- Verify your payment methods haven't been modified
- Look for any new API keys or integrations you didn't create
- Consider how the breach occurred - was your password reused elsewhere?
Preventing Future Breaches
After recovering from a breach, take steps to prevent it from happening again:
- Enable 2FA - this single action blocks 99.9% of automated attacks
- Use a password manager to generate and store unique passwords
- Never reuse passwords across different services
- Be cautious of phishing emails asking for your credentials
- Regularly review your active sessions
- Log out from shared or public computers
Revoking Sessions
Learn the different ways to revoke sessions and when to use each approach for maximum security.
You have several options for revoking sessions, each suited to different situations.
Revoke Single Session
Use this when you want to end access for a specific device while keeping other sessions active.
- Open Account Settings > Sessions
- Find the session you want to revoke
- Click the 'Revoke' button next to it
- Confirm the action in the popup
- The session is terminated instantly
Revoke All Other Sessions
Use this during a security emergency or when you want to start fresh with only your current device logged in.
- Open Account Settings > Sessions
- Click 'Revoke All Other Sessions'
- Confirm the action (requires password if you have sessions with 'Dangerous' risk)
- All sessions except your current one are terminated instantly
You cannot revoke your current session from the Sessions tab - this is intentional to prevent accidental lockout. To end your current session, use the standard 'Logout' option.
Post-Revocation Confirmation
After revoking sessions, especially during a security event, you'll be offered the option to:
- Change your password immediately
- View details about the revoked session (browser, IP, device)
- Enable 2FA if not already active
Daily Security Habits
Good security isn't just about responding to threats - it's about habits that prevent threats in the first place.
Developing good security habits reduces your risk of account compromise and makes it easier to spot problems when they occur.
The Security Essentials Checklist
- Enable Two-Factor Authentication - non-negotiable
- Use a unique, strong password (16+ characters, mixed case, numbers, symbols)
- Never share your password or 2FA codes with anyone
- Log out from devices you no longer use
- Review your sessions weekly
- Keep your devices and browsers updated
Password Security
| Practice | Why It Matters |
|---|---|
| Unique password per service | A breach at one service doesn't affect others |
| 16+ characters | Longer passwords are exponentially harder to crack |
| No personal information | Attackers research targets and try personal info first |
| Use a password manager | Generates and stores strong unique passwords |
| Change after a breach | Prevents continued access if credentials are leaked |
A password manager like 1Password, Bitwarden, or KeePass can generate and store unique passwords for every service. Many also support storing 2FA secrets as a backup.
Session Hygiene
- Log out when done on shared/public computers
- Use private/incognito mode on untrusted devices
- Revoke sessions you no longer need
- Set calendar reminders to review sessions monthly
- Pay attention to login notification emails
Your Security Audit Log
Every security-related action on your account is logged. This audit trail helps you understand what happened and when, especially during incident investigation.
We maintain a comprehensive log of security events for your account. This log is immutable - once an event is recorded, it cannot be modified or deleted.
Events We Log
| Event Type | Details Recorded |
|---|---|
| Successful Login | Timestamp, IP, Device, Browser, 2FA used |
| Failed Login | Timestamp, IP, Reason (wrong password, invalid 2FA, etc.) |
| Password Changed | Timestamp, IP, Device |
| 2FA Enabled/Disabled | Timestamp, IP, Device |
| Session Created | Timestamp, IP, Device, Session ID |
| Session Revoked | Timestamp, IP, Who revoked (user/system), Session ID |
| Fingerprint Mismatch | Timestamp, IP, What changed, Severity |
Using the Audit Log
The audit log is available in your Account Settings under the 'Security' tab. Use it to:
- Verify that only you have been logging in
- Check the times and locations of recent logins
- Investigate suspicious activity alerts
- Confirm that sessions you revoked were actually terminated
- Review failed login attempts (could indicate attack attempts)
Security logs are retained for 90 days. After 90 days, older entries are automatically removed. Important security events (password changes, 2FA changes) may be retained longer for compliance purposes.
Session Management
PoW-anchored session lifecycle and control
Session Lifecycle
Sessions are created at login, validated on every request, and can be revoked instantly. Each login creates a unique session bound to your browser.
Every session in Memescale is anchored to a Proof of Work computation and bound to your browser. Sessions are stored in Redis with automatic expiration after 7 days of inactivity.
Session States
| State | Description | Duration | User Experience |
|---|---|---|---|
| Creating | PoW verified, login in progress | Milliseconds | Login form processing |
| Active | Fully bound and operational | Up to 7 days | Normal access to dashboard |
| Rebind Needed | Account switch detected | Until reinit | Automatic re-initialization |
| Expired | 7 days without activity | N/A | Redirect to login |
| Revoked | Explicitly terminated | N/A | Immediate logout via WebSocket |
State Transitions
- Login -> Active: PoW verified, JWT created, powxd derived and cookie set
- Active -> Rebind Needed: Different userId in JWT than session (account switch)
- Rebind Needed -> Active: Client calls init-session to rebind
- Active -> Expired: No activity for 7 days, Redis TTL expires
- Active -> Revoked: User clicks Revoke, or password changed, or admin action
Session activity is updated at most every 5 minutes to avoid excessive Redis writes. Your session remains valid as long as you use the site within the 7-day window.
Token Architecture
Session security relies on three tokens: powId (PoW anchor), JWT (identity), and powxd (cryptographic binding). Each serves a distinct security purpose.
Memescale uses three distinct tokens that work together. Unlike traditional systems with a single session cookie, our triplet ensures no single token grants access.
Token Types
| Token | Length | Purpose | TTL | Storage |
|---|---|---|---|---|
| powId | UUID (36 chars) | PoW session anchor | 7 days | pow_valid cookie + Redis |
| JWT | Variable | User identity claim | 7 days | HTTP-only cookie |
| powxd | 128-bit (32 hex) | Cryptographic binding | 7 days | HTTP-only cookie |
| sid | UUID (36 chars) | JWT session ID | 7 days | Inside JWT payload |
Token Generation
The powId and sid are generated using UUID v4 (cryptographically random). The powxd is not random - it is derived using HMAC-SHA256 from your PoW proof combined with your userId and sid.
powId: 550e8400-e29b-41d4-a716-446655440000 (UUID)
sid: 7c9e6679-7425-40de-944b-e07fc1f90ae7 (UUID)
powxd: a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6 (32 hex chars)
JWT: eyJhbGciOiJIUzI1NiIs... (signed payload)Token Security Properties
- Entropy: 128 bits for powxd, 122 bits for UUIDs
- Derivation: powxd is HMAC-derived, cannot be guessed
- Binding: powxd is bound to specific userId + sid + PoW proof
- Verification: Server reconstructs expected powxd on every request
- Isolation: Each login generates new sid, therefore new powxd
All three tokens are transmitted via httpOnly cookies with Secure and SameSite=Lax flags. They cannot be accessed by JavaScript and are only sent over HTTPS connections.
Secure Session Storage
Session data is stored in Redis with all binding components needed for HMAC reconstruction. The powxd value itself is NOT stored - only the components to derive it.
Session data is stored server-side in Redis, keyed by powId. The critical security property: we store the binding components (challenge, nonce, resultHash, userId, sid, timestamp) and reconstruct powxd on every request rather than storing it.
Session Data Structure
{
"powId": "550e8400-e29b-41d4-a716-446655440000",
"userId": "user_abc123",
"username": "johndoe",
"powXdHash": "sha256:abc123...",
"challenge": "random_challenge_string",
"nonce": "12345678",
"resultHash": "0000abcd...",
"sid": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"bindingTimestamp": 1706123456789,
"createdAt": "2024-01-15T10:30:00Z",
"lastActivity": "2024-01-15T14:22:00Z",
"ipHistory": [{"ip": "192.168.1.1", "firstSeen": "...", "lastSeen": "...", "requestCount": 42}],
"browser": "Chrome",
"browserVersion": "12",
"os": "Windows"
}Storage Security
- Sessions expire automatically via Redis TTL after 7 days
- powxd is never stored - only the hash for audit logging
- IP history limited to 20 entries (oldest removed first)
- Browser version truncated to first 2 digits of major version
We store binding components rather than the powxd itself. Even if Redis is compromised, the attacker cannot use stored data without knowing the server's HMAC secret.
Browser Binding
Sessions are bound to your browser using a fingerprint of browser name + truncated version. Using stolen cookies from a different browser is detected and blocked.
Browser binding is a critical security feature. When you log in, we store your browser's fingerprint (name + version). Every subsequent request must come from the same browser type, or the session is rejected.
Binding Mechanism
- At login, server parses User-Agent header to extract browser info
- Browser name (Chrome, Firefox, Safari, etc.) is stored
- Browser version is truncated to first 2 digits of major version
- Fingerprint = browser + truncated version (e.g., 'Chrome12')
- On each request, current fingerprint is compared to stored
- Mismatch returns BROWSER_MISMATCH error with 403 status
Fingerprint Examples
| User Agent Version | Truncated | Fingerprint | Match With |
|---|---|---|---|
| Chrome/120.0.6099.129 | 12 | Chrome12 | Chrome12 only |
| Chrome/125.0.6422.60 | 12 | Chrome12 | Chrome12 only |
| Firefox/121.0 | 12 | Firefox12 | Firefox12 only |
| Safari/17.2.1 | 17 | Safari17 | Safari17 only |
We only use the first 2 digits of the major version. This allows browser updates (120 to 125) without invalidating your session, while still catching cross-browser attacks (Chrome vs Firefox).
Why Not Full Fingerprinting?
Session Visibility & Control
The security dashboard displays all active sessions with device information and last activity. You can terminate any session instantly, with real-time logout via WebSocket.
Session visibility gives you complete control over where your account is logged in. The dashboard shows every active session with browser, OS, IP addresses used, and activity timestamps.
Session Information Displayed
- Browser: Browser name (Chrome, Firefox, Safari, Edge, etc.)
- Operating System: Windows, macOS, Linux, iOS, Android, etc.
- IP Addresses: All IPs used with this session (masked for privacy)
- Created: When the session was established
- Last Active: Most recent request timestamp
- Current Session: Badge indicating which session you're using now
Session Control Actions
| Action | Scope | Effect | Requires Re-auth |
|---|---|---|---|
| View Sessions | All | Display session list | No |
| Terminate Session | Single | Immediate revocation + WebSocket logout | No |
| Terminate All Others | All except current | Bulk revocation | No |
| Terminate All | All including current | Full logout everywhere | No |
When you terminate a session, a WebSocket message is sent immediately. The user on that device sees a 'Session Revoked' message and is redirected to the login page within seconds.
Session Limits
You can have up to 10 active sessions. When you create an 11th session, the oldest session is automatically revoked. This prevents session accumulation while allowing reasonable multi-device use.
Session Revocation
Session revocation is immediate and irreversible. Revoked sessions are deleted from Redis, logged to audit trail, and the user is notified via WebSocket.
When a session is revoked, it is immediately and permanently terminated. The session data is removed from Redis, a WebSocket notification is sent for instant logout, and an audit event is logged.
Revocation Triggers
- User Action: Click 'Revoke' button in session list
- Logout: Explicit logout revokes the current session
- Session Limit: 11th session auto-revokes the oldest
- Password Change: All other sessions revoked (security best practice)
- Admin Action: Administrator can revoke any user's sessions
- System Detection: Browser mismatch or validation failure
Revocation Process
- Session removed from user's session set ({auth}:user_pow_sessions:{userId})
- Session data deleted from Redis ({auth}:pow_session:{powId})
- WebSocket notification sent: {type: 'session_revoked', powId}
- Audit event logged with revocation reason and metadata
- Note: pow_proof is NOT deleted (user can log in again with same pow_valid)
Revocation takes effect within milliseconds. The next API request from the revoked session will fail with SESSION_NOT_FOUND (401). There is no grace period.
Browser Validation
Session binding through browser fingerprinting
Fingerprint Components
Memescale uses a lightweight browser fingerprint consisting of browser name and truncated version. This provides security without invasive tracking.
Unlike traditional fingerprinting systems that collect dozens of attributes, Memescale uses a simple but effective approach: we identify your browser by name and major version. This catches cross-browser attacks while respecting your privacy.
What We Collect
| Component | Source | Example | Purpose |
|---|---|---|---|
| Browser Name | User-Agent parsing | Chrome, Firefox, Safari | Detect browser type change |
| Browser Version | User-Agent parsing | 120.0.6099.129 | Raw version extracted |
| Truncated Version | First 2 digits of major | 12 | Stored for comparison |
| Operating System | User-Agent parsing | Windows, macOS | Display in session list |
What We Don't Collect
- Screen resolution or device pixel ratio
- Hardware concurrency or device memory
- WebGL vendor or renderer information
- Canvas or audio fingerprints
- Installed fonts or plugins
- Timezone or language preferences
We deliberately avoid elaborate fingerprinting. Browser name + version is sufficient to detect cross-browser session theft while minimizing data collection.
Fingerprint Generation
The browser fingerprint is generated server-side by parsing the User-Agent header. The version is truncated to allow minor updates without invalidating sessions.
Fingerprint generation happens at session creation (login or account creation). The server parses the User-Agent header to extract browser information, then truncates the version for stable comparison.
Generation Process
- Server receives User-Agent header from login request
- Parse browser name: Chrome, Firefox, Safari, Edge, Opera, etc.
- Extract full version string (e.g., '120.0.6099.129')
- Extract major version (before first dot): '120'
- Truncate to first 2 characters: '12'
- Create fingerprint: browser + truncatedVersion (e.g., 'Chrome12')
- Store browser, browserVersion, and os in session data
Truncation Examples
User-Agent: Mozilla/5.0 ... Chrome/120.0.6099.129
Major Version: 120
Truncated: 12
Fingerprint: Chrome12
User-Agent: Mozilla/5.0 ... Firefox/121.0
Major Version: 121
Truncated: 12
Fingerprint: Firefox12
User-Agent: Mozilla/5.0 ... Safari/17.2.1
Major Version: 17
Truncated: 17
Fingerprint: Safari17Supported Browsers
Fingerprint generation happens entirely server-side. No client-side JavaScript is required for fingerprint collection, reducing attack surface.
Fingerprint Validation
Every authenticated request validates that the current browser fingerprint matches the stored fingerprint. Mismatches result in immediate session rejection.
Fingerprint validation is simple and fast: we compare the current browser fingerprint to the stored one. If they don't match exactly, the request is rejected with BROWSER_MISMATCH.
Validation Process
- Extract User-Agent from current request
- Parse browser name and version from User-Agent
- Truncate version to first 2 digits
- Build current fingerprint: browser + truncatedVersion
- Retrieve stored fingerprint from session in Redis
- Build stored fingerprint: session.browser + session.browserVersion
- Compare: currentFingerprint === storedFingerprint
- Match: Continue to next validation step
- Mismatch: Return 403 BROWSER_MISMATCH
Validation Outcomes
| Scenario | Current | Stored | Result |
|---|---|---|---|
| Same browser, same version range | Chrome12 | Chrome12 | Pass |
| Same browser, minor update | Chrome12 (125) | Chrome12 (120) | Pass |
| Same browser, major update | Chrome13 | Chrome12 | FAIL |
| Different browser | Firefox12 | Chrome12 | FAIL |
| Same browser, different major version | Safari18 | Safari17 | FAIL |
There is no 'soft match' or scoring system. The fingerprint either matches exactly or the session is rejected. This is intentional - it's better to require re-login than to allow potential session hijacking.
Error Response
When validation fails, the server logs the mismatch (stored vs current fingerprint) and returns HTTP 403 with error code BROWSER_MISMATCH. The user must log in again to create a new session.
Version Tolerance
Browser version truncation allows minor updates without session invalidation. Chrome 120 and Chrome 125 both become 'Chrome12' and are treated as the same browser.
Browser updates are frequent - Chrome updates every few weeks. To avoid forcing users to re-login after every update, we truncate the version number so that minor updates don't change the fingerprint.
Truncation Effect
| Browser Updates | Full Version | Truncated | Session Valid? |
|---|---|---|---|
| Chrome 120 -> 125 | 120 -> 125 | 12 -> 12 | Yes (same) |
| Chrome 125 -> 129 | 125 -> 129 | 12 -> 12 | Yes (same) |
| Chrome 129 -> 130 | 129 -> 130 | 12 -> 13 | No (re-login needed) |
| Firefox 120 -> 121 | 120 -> 121 | 12 -> 12 | Yes (same) |
| Safari 17.2 -> 17.5 | 17 -> 17 | 17 -> 17 | Yes (same) |
Why This Design?
- Browsers update frequently (every 4-6 weeks for Chrome)
- Full version matching would force constant re-logins
- First 2 digits of major version stay stable for ~10 releases
- This gives roughly 6-12 months before re-login is needed
- Still catches: different browsers, very old sessions, cross-device attacks
Edge Cases
You'll need to re-login when Chrome goes from 129 to 130, or Firefox from 129 to 130, etc. This happens roughly once a year per browser. Simply log in again and a new session is created.
IP History Tracking
Each session maintains a history of up to 20 IP addresses used. This helps you identify where your sessions have been accessed from.
We track IP addresses for each session to help you monitor where your account is being accessed. This information appears in the session list and can help identify unauthorized access.
IP Data Collected
- IP address (extracted from CF-Connecting-IP, X-Real-IP, or X-Forwarded-For)
- First seen timestamp for each IP
- Last seen timestamp for each IP
- Request count per IP
- Up to 20 IPs stored per session (oldest removed when limit reached)
IP History Structure
"ipHistory": [
{
"ip": "192.168.1.100",
"firstSeen": "2024-01-15T10:30:00Z",
"lastSeen": "2024-01-15T14:22:00Z",
"requestCount": 47
},
{
"ip": "10.0.0.50",
"firstSeen": "2024-01-16T09:00:00Z",
"lastSeen": "2024-01-16T17:30:00Z",
"requestCount": 123
}
]IP Display in Dashboard
| Raw IP | Displayed As | Purpose |
|---|---|---|
| 192.168.1.100 | 192.168.*.* | Privacy masking |
| 10.0.0.50 | 10.0.*.* | Privacy masking |
| 2001:db8::1 | 2001:db8:**** | IPv6 masking |
| unknown | Unknown | Header not available |
Unlike some systems, we do NOT block sessions based on IP changes. Mobile users frequently change IPs, and VPN users switch constantly. IP history is informational only - browser fingerprint is what binds the session.
Activity Updates
IP history and activity timestamps are updated at most every 5 minutes to reduce Redis writes. The current IP is checked and added/updated in the history array, with the oldest entry removed if 20 IPs are already tracked.
Authentication
Secure identity verification and access control
Password Security
Passwords are hashed using bcrypt with a secret PEPPER, making them computationally infeasible to crack even if the database is compromised.
Memescale never stores plaintext passwords. All passwords are processed through a multi-layer hashing system that provides protection against dictionary attacks, rainbow tables, and database theft.
Password Hashing Process
- User submits password via HTTPS
- Password is combined with server-side PEPPER (secret key)
- Combined value is hashed using bcrypt with 12 rounds
- bcrypt generates random salt internally
- Final hash stored in database (salt included in hash)
Security Parameters
Password Requirements
| Requirement | Minimum | Recommended |
|---|---|---|
| Length | 8 characters | 16+ characters |
| Complexity | Mixed case + numbers | All character types |
| Uniqueness | Not in common lists | Generated password |
| Rotation | Not enforced | Optional |
The PEPPER is a secret value stored separately from the database. Even if an attacker obtains the password hashes from the database, they cannot crack passwords without also obtaining the PEPPER from the application server.
Legacy passwords using SHA-256 are automatically upgraded to bcrypt on successful login. This transparent migration ensures all users benefit from the stronger algorithm without requiring password resets.
Login Flow
The login flow includes credential validation, threat assessment, session creation, fingerprint capture, and device binding in a secure, atomic sequence.
Login is a multi-step process that validates credentials, assesses risk, and establishes a secure session bound to the user's device. Each step must succeed for login to complete.
Login Sequence
- User submits username and password via login form
- Pre-login threat check: velocity limits, account lock status
- Credential validation: bcrypt comparison with PEPPER
- If credentials valid: create session with unique ID
- Client-side: capture device fingerprint
- Post-login: send fingerprint to enhance session
- Session enhancement: bind fingerprint, generate tokens
- Set HTTP-only session cookie
- Log successful login to audit trail
- Redirect to dashboard
Login Response States
| State | Cause | User Message | Next Action |
|---|---|---|---|
| Success | Valid credentials | None (redirect) | Dashboard access |
| Invalid Credentials | Wrong password | Invalid credentials | Retry allowed |
| Account Locked | Too many failures | Account temporarily locked | Wait or reset |
| Rate Limited | Too many attempts | Too many attempts | Wait 15 minutes |
| Suspicious | Threat detected | Additional verification | Challenge flow |
Password comparison uses constant-time algorithms to prevent timing attacks. An invalid username takes the same time as an invalid password, preventing username enumeration.
Failed Login Handling
Session Enhancement
After basic session creation, the session is enhanced with fingerprint data and binding tokens, upgrading it from a simple identifier to a device-bound security context.
Session enhancement transforms a basic session into a fully secured, device-bound session. This process occurs immediately after login and adds all the security metadata needed for ongoing protection.
Enhancement Steps
- Client collects fingerprint components after login redirect
- Fingerprint sent to /api/auth/enhance-session endpoint
- Server validates session exists and is in CREATED state
- Server computes fingerprint hash and stores components
- Server generates binding token and computes binding hash
- Session updated with fingerprint, binding data, and IP
- Session state transitions from CREATED to ACTIVE
- Login success logged to audit trail with full context
Enhanced Session Data
{
"sessionId": "sess_abc123...",
"state": "ACTIVE",
"fingerprint": {
"hash": "sha256:def456...",
"components": {
"screenResolution": "1920x1080",
"timezone": "America/New_York",
"language": "en-US",
"platform": "Win32",
"hardwareConcurrency": 8,
"deviceMemory": 16,
"colorDepth": 24
}
},
"binding": {
"token": "bind_xyz789...",
"hash": "sha256:ghi012..."
},
"ipAddress": "192.168.1.100",
"userAgent": "Mozilla/5.0..."
}Sessions have a 30-second grace period after creation to receive enhancement. If fingerprint data is not received within this window, the session remains usable but with reduced trust level.
Re-authentication for Sensitive Actions
Sensitive operations like password changes or bulk session revocation require recent password verification through a time-limited re-authentication token.
Re-authentication provides an additional verification step for sensitive operations. Even with a valid session, users must prove they know the current password before performing high-risk actions.
Operations Requiring Re-auth
- Change password
- Change username
- Terminate all sessions (including current)
- Enable/disable two-factor authentication
- Download account data export
- Delete account
Re-auth Flow
- User initiates sensitive action
- System detects no valid re-auth token
- Modal prompts for current password
- Password verified against stored hash
- On success: re-auth token generated (5-minute TTL)
- Token stored in Redis, linked to session
- Original action proceeds with token
- Token consumed (single use per operation)
A re-auth token obtained for password change can only be used for password change. Attempting to use it for account deletion will fail and require new re-authentication.
Password Reset Flow
Password reset uses secure, time-limited tokens sent via trusted channels. Tokens are single-use and expire after one hour.
The password reset flow provides a secure way to recover account access when the password is forgotten. The process uses cryptographically secure tokens with strict expiration and usage limits.
Reset Request Flow
- User submits username on forgot password page
- System validates username exists
- Rate limit check: max 3 requests per hour per username
- Generate 64-byte cryptographically random token
- Store token in Redis with 1-hour TTL
- Link token to user ID (not stored in token itself)
- Return success (regardless of username validity)
- Deliver token via secure channel
Reset Completion Flow
- User clicks reset link with token
- System validates token exists and not expired
- User enters new password
- Password validated against requirements
- New password hashed with bcrypt + PEPPER
- Password updated in user record
- Token consumed (deleted from Redis)
- All existing sessions revoked
- Audit event logged
- Security alert sent to user
When a password is reset, ALL existing sessions for that account are immediately revoked. This ensures that a potential attacker who may have gained session access is locked out.
Threat Detection
Automated threat identification and response
Velocity Tracking
Login velocity tracking monitors the rate of authentication attempts to detect brute force attacks, credential stuffing, and other automated threats.
Velocity tracking monitors the frequency of login attempts across multiple dimensions: per-user, per-IP, and globally. Abnormal patterns trigger protective actions before damage occurs.
Velocity Metrics
| Metric | Window | Threshold | Action |
|---|---|---|---|
| Logins per user | 1 hour | 10 attempts | Soft lock |
| Failed logins per user | 1 hour | 5 attempts | Soft lock |
| Unique IPs per user | 1 hour | 5 IPs | Investigation flag |
| Logins per IP | 1 hour | 20 attempts | IP rate limit |
| Failed logins per IP | 15 minutes | 10 attempts | IP block |
Velocity Data Structure
Key: {auth}:velocity:{userId}
Type: Sorted Set
Members: Timestamps of login attempts
Score: Unix timestamp (ms)
TTL: 1 hour (auto-cleanup)
Example:
Member: "1705321200000:success:192.168.1.1"
Score: 1705321200000Rate Calculation
- Use Redis ZRANGEBYSCORE to get attempts within window
- Count total attempts and failed attempts separately
- Extract unique IPs from attempt metadata
- Compare counts against thresholds
- Apply most restrictive action if multiple thresholds exceeded
Velocity uses a sliding time window, not fixed buckets. An attempt at 10:30 AM is counted in the window from 9:30-10:30 AM, not just the 10:00-11:00 AM bucket.
Anomaly Detection
Anomaly detection identifies unusual patterns that deviate from established user behavior, such as unexpected location changes or unusual access times.
Beyond simple velocity limits, our anomaly detection system learns normal behavior patterns and flags deviations. This catches sophisticated attacks that operate below velocity thresholds.
Detected Anomalies
- Geographic impossibility: Logins from physically impossible locations
- Time anomaly: Access at unusual hours (based on history)
- Device proliferation: Sudden increase in unique devices
- Browser switching: Rapid changes between browser types
- IP reputation: Logins from known malicious IP ranges
- VPN hopping: Frequent VPN exit node changes
Behavioral Baseline
| Factor | Learning Period | Deviation Sensitivity |
|---|---|---|
| Typical login hours | 30 days | 2+ hours outside norm |
| Common locations | 90 days | New country |
| Device count | 30 days | 50% increase |
| Browser preferences | 30 days | Unknown browser |
| IP ranges | 30 days | New ISP/region |
New accounts have no behavioral baseline. During the first 30 days, anomaly detection is less sensitive and relies more on absolute thresholds rather than behavioral deviation.
Anomaly Response
Risk Scoring Engine
Each login attempt receives a risk score based on multiple factors. Higher scores trigger additional verification steps or outright blocking.
The risk scoring engine combines all available signals into a single score that determines the authentication response. This enables nuanced decisions rather than binary allow/deny.
Risk Factors
| Factor | Low Risk | Medium Risk | High Risk |
|---|---|---|---|
| IP Location | Known location | Same country | New country |
| Device | Known device | Similar device | New device |
| Time | Normal hours | Unusual hours | Never seen |
| Velocity | Normal rate | Elevated | Threshold exceeded |
| IP Reputation | Clean | Residential proxy | Known malicious |
| Browser | Known browser | Updated browser | New browser type |
Score Calculation
Base Score: 0
For each factor:
Low Risk: +0 points
Medium Risk: +15 points
High Risk: +30 points
Multipliers:
Previous account lock: 1.5x
Recent password reset: 1.2x
First login ever: 0.8x
Final Score = Sum of factors × MultipliersScore Thresholds
Risk scores are logged in the audit trail for forensic analysis. You can review why specific logins were challenged by examining the factor breakdown in login history.
Account Locking
Account locking provides temporary or permanent access restriction in response to detected threats. Soft locks expire automatically; hard locks require intervention.
Account locking is a protective measure that prevents further authentication attempts when suspicious activity is detected. We use tiered locking to balance security with user convenience.
Lock Types
| Type | Duration | Trigger | Unlock Method |
|---|---|---|---|
| Soft Lock | 15 minutes | 5 failed attempts | Automatic expiration |
| Hard Lock | 1 hour | 10 failed attempts | Password reset or expiration |
| Security Lock | Until resolved | Confirmed compromise | Support contact required |
| Admin Lock | Indefinite | Policy violation | Admin action required |
Lock State Data
{
"locked": true,
"lockType": "hard",
"lockedAt": "2024-01-15T10:30:00Z",
"lockedUntil": "2024-01-15T11:30:00Z",
"reason": "10 consecutive failed login attempts",
"failedAttempts": 10,
"lockingIP": "192.168.1.100",
"lockingUserAgent": "Mozilla/5.0..."
}Lock Progression
- Failed attempts increment counter
- At 5 failures: soft lock (15 minutes)
- Counter resets after soft lock expires
- At 10 failures (within 24 hours): hard lock (1 hour)
- At 20 failures: extended hard lock (24 hours)
- Repeated patterns: escalate to security lock
Security locks and admin locks also revoke all active sessions. Soft and hard locks only prevent new logins; existing sessions remain valid until they expire naturally.
Brute Force Protection
Multiple layers of brute force protection make password guessing computationally infeasible, even against targeted accounts.
Brute force protection combines rate limiting, account locking, and IP blocking to make automated password guessing impractical. Each layer adds friction for attackers while minimizing impact on legitimate users.
Protection Layers
- bcrypt work factor: Each password check takes ~100ms
- Per-account rate limiting: 10 attempts per hour maximum
- Per-IP rate limiting: 20 attempts per hour from single IP
- Progressive delays: 1s, 2s, 4s, 8s delays between failures
- Account locking: Lock after 5-10 failures
Attack Resistance Analysis
| Attack Type | Without Protection | With Protection |
|---|---|---|
| Dictionary (10k words) | ~17 minutes | ~28 hours (locked after 5) |
| Brute force (6 chars) | ~3 days | Effectively infinite |
| Credential stuffing | Parallel attacks | Rate limited + locked |
| Distributed attack | Bypass IP limits | Account locks apply |
During high-risk scenarios, we may enable proof-of-work challenges that require the client to perform computational work before submitting login attempts. This further increases attacker costs.
Distributed Attack Defense
Distributed attacks using botnets bypass IP-based rate limiting. We counter this with account-level locks that apply regardless of source IP. An account with 5 failures is locked whether those failures came from 1 IP or 5 different IPs.
Audit Trail System
Comprehensive security event logging
Audit Event Types
Every security-relevant action is logged as an audit event with full context, enabling forensic analysis and compliance reporting.
The audit trail captures all security-relevant events in your account. Each event includes who did what, when, from where, and the outcome. This data is essential for security investigations and regulatory compliance.
Event Categories
| Category | Events | Risk Level |
|---|---|---|
| Authentication | login_success, login_failure, logout | Low to Medium |
| Session | session_created, session_revoked, session_expired | Low |
| Account | password_changed, password_reset, profile_updated | Medium to High |
| Security | fingerprint_mismatch, account_locked, suspicious_activity | High |
| Access | sensitive_data_accessed, permission_denied | Medium |
| Administrative | admin_access, config_changed | Critical |
Event Risk Levels
Full Event List
- login_success: Successful authentication
- login_failure: Failed authentication attempt
- logout: User-initiated session end
- session_created: New session established
- session_revoked: Session explicitly terminated
- session_expired: Session TTL exceeded
- password_changed: Password updated successfully
- password_reset_requested: Reset token generated
- password_reset_completed: Password reset via token
- fingerprint_mismatch: Device binding validation failed
- account_locked: Account locked due to failures
- account_unlocked: Account lock expired or cleared
- suspicious_activity: Anomaly detected and flagged
- reauth_success: Re-authentication completed
- reauth_failure: Re-authentication failed
Audit events are write-once. Once logged, they cannot be modified or deleted (except by automatic retention policy). This ensures audit trail integrity.
Audit Logging Mechanism
Audit events are logged synchronously to ensure no event is lost, with rich metadata captured at the moment of occurrence.
Our audit logging mechanism captures events in real-time with full contextual data. Events are logged before the triggering action completes, ensuring that even failed or interrupted operations are recorded.
Event Structure
{
"eventId": "evt_abc123...",
"type": "login_success",
"riskLevel": "low",
"userId": "user_xyz...",
"username": "johndoe",
"sessionId": "sess_def456...",
"ipAddress": "192.168.1.100",
"userAgent": "Mozilla/5.0...",
"fingerprint": "sha256:abc...",
"metadata": {
"loginMethod": "password",
"deviceType": "desktop",
"location": "New York, US"
},
"outcome": "success",
"timestamp": "2024-01-15T10:30:00.123Z"
}Logging Pipeline
- Event triggered by security-relevant action
- Event data collected from request context
- Event ID generated (cryptographically random)
- Timestamp captured with millisecond precision
- Event written to Redis (sorted set by timestamp)
- Event data stored separately (hash)
- User's audit index updated
Captured Context
| Context | Source | Purpose |
|---|---|---|
| IP Address | X-Forwarded-For / Remote | Geolocation, correlation |
| User Agent | HTTP Header | Device identification |
| Fingerprint | Client submission | Device verification |
| Session ID | Cookie / Token | Session correlation |
| Timestamp | Server clock | Chronological ordering |
| Request ID | Generated | Request tracing |
For high-throughput scenarios, audit logging can be configured for asynchronous writes. Events are queued and written in batches while maintaining ordering guarantees.
Audit Data Storage
Audit data is stored in Redis with efficient indexing for both chronological queries and event-type filtering.
Audit storage uses Redis sorted sets for efficient time-range queries combined with hashes for full event data. This architecture supports both real-time monitoring and historical analysis.
Storage Structure
# User's audit log (sorted set)
Key: {auth}:audit:{userId}
Members: Event IDs
Score: Unix timestamp (ms)
# Individual event (hash)
Key: {auth}:audit_event:{eventId}
Fields: type, userId, sessionId, ipAddress, ...
# Event type index (sorted set)
Key: {auth}:audit_type:{type}:{userId}
Members: Event IDs
Score: Unix timestamp (ms)Query Patterns
| Query Type | Command | Performance |
|---|---|---|
| Recent events | ZREVRANGE audit:{userId} 0 19 | O(log N) |
| Time range | ZRANGEBYSCORE audit:{userId} min max | O(log N + M) |
| By event type | ZRANGE audit_type:{type}:{userId} | O(log N) |
| Event details | HGETALL audit_event:{eventId} | O(1) |
| Event count | ZCARD audit:{userId} | O(1) |
Storage Limits
When the event limit is reached, oldest events are automatically removed using Redis ZREMRANGEBYRANK. This keeps storage bounded while preserving recent history.
Retention Policies
Audit data is retained for 90 days by default, with automatic cleanup of expired events to maintain storage efficiency.
Retention policies balance the need for forensic analysis against storage costs. Different event types may have different retention periods based on their security significance.
Retention Periods
| Event Category | Retention | Rationale |
|---|---|---|
| Authentication events | 90 days | Compliance standard |
| Session events | 90 days | Session lifecycle tracking |
| Security events | 180 days | Extended investigation window |
| Administrative events | 365 days | Regulatory requirement |
| Critical events | 365 days | Long-term forensics |
Cleanup Process
- Scheduled job runs daily at low-traffic hours
- Calculate cutoff timestamp based on retention period
- For each user: ZREMRANGEBYSCORE audit:{userId} -inf {cutoff}
- Delete corresponding event hashes
- Update type indexes
- Log cleanup statistics
Events subject to legal holds are excluded from automatic cleanup. If your account is involved in a legal matter, retention may be extended indefinitely until the hold is released.
Forensic Analysis
The audit trail enables detailed forensic analysis to investigate security incidents, trace attacker actions, and understand breach timelines.
When a security incident occurs, the audit trail provides the evidence needed to understand what happened, when it happened, and what the attacker accessed. This data is crucial for incident response and remediation.
Investigation Capabilities
- Timeline reconstruction: Order events chronologically to understand attack sequence
- Session tracing: Follow all actions within a specific session
- IP correlation: Find all events from a specific IP address
- Pattern detection: Identify unusual event sequences or frequencies
- Impact assessment: Determine what data or actions were affected
- Attribution: Link events to specific users or sessions
Common Investigation Queries
| Question | Query Approach | Data Used |
|---|---|---|
| When was account compromised? | Find first suspicious event | Risk level, IP changes |
| What did attacker access? | Trace session actions | Session ID correlation |
| How did attacker get in? | Analyze login patterns | Login events, fingerprints |
| Was data exfiltrated? | Check sensitive data access | Access events, volumes |
| Are other accounts at risk? | IP/pattern correlation | Cross-account analysis |
Forensic Report Contents
1. Incident Summary
- Detection time
- Affected accounts
- Severity assessment
2. Timeline
- Chronological event listing
- Key events highlighted
3. Attack Analysis
- Entry point
- Actions taken
- Lateral movement
4. Impact Assessment
- Data accessed
- Actions performed
- Persistence mechanisms
5. Indicators of Compromise
- IP addresses
- Fingerprints
- Behavior patternsAudit data can be exported in JSON format for analysis with external tools. This is useful for integrating with SIEM systems or conducting offline analysis.
Security Alerts
Proactive security notifications
Alert Types
Security alerts notify you of important security events, from new device logins to suspected account compromise.
Security alerts keep you informed about your account's security status. Each alert type has a specific purpose and requires different levels of attention.
Alert Categories
| Alert Type | Severity | Description | Action Required |
|---|---|---|---|
| new_login | Low | Successful login detected | Review if unexpected |
| new_device | Medium | Login from new device | Verify device |
| suspicious_login | High | Unusual login pattern | Investigate immediately |
| session_revoked | Low | A session was terminated | Informational |
| password_changed | Medium | Password was changed | Verify you did this |
| account_locked | High | Account temporarily locked | Check for attacks |
| failed_attempts | Medium | Multiple failed logins | Review activity |
Alert Severity Levels
Alert Details
- new_login: Shows device type, browser, location, and time of login
- new_device: Includes full device fingerprint summary and location
- suspicious_login: Explains why login was flagged (location, time, etc.)
- session_revoked: Shows which session was revoked and by whom
- password_changed: Indicates time of change and originating IP
- account_locked: Shows reason for lock and unlock time
- failed_attempts: Lists attempt count, IPs, and timeframe
You can customize which alerts you receive and how. Low-severity alerts can be disabled if you prefer less noise, while high-severity alerts are always sent.
Alert Triggers
Alerts are triggered by specific security events. Understanding triggers helps you interpret alerts and take appropriate action.
Each alert type has specific conditions that trigger it. These triggers are carefully calibrated to notify you of genuinely important events while avoiding alert fatigue.
Trigger Conditions
| Alert | Primary Trigger | Additional Conditions |
|---|---|---|
| new_login | Successful authentication | None (always triggered) |
| new_device | Unknown fingerprint hash | Device not seen in 90 days |
| suspicious_login | Risk score > 90 | Any high-risk factor |
| session_revoked | Session explicitly terminated | By user or system |
| password_changed | Password update successful | None (always triggered) |
| account_locked | Lock threshold exceeded | 5+ failed attempts |
| failed_attempts | 3+ failures in 1 hour | From same or different IPs |
Suspicious Login Factors
- Geographic impossibility: Login from impossible location
- New country: First login from a new country
- Unusual time: Login at abnormal hours for user
- Unknown device + unknown location: Combined risk factors
- Rapid location change: Significant distance in short time
- Known malicious IP: IP on reputation blocklist
VPN usage, travel, or browser updates can trigger alerts. If you receive unexpected alerts after such changes, you can mark them as acknowledged. Patterns will learn over time.
Trigger Debouncing
To prevent alert floods, some triggers are debounced. For example, multiple failed login attempts within a short window generate a single aggregated alert rather than one per attempt.
Alert Delivery
Alerts are delivered through the security dashboard with optional email notifications for high-severity events.
Alerts are delivered through multiple channels to ensure you receive important security notifications promptly. The delivery method depends on alert severity and your preferences.
Delivery Channels
| Channel | Alerts Delivered | Latency | Opt-out |
|---|---|---|---|
| Dashboard | All alerts | Real-time | No |
| High/Critical only | < 5 minutes | Configurable | |
| Push Notification | Critical only | Real-time | Configurable |
| API Webhook | Configurable | Real-time | N/A |
Dashboard Alerts
- Unread count badge visible on security tab
- Alerts sorted by recency with newest first
- Click to expand full details
- Mark as read with single click
- Dismiss non-actionable alerts
Email Notifications
Email notifications include a summary of the alert with key details. For security reasons, emails do not include sensitive information like full IP addresses or session tokens.
Subject: [Memescale] New login from unknown device
-----------------------------------------
A new login was detected on your account.
-----------------------------------------
Device: Chrome on Windows
Location: San Francisco, CA, US
Time: January 15, 2024 at 10:30 AM PST
If this was you, no action is needed.
If this wasn't you, please:
1. Log in and review your sessions
2. Terminate unknown sessions
3. Change your password
Review your security at:
https://app.memescale.ai/ordersWe never include direct login links in security emails to prevent phishing attacks. Always navigate to Memescale manually to review security alerts.
Alert Management
Manage your alerts through the security dashboard: mark as read, dismiss, or take action directly from the alert.
The security dashboard provides comprehensive alert management capabilities. You can review, acknowledge, and act on alerts without leaving the dashboard.
Alert States
| State | Meaning | Visual Indicator |
|---|---|---|
| Unread | Not yet viewed | Bold text, blue dot |
| Read | Viewed but not dismissed | Normal text |
| Dismissed | Acknowledged and hidden | Hidden from list |
Alert Actions
- Mark as Read: Acknowledge without dismissing
- Mark All Read: Clear all unread indicators
- Dismiss: Remove from active list (still in history)
- View Details: Expand full alert information
- Take Action: Direct links to relevant security actions
- Report False Positive: Flag incorrectly triggered alerts
Actionable Alerts
Some alerts include direct action buttons to streamline your response. These actions are pre-authenticated through your current session.
Dismissed alerts are not deleted. They remain in your audit history and can be retrieved through the audit log if needed for investigation.
Bulk Operations
For users with many alerts, bulk operations are available. You can mark all alerts as read with a single click, or filter alerts by type to manage specific categories.
Data Protection
Encryption and data security
Encryption at Rest
All sensitive data is encrypted when stored, including passwords, session data, and personal information.
Encryption at rest ensures that data remains protected even if storage media is compromised. We employ multiple encryption strategies depending on the data sensitivity level.
Encrypted Data Types
| Data Type | Encryption Method | Key Management |
|---|---|---|
| Passwords | bcrypt (one-way hash) | PEPPER in environment |
| Session tokens | Generated via CSPRNG | Redis key expiration |
| Reset tokens | Generated via CSPRNG | Single-use, TTL |
| Audit logs | Application-level | Managed key rotation |
| User data | Database encryption | Infrastructure keys |
Password Storage
Passwords use one-way hashing rather than reversible encryption. Even with full database access, original passwords cannot be recovered. We use bcrypt with 12 rounds and a server-side PEPPER.
$2b$12$[22 chars salt][31 chars hash]
Components:
- $2b$ : bcrypt version identifier
- 12 : cost factor (2^12 iterations)
- salt : 22 base64 characters
- hash : 31 base64 charactersDatabase Encryption
- Redis: TLS encryption for data in transit to/from Redis
- File storage: Server-side encryption on storage volumes
- Backups: Encrypted with separate backup keys
- Logs: Sensitive fields redacted before logging
Multiple encryption layers ensure that compromising one system doesn't expose all data. Password hashes require the PEPPER, tokens require Redis access, and user data requires database keys.
Encryption in Transit
All network communication uses TLS 1.3 with strong cipher suites. Unencrypted connections are not accepted.
Data in transit is protected using Transport Layer Security (TLS). All client-server communication and internal service communication uses encrypted channels.
TLS Configuration
HTTP Security Headers
| Header | Value | Purpose |
|---|---|---|
| Strict-Transport-Security | max-age=31536000; includeSubDomains | Force HTTPS |
| X-Content-Type-Options | nosniff | Prevent MIME sniffing |
| X-Frame-Options | DENY | Prevent clickjacking |
| X-XSS-Protection | 1; mode=block | XSS filter |
| Referrer-Policy | strict-origin-when-cross-origin | Control referrer |
Cookie Security
- Secure: Cookies only sent over HTTPS
- HttpOnly: Cookies not accessible via JavaScript
- SameSite=Strict: Cookies not sent in cross-origin requests
- Path=/: Cookies scoped to entire domain
HTTP connections are automatically redirected to HTTPS. The HSTS header ensures browsers remember to use HTTPS for all future requests, even if the user types http://.
Key Management
Cryptographic keys are managed securely with proper rotation, storage, and access controls.
Cryptographic key management is critical to maintaining data security. Keys are stored securely, rotated regularly, and accessed only by authorized systems.
Key Types
| Key Type | Storage | Rotation | Access |
|---|---|---|---|
| PASSWORD_PEPPER | Environment variable | Rare (re-hash required) | Application only |
| Session signing | Environment variable | Monthly | Application only |
| TLS certificates | Secret management | Annually | Load balancer |
| Database encryption | Infrastructure KMS | Quarterly | Database service |
| Backup encryption | Offline storage | Annually | Backup service |
Key Storage
- Never stored in source code or version control
- Environment variables for application secrets
- Infrastructure-level KMS for database keys
- Hardware Security Modules (HSM) for critical keys
- Separate keys for different environments (dev/staging/prod)
Key Rotation Process
- Generate new key material using secure random generation
- Deploy new key to all application instances
- Update references to use new key for new operations
- Maintain old key for decrypting existing data
- Re-encrypt data using new key (if applicable)
- Revoke old key after transition period
The PASSWORD_PEPPER is rarely rotated because it requires all users to re-authenticate and have their passwords re-hashed. If rotation is needed, users are prompted to re-enter their password on next login.
Data Isolation
User data is strictly isolated to prevent unauthorized access across accounts, even from within the application.
Data isolation ensures that one user cannot access another user's data, even if they discover internal identifiers or attempt to manipulate API requests.
Isolation Mechanisms
- Redis key namespacing: All keys include user ID prefix
- Session binding: Session tokens bound to specific user
- API authorization: Every endpoint validates user ownership
- Query filtering: Database queries include user ID constraint
- File system: User files in isolated directories
Key Namespace Structure
{auth}:user:{userId} # User profile
{auth}:user_sessions:{userId} # Session index
{auth}:audit:{userId} # Audit events
{auth}:alerts:{userId} # Security alerts
{auth}:velocity:{userId} # Login velocity
Cross-reference keys:
{auth}:session:{sessionId} # Session data
{auth}:username:{username} # Username -> userIdAuthorization Checks
Every API endpoint that accesses user data performs authorization checks. The pattern is consistent: extract user ID from session, verify requested resource belongs to that user.
// 1. Validate session
const session = await validateSession(request);
if (!session.valid) return unauthorized();
// 2. Extract user ID from session
const userId = session.userId;
// 3. Verify ownership of requested resource
const resource = await getResource(resourceId);
if (resource.userId !== userId) {
return forbidden();
}Even if a request has a valid session, ownership of the requested resource is always verified. A valid session for User A cannot access User B's data, even through direct ID manipulation.
Session Validation
Request-by-request session verification
Validation Middleware
The withApiAuth middleware intercepts every request to protected routes, validating all three cookies, browser fingerprint, and HMAC reconstruction before allowing access.
Every API request passes through the withApiAuth middleware, which enforces the complete session triplet validation. This happens on every single request - there's no caching of authentication state.
Middleware Pipeline
- Quick session check to determine if user is a paying customer (for rate limiting)
- Check if IP is rate-limited due to prior failures (skipped for paying customers)
- Validate pow_valid cookie: HMAC signature check, extract powId
- Validate JWT: Check session exists with userId and username
- Validate powxd cookie: Ensure 32-character hex value is present
- Fetch session from Redis using powId
- Verify userId in JWT matches userId in session
- Verify browser fingerprint matches stored fingerprint
- Reconstruct expected powxd using HMAC derivation
- Compare cookie powxd with reconstructed value
- Re-verify PoW solution still has 4 leading zeros
- Update session activity (throttled to every 5 minutes)
- Continue to route handler with authenticated context
Validation Results
| Result | HTTP Status | Error Code | Client Action |
|---|---|---|---|
| Valid | 200 | None | Request proceeds |
| No PoW Cookie | 429 | POW_REQUIRED | Refresh page, solve PoW |
| No JWT | 401 | NOT_AUTHENTICATED | Redirect to login |
| No powxd | 401 | MISSING_POWXD | Call init-session or re-login |
| Session Not Found | 401 | SESSION_NOT_FOUND | Session expired, re-login |
| User Mismatch | 401 | SESSION_REBIND_NEEDED | Call init-session |
| Browser Mismatch | 403 | BROWSER_MISMATCH | Different browser, re-login |
| HMAC Mismatch | 401 | INVALID_PROOF | Tampering detected, re-login |
| PoW Invalid | 401 | POW_FAILED | PoW tampered, refresh and re-login |
Users who have purchased bots bypass all rate limiting. This ensures paying customers ($199-$1,199/mo) are never throttled for legitimate use.
Protected Routes
- /api/bots/* - Bot management (with requireBotOwnership option)
- /api/payments/* - Payment operations
- /api/support/* - Support ticket system
- /api/user/* - User data endpoints
- /api/auth/sessions - Session management (list, revoke)
Validation Options
The withApiAuth middleware supports options for requiring folder ownership, bot ownership, or custom rate limiting. These add authorization checks after authentication.
Beyond authentication, the middleware can enforce authorization rules. Routes can require that the user has a folder (account with data), owns a specific bot, or respect certain rate limits.
Middleware Options
| Option | Purpose | Failure Response | Use Case |
|---|---|---|---|
| (none) | Authentication only | N/A | General API access |
| requireFolder | Must have account with folderId | 404 NO_FOLDER | Dashboard data endpoints |
| requireBotOwnership | Must own the specified bot | 403 BOT_OWNERSHIP_DENIED | Bot management endpoints |
| rateLimit | Apply request rate limiting | 429 with retry info | Expensive operations |
Bot Ownership Verification
// Example route with bot ownership requirement
export const POST = withApiAuth(
async (req, { userId, bot, folderId }) => {
// bot is verified to be owned by userId
// folderId is the user's storage folder
return NextResponse.json({ success: true });
},
{ requireBotOwnership: { from: 'body', field: 'botId' } }
);Rate Limit Configuration
- Paying customers: NO rate limit (always allowed)
- Authenticated non-paying: 10x the base limit
- Failed auth attempts: 10 per 60 seconds, then 5-minute block
- Custom route limits: Configured per-route with keyPrefix
The full session triplet is validated BEFORE checking ownership or rate limits. A failed authentication never reaches the authorization checks.
Activity Tracking
Session activity is updated automatically on each request, throttled to avoid excessive Redis writes. This keeps your session alive as long as you're using the site.
Every successful request updates your session's lastActivity timestamp. However, to avoid hammering Redis with writes, updates are throttled to at most once every 5 minutes.
Activity Update Rules
What Gets Updated
- lastActivity timestamp set to current time
- Current IP added to ipHistory (or request count incremented)
- Redis TTL refreshed to full 7 days
- User's session set TTL also refreshed
Session Expiration
If you don't make any authenticated requests for 7 days, your session expires automatically via Redis TTL. The next request will fail with SESSION_NOT_FOUND and you'll need to log in again.
As long as you visit the dashboard at least once a week, your session stays active. Normal usage patterns keep the session refreshed automatically.
HMAC Reconstruction
The core security check: we don't compare stored powxd to cookie. Instead, we reconstruct what powxd SHOULD be from stored components and compare that. Tampering is detected.
HMAC reconstruction is what makes session hijacking nearly impossible. Even if an attacker gains access to Redis, they cannot forge a valid powxd because the HMAC secret is never stored - it's only in the server's environment.
Reconstruction Process
- Fetch session from Redis using powId
- Extract binding data: challenge, nonce, resultHash, userId, sid, bindingTimestamp
- Reconstruct data string: challenge|nonce|resultHash|userId|sid|timestamp
- Compute HMAC: HMAC-SHA256(POWXD_SECRET, data).slice(0, 32)
- Compare computed value to powxd cookie value
- Match: Proceed to PoW verification
- Mismatch: Return INVALID_PROOF error
The HMAC Formula
// Data components from Redis session
data = `${challenge}|${nonce}|${resultHash}|${userId}|${sid}|${timestamp}`
// HMAC computation (POWXD_SECRET is server-side only)
expectedPowXd = HMAC-SHA256(POWXD_SECRET, data)
.digest('hex')
.slice(0, 32) // 128-bit = 32 hex chars
// Comparison
if (cookiePowXd !== expectedPowXd) {
return { valid: false, code: 'INVALID_PROOF' }
}Why Reconstruction Works
| Attack Scenario | What Attacker Has | Why It Fails |
|---|---|---|
| Steal all 3 cookies | pow_valid, JWT, powxd | Browser fingerprint mismatch |
| Tamper with Redis session | Modified session data | Reconstruction produces different HMAC |
| Guess POWXD_SECRET | Nothing | 256-bit secret, computationally infeasible |
| Replay old session | Old cookies | Different sid per login = different powxd |
After HMAC reconstruction succeeds, we ALSO verify the PoW solution: SHA256(challenge + nonce) must equal resultHash AND have 4 leading zeros. This catches Redis tampering of the PoW components.
Security Dashboard
Your security control center
Dashboard Overview
The security dashboard provides a comprehensive view of your account's security status, active sessions, recent activity, and alerts.
The security dashboard is your central control panel for account security. It displays real-time information about sessions, alerts, and activity, giving you complete visibility into your account's security posture.
Dashboard Sections
- Session Visibility: View and manage all active sessions
- Security Alerts: Unread alerts with severity indicators
- Login History: Recent authentication events
- Quick Actions: Common security operations
Security Status Indicators
| Indicator | Meaning | Visual |
|---|---|---|
| Green checkmark | All security normal | Green badge |
| Yellow warning | Attention recommended | Yellow badge |
| Red alert | Action required | Red badge with count |
| Blue info | Informational items | Blue badge |
Dashboard Location
The security dashboard is integrated into the bot management page. It appears at the bottom of the management tab, always visible regardless of whether you have active bots.
The security dashboard is visible on every visit to the management page. You don't need to navigate to a separate security settings page to monitor your account.
Active Sessions View
View all devices where your account is currently logged in, with detailed information about each session.
The active sessions view shows every device currently logged into your account. Each session displays device information, location, and last activity time.
Session Information
| Field | Description | Example |
|---|---|---|
| Device | Device type and OS | Desktop - Windows |
| Browser | Browser name and version | Chrome 120 |
| Location | Approximate location | New York, US |
| IP Address | Last known IP | 192.168.x.x |
| Created | Session creation time | Jan 15, 2024 10:30 AM |
| Last Active | Most recent activity | 2 minutes ago |
| Current | Is this your current session | Yes/No badge |
Session Actions
- Terminate: End a specific session immediately
- Terminate All Others: End all sessions except current
- Terminate All: End all sessions including current (requires re-auth)
- View Details: Expand full session information
Session Sorting
Sessions are sorted with your current session first, followed by most recently active sessions. This makes it easy to identify and manage sessions you're currently using.
Your current session is highlighted with a 'Current Session' badge. This session cannot be individually terminated; use 'Terminate All' if you need to end it.
Login History
Review recent login attempts, both successful and failed, to identify suspicious activity.
Login history shows all authentication attempts on your account, including successful logins and failed attempts. This helps you identify unauthorized access attempts.
History Fields
| Field | Description | Significance |
|---|---|---|
| Time | When attempt occurred | Detect unusual hours |
| Status | Success or failure | Identify attacks |
| IP Address | Source IP | Track attacker IPs |
| Location | Geographic location | Detect impossible travel |
| Device | Device fingerprint summary | Identify new devices |
| Reason | Failure reason (if failed) | Understand attack type |
History Retention
Suspicious Patterns
- Multiple failed attempts from same IP
- Failed attempts from many different IPs (distributed attack)
- Logins from new countries
- Logins at unusual times
- Rapid succession of login attempts
If you see suspicious login attempts, immediately change your password and terminate all other sessions. This prevents attackers who may have guessed your password from maintaining access.
Security Actions
Quick actions available from the security dashboard to secure your account.
The security dashboard provides quick access to common security actions. These actions are designed for rapid response to security concerns.
Available Actions
| Action | Effect | Requires Re-auth |
|---|---|---|
| Terminate Session | End specific session | No |
| Terminate All Others | End all except current | Yes |
| Terminate All Sessions | End all sessions | Yes |
| Change Password | Update account password | Yes |
| Mark Alert Read | Acknowledge alert | No |
| Dismiss Alert | Hide alert from list | No |
Emergency Response
If you suspect your account is compromised, follow this emergency response procedure from the security dashboard:
- Click 'Terminate All Other Sessions' to lock out attackers
- Enter your password to confirm re-authentication
- Navigate to password change (if available in dashboard)
- Change to a new, strong password
- Review recent activity for unauthorized changes
- Contact support if unauthorized changes detected
Action Confirmation
Destructive actions like terminating sessions require confirmation. A confirmation dialog shows exactly what will happen before proceeding.
All security actions taken from the dashboard are logged to the audit trail. You can review past actions in login history to confirm when sessions were terminated or passwords changed.
Session Limits
The dashboard also displays your current session count and any applicable limits. While there's no hard limit on concurrent sessions, unusual session counts may trigger security reviews.
