Overview
Session sharing is PassAgent’s flagship feature. It lets you share access to any web service — Netflix, Spotify, GitHub, anything — without revealing your password. Instead of giving someone your credentials, PassAgent creates a live cloud browser session, logs in on your behalf (optionally via AI), and gives the recipient a view-only or interactive link to the already-authenticated session. The recipient sees the logged-in service in their browser. They never see, intercept, or extract the password. When the session expires, the cloud browser is destroyed and all session data is gone.Use cases
Share streaming services
Let a friend watch Netflix for 4 hours without sharing your password. The session is domain-locked — they cannot navigate away from Netflix.
Delegate account access
Give a contractor temporary access to your project dashboard. Enable view-only mode so they can see but not modify anything.
Demo an account
Show a client their account setup without handing over credentials. Watermark the session to deter screenshots.
Emergency access
Provide a family member access to a utility account during a crisis without any password exchange.
Session lifecycle
How it works
Owner creates a session share
From the vault, the owner selects a credential and chooses duration (15 min, 1 hour, 4 hours, or 8 hours), login method (AI agent or manual), and options like view-only mode and watermarking. The client decrypts the credential and sends the plaintext username/password to the server over HTTPS for the login step only.
Cloud browser session created
PassAgent provisions a Hyperbrowser cloud browser session with
disableRecording: true for security. The session returns a livePreviewUrl — a public, token-authenticated URL that renders the browser viewport in an iframe. Up to 3 retry attempts are made with exponential backoff (2s, 4s, 6s delays).AI agent logs in (or owner logs in manually)
If the AI agent method is selected, the
LoginAgent uses a Claude-powered perceive-reason-act loop to fill the login form. The agent takes screenshots, reads the DOM, and executes up to 12 steps. If CAPTCHA or 2FA is detected, the session falls back to manual mode. If manual mode is selected, the owner is shown the live browser to log in themselves.Security controls applied
After login, PassAgent applies domain locking (restricts navigation to the service’s domain), tab restriction (prevents opening new tabs), and optionally view-only mode and watermarking. The session status transitions to
active.Viewer accesses the session
The owner shares a link (
/s/{shareToken}). The viewer clicks it, and PassAgent serves the Hyperbrowser live preview URL in an embedded iframe. A viewer token is issued with a 5-minute TTL, renewed by heartbeat.AI login agent
TheLoginAgent class in lib/session-sharing/login-agent.ts automates the login process using the same architecture as PassAgent’s password reset agent.
Login strategy:
- Navigate to the service URL
- Detect the login form (email/username + password fields)
- Enter the username, then the password (using
[PASSWORD]placeholder in AI responses) - Click the login/sign-in button or press Enter
- Detect success (dashboard/home page), failure (incorrect credentials), CAPTCHA, or 2FA
claude-sonnet-4-20250514 and a maximum of 12 steps.
| Outcome | Next action |
|---|---|
success | Session goes active, security controls applied |
failed | Session terminated, owner notified |
captcha | Falls back to manual login (owner completes CAPTCHA) |
2fa_required | Falls back to manual login (owner enters 2FA code) |
max_steps | Falls back to manual login |
Security controls
Domain locking
After login,lockToSingleTab() restricts the browser to the service’s domain using four enforcement layers:
Active URL polling (primary)
Active URL polling (primary)
Every 2 seconds, PassAgent evaluates
window.location.href via Playwright and compares the hostname against the allowed domain using base domain extraction. If a violation is detected, the page is redirected back to the last known good URL. This catches address bar navigation, bookmarks, and JS redirects.New tab listener
New tab listener
A
context.on('page') handler automatically closes any new tabs the viewer opens. The event fires before the new page loads.Injected client-side script
Injected client-side script
JavaScript injected into the page overrides
window.open (returns null), intercepts link clicks to non-allowed domains (preventDefault), blocks form submissions to external domains, wraps location.assign and location.replace, and blocks Ctrl+T/Cmd+T/Ctrl+N/Ctrl+L keyboard shortcuts.Re-injection on navigation
Re-injection on navigation
View-only mode
When enabled,injectReadOnlyMode() creates a transparent overlay at z-index 2147483646 that blocks all pointer events. Keyboard input is intercepted on keydown, keypress, and keyup with preventDefault(). A “View Only” badge appears in the top-right corner. A MutationObserver prevents removal of the overlay by the page’s own scripts.
Watermarking
injectWatermark() renders a semi-transparent diagonal text pattern across the viewport at 6% opacity. The watermark text includes “PassAgent Session” and a truncated session ID. Pointer events pass through (pointer-events: none), and a MutationObserver prevents removal. The watermark deters screenshot sharing.
CDP heartbeat
Cloud browser providers terminate sessions after detecting inactivity. PassAgent maintains a CDP heartbeat every 20 seconds viapage.evaluate(() => Date.now()), which generates real Chrome DevTools Protocol traffic. After 3 consecutive heartbeat failures, the session is considered dead and is cleaned up automatically.
The active session store uses
globalThis to survive Next.js Hot Module Reloading. Without this, dev-mode file edits would drop all CDP connections and kill active sessions.Duration and cost
| Duration | Label | Estimated cost |
|---|---|---|
| 15 min | Quick share | ~$0.03 |
| 60 min | 1 hour | ~$0.11 |
| 240 min | 4 hours | ~$0.41 |
| 480 min | 8 hours | ~$0.82 |
HYPERBROWSER_COST_PER_MIN_CENTS environment variable. The GET /api/session-sharing/estimate endpoint returns cost estimates for all supported providers.
Viewer tokens and tracking
Each viewer receives a unique token with a 5-minute TTL stored in Redis atsession_viewer:{token}. The token is renewed by periodic heartbeat calls from the viewer’s browser. Viewer counts are tracked atomically using Redis INCR/DECR to prevent race conditions from concurrent access.
Auto-logout
When a session ends, PassAgent navigates the browser to the service’s known logout URL before termination. Thelogout-urls.ts registry maps 40+ services (Netflix, Spotify, GitHub, Slack, Amazon, etc.) to their logout endpoints. For unknown services, a fallback sequence tries common paths: /logout, /signout, /sign-out, /log-out, /api/auth/logout, and /api/logout.
Scheduled sessions
Sessions can be scheduled for future start times. Credentials are encrypted withSERVER_ENCRYPTION_KEY (AES-256-GCM) and stored in Redis with a TTL matching the scheduled time plus a 10-minute buffer. A cron job picks up scheduled sessions and starts the login process at the appropriate time.
API endpoints
| Method | Endpoint | Description |
|---|---|---|
POST | /api/session-sharing | Create a new session share (step-up auth required) |
GET | /api/session-sharing | List your session shares |
GET | /api/session-sharing/estimate | Get cost estimates for a duration |
GET | /api/session-sharing/[id] | Get session details |
GET | /api/session-sharing/[id]/status | Poll session status |
GET | /api/session-sharing/[id]/events | Get session event log |
POST | /api/session-sharing/heartbeat | Viewer heartbeat (renews token) |
GET | /api/session-sharing/viewer | Viewer access (returns live URL) |
GET | /api/session-sharing/access/[token] | Token-based viewer entry point |
GET | /api/session-sharing/analytics | Session usage analytics |