Skip to main content

Auth Gate

MonoSurf requires explicit human authorization before AI can access any site. All access is time-limited — when the grant expires, everything locks.

The Model

┌──────────────────────────────────────────────────────────────────┐
│  Auth Gate                                                        │
├──────────────────────────────────────────────────────────────────┤
│                                                                   │
│  Human action:  monosurf auth grant write 24h                     │
│                 ↓ physical command = proof of intent               │
│                                                                   │
│  24 hours:      AI can read and write freely                      │
│                 Cookies retrieved from keychain                    │
│                 Injected into Chrome per request                   │
│                                                                   │
│  After 24h:     Grant expires automatically                       │
│                 Keychain access blocked                            │
│                 Chrome has no cookies                              │
│                 AI sees logged-out pages = useless                 │
│                                                                   │
│  To resume:     Human runs grant again                            │
│                                                                   │
└──────────────────────────────────────────────────────────────────┘

Commands

monosurf auth grant                 # write scope, 24 hours (default)
monosurf auth grant read 1h         # read-only, 1 hour
monosurf auth grant write 7d        # read + write, 7 days
monosurf auth revoke                # revoke all immediately
monosurf auth revoke write          # revoke write only
monosurf auth status                # show active grants

Scopes

ScopeIncludesUse Case
readRead onlyBrowse, search, extract content
writeRead + WritePost, reply, interact
fullEverythingAlias for write
write automatically includes read. You don’t need both.

Duration Limits

FormatExampleMaximum
Minutes30m
Hours24h
Days7d28d
Default: write 24h. Maximum: 28d.

How Credentials are Protected

Login (One-Time)

monosurf login x.com
  1. Opens Chrome browser to site’s login page
  2. Human logs in manually
  3. MonoSurf extracts cookies via CDP
  4. Cookies encrypted and stored in macOS Keychain
  5. Cookies removed from Chrome profile
After login, credentials exist ONLY in the Keychain — not on disk, not in the browser.

Per-Request Flow

monosurf x.com search "rust"

1. Check auth gate → grant active?
   NO  → "Scope 'read' not granted. Run: monosurf auth grant"
   YES ↓
2. Retrieve cookies from keychain
3. Inject into Chrome tab
4. Navigate + extract
5. Return result

Grant Expiry

When a grant expires:
  • Keychain access is blocked by the gate
  • Chrome tabs don’t receive cookies
  • Sites show logged-out content
  • Write operations are refused
No timer runs in the background. The gate simply checks expires_at < now on every request.

Storage Architecture

┌─────────────────────────────────────┐
│  macOS Keychain                     │
│  └── ai.monolex.monosurf           │
│      └── AES-256-GCM encrypted     │
│          ├── cookies:x.com          │
│          ├── cookies:reddit.com     │
│          └── cookies:github.com     │
├─────────────────────────────────────┤
│  Auth Gate State (JSON file)        │
│  └── grants:                        │
│      ├── scope: write               │
│      │   granted_at: 1712100000     │
│      │   expires_at: 1712186400     │
│      └── ...                        │
└─────────────────────────────────────┘
The grant state is a simple JSON file — it only records WHEN access was granted and WHEN it expires. The actual secrets (cookies) live exclusively in the Keychain. Even if someone reads the grant file, they can’t access the cookies without the Keychain encryption key.

Reusable Library

The auth gate is implemented as lib-auth-gate — a standalone Rust library that any tool can use:
lib-auth-gate
├── grant(scope, duration)       → create time-limited grant
├── check(scope)                 → verify grant is active
├── revoke(scope)                → immediate revocation
├── store_secret(scope, k, v)    → gated keychain write
├── get_secret(scope, k)         → gated keychain read
└── status()                     → list all grants
The same library can be used by kernel-cli, niia, or any future tool that needs time-limited human authorization.

Comparison with Kernel-CLI

MonoSurf Auth GateKernel-CLI OTP
Human proofCLI commandEmail OTP
Token signingLocal (no server)Server Ed25519
Scoperead / writeobserve / control
Duration30m to 28d10m to 4h
StorageKeychain (local)File + signature
Use caseSocial media accessOS-level control
MonoSurf’s gate is lighter (no server, no OTP) because the risk is lower — social media posts vs OS-level control. The architecture is the same: human grants, machine checks, time expires.

Security Model by App Type

OpenCLIs tools have different verification levels depending on how they’re accessed:
┌──────────────────────────────────────────────────────────────────┐
│  App                  Auth      Server     Quota    Offline      │
├──────────────────────────────────────────────────────────────────┤
│  monolex-web          Required  Every req  Yes      No           │
│  session-gateway      Required  Every conn Yes      No           │
│  Tauri desktop        License   On start   No       Yes (cached) │
│  headless daemon      Device    Every conn No       No           │
│  monosurf CLI         Optional  Optional   If login Yes          │
│  niia CLI             Optional  Optional   If login Yes          │
└──────────────────────────────────────────────────────────────────┘

Web Apps (Always Verified)

Web apps (monolex-web, session-gateway) require authentication on every request. All traffic passes through Cloudflare Workers with D1 verification. There is no anonymous mode — login is mandatory.

CLI Tools (Verification Optional)

CLI tools (monosurf, niia) can run locally without any server connection. This creates two modes: Logged in:
  • Server verification on every command (quota check via D1)
  • Usage tracking + billing attribution
  • Plugin tamper detection via server checksum
  • Subscription benefits (unlimited quota, per-dev access)
  • D1 cost covered by subscription revenue
Not logged in:
  • No server calls (D1 cost = $0)
  • No verification, no tracking, no protection
  • Official plugins (source: openclis) still work
  • Non-official plugins (partner/dev/local) require login
  • Local checksum only — user’s responsibility
This is intentional. Unregistered CLI users cost nothing to serve. Server verification is a service that comes with registration. The warning is clear:
[monosurf] WARNING: Not logged in. Plugins run without server verification.
           Run 'monosurf login' for quota, updates, and tamper protection.

Why the Split

Web app user → always online → server verification is free (already routing through CF)
CLI user     → sometimes offline → server verification is an extra HTTP call per command
                                → D1 write per event = cost
                                → only worth it if user pays (quota/subscription)
The cost model drives the security model. Web verification is inherent to the architecture. CLI verification is opt-in because it has a marginal cost per call.