Skip to main content

Overview

Account discovery scans your connected Gmail inbox to find every service you have ever signed up for. It searches for welcome emails, verification emails, password reset notifications, and sign-in alerts to build a comprehensive list of your online accounts. Discovered accounts are matched against your vault to show which services are already stored and which are missing — giving you a complete picture of your digital footprint.

How it works

Gmail search queries

PassAgent runs seven targeted Gmail searches designed to catch the common email patterns services send during account creation and use:
QueryWhat it catches
subject:("welcome to" OR "thanks for signing up" OR "thanks for joining")Onboarding emails
subject:("verify your email" OR "confirm your email" OR "email verification")Email verification
subject:("your account" OR "account created" OR "account confirmation")Account creation
subject:("get started" OR "getting started")Activation emails
subject:("password reset" OR "reset your password" OR "change your password")Password reset
subject:("new sign-in" OR "security alert" OR "login notification")Security alerts
subject:("subscription" OR "your plan" OR "your order" OR "order confirmation")Commerce
Each query returns up to 75 results. Message metadata (From and Date headers) is fetched in batches of 50 using format: "metadata" for efficiency — full message bodies are never read.
PassAgent uses read-only Gmail API scopes. It reads only the From and Date headers of matching messages. It does not read email bodies, attachments, or any messages that do not match the discovery queries.

Domain extraction

The extractDomainFromEmail() function parses the From header to extract the sender’s domain, then strips common email infrastructure subdomains to get the actual service domain: Stripped prefixes: mail., email., mailer., noreply., notify., notifications., accounts., account., info., news., newsletter., support., help., no-reply., updates., marketing., transactional., bounce., e., em., m., mg., post., comms. For example, noreply@email.spotify.com becomes spotify.com.

Filtered domains

Email infrastructure providers and personal email services are excluded from results since they represent the email platform, not a service account:
gmail.com, google.com, googlemail.com, outlook.com, hotmail.com, live.com, microsoft.com, yahoo.com, aol.com, icloud.com, me.com, mac.com, mail.com, protonmail.com, proton.me, mailchimp.com, sendgrid.net, sendgrid.com, amazonses.com, mandrillapp.com, mailgun.org, mailgun.com, postmarkapp.com, sparkpostmail.com, mailjet.com, sendinblue.com, brevo.com, constantcontact.com, campaignmonitor.com

Service enrichment

Each discovered domain is matched against PassAgent’s known services database using findServiceByQuery(). Matched services receive:
FieldSourceExample
serviceNameKnown services DB or domain capitalization”Spotify”
serviceIconFavicon URL from getServiceFavicon()https://spotify.com/favicon.ico
serviceColorBrand color from known services DB#1DB954
categorygetServiceCategory()”Entertainment”
loginUrlKnown login page URLhttps://accounts.spotify.com/login
Unrecognized domains fall back to the capitalized first segment of the domain (e.g., acme.com becomes “Acme”) with a generic gray color.

Vault cross-reference

Discovered accounts are matched against your existing vault entries by comparing domains. A match is found if:
  1. The vault entry’s website or url field resolves to the same domain
  2. The vault entry’s name contains the service name (case-insensitive)
  3. The vault entry’s website/URL contains the discovered domain as a substring
Matched accounts are marked inVault: true with a reference to the vault entry’s vaultPasswordId.

Sign-in discovery enrichment

The unified /api/accounts endpoint goes further by detecting which accounts use OAuth (“Sign in with Google”) instead of passwords:
1

Match connected emails to vault entries

For each connected email integration (Gmail, Outlook, Yahoo), PassAgent checks which vault entries use that email as the username.
2

Detect passwordless accounts

Vault entries where the username matches a connected email AND the password field is empty (or contains only whitespace/placeholder text) are flagged as likely OAuth sign-ins.
3

Generate synthetic entries

Vault entries that use a connected email but were not found during the Gmail scan are surfaced as synthetic discovered accounts, ensuring complete coverage.

Response format

The discovery response includes both the account list and summary statistics:
{
  "accounts": [...],
  "connectedEmails": [
    { "id": "...", "email": "user@gmail.com", "provider": "gmail", "connected": true }
  ],
  "stats": {
    "total": 47,
    "inVault": 32,
    "notInVault": 15,
    "oauthLikely": 8,
    "dismissed": 3
  },
  "lastScannedAt": "2024-01-15T10:30:00Z"
}
StatDescription
totalTotal discovered accounts
inVaultAccounts with a matching vault entry
notInVaultAccounts missing from the vault
oauthLikelyAccounts that appear to use OAuth (no password)
dismissedAccounts the user has dismissed

Auto-import to vault

The POST /api/accounts/add-to-vault endpoint bulk-imports discovered accounts as placeholder vault entries:
1

Select accounts to import

The user selects one or more discovered accounts (by domain) from the UI. Up to 200 accounts can be imported in a single request.
2

Check for duplicates

The server fetches existing vault entries and checks if any share a domain with the accounts being imported. Duplicates are skipped.
3

Create placeholder entries

For each new account, a vault entry is created with the service name, domain, URL (https://{domain}), and the first connected email as the username. The password field is left empty and encryption_version is set to -1 (placeholder — the client must encrypt with the vault key).
4

Update discovery status

Successfully imported accounts are marked in_vault: true in the discovered_accounts table.
Imported accounts start as placeholders without passwords. Use PassAgent’s password reset feature or manually add the password to complete the entry. This workflow ensures you know about every account even before you have the credentials stored.

Caching and persistence

Discovery results are persisted in the discovered_accounts table (auto-created if missing). Subsequent GET requests return cached results without re-scanning Gmail. The POST endpoint triggers a fresh scan and upserts results, preserving the user’s dismissed state for previously seen accounts. Stale entries (accounts from a previous scan that no longer appear) are automatically removed.

Dismiss and manage

Users can dismiss irrelevant accounts via PATCH /api/accounts or PATCH /api/discover-accounts with { id, dismissed: true }. Dismissed accounts are hidden from the default view but remain in the database and can be un-dismissed at any time.

Rate limiting

EndpointLimitWindow
POST /api/discover-accounts (scan)5 requests1 hour
POST /api/accounts (scan)30 requests60 seconds
PATCH /api/accounts (dismiss)60 requests60 seconds
POST /api/accounts/add-to-vault30 requests60 seconds
The Gmail scan endpoint has a stricter hourly limit because each scan consumes Gmail API quota.

Token management

Gmail OAuth tokens are automatically refreshed before each scan. If a token refresh fails, the integration is marked as disconnected and the user is prompted to reconnect. A Redis lock (gmail_refresh_lock:{userId}) prevents concurrent token refresh races when multiple requests arrive simultaneously.
If all Gmail API queries return 401/403 errors during a scan, the integration is automatically marked as disconnected. The user must re-authorize Gmail access from the Settings page.

API endpoints

MethodEndpointDescription
GET/api/discover-accountsReturn cached discovered accounts
POST/api/discover-accountsTrigger a fresh Gmail scan
PATCH/api/discover-accountsDismiss or un-dismiss an account
GET/api/accountsReturn discovered accounts with sign-in enrichment
POST/api/accountsTrigger a scan with optional email filter
PATCH/api/accountsDismiss/un-dismiss or mark accounts in vault
POST/api/accounts/add-to-vaultBulk-import discovered accounts as vault placeholders
The /api/accounts endpoint is the newer, unified version that supports multiple connected email providers and OAuth sign-in detection. The /api/discover-accounts endpoint is the original implementation that supports Gmail only. Both are functional; the unified endpoint is recommended for new integrations.