npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@qitech/1pwd-proxy

v0.0.3

Published

Local HTTP proxy that resolves 1Password secret references (op://) via the 1Password CLI. Cross-platform autostart for Postman Community and similar tools.

Readme

@qitech/1pwd-proxy

Local HTTP proxy that pulls secrets from 1Password using your desktop biometric unlock. Drop-in solution for tools without native 1Password integration (Postman Community, curl, ad-hoc scripts, CI runners on a developer machine).

Cross-platform autostart: launchd (macOS), systemd user units (Linux), Task Scheduler (Windows).


5-minute setup

1. Install the 1Password CLI

| OS | command | |---|---| | macOS | brew install 1password-cli | | Windows | winget install AgileBits.1Password.CLI | | Linux | follow the official guide |

Then in the 1Password desktop app:

Settings → Developer → enable "Integrate with 1Password CLI"

Unlock the app once. From now on, op will use biometrics via the desktop.

Verify it works:

op vault list

If you see your vaults listed, you're good.

2. Install this proxy

npm install -g @qitech/1pwd-proxy

3. Run the doctor to check everything

1pwd-proxy doctor

You'll see something like:

✓ op CLI installed (2.34.0)
✓ op CLI can talk to 1Password (desktop integration enabled)
✗ proxy not responding on port 7777 (not listening)
   Run: 1pwd-proxy install   (to register autostart)

4. Start the proxy as a background service

1pwd-proxy install

This registers it to start automatically on login (launchd / systemd / Task Scheduler depending on your OS) and starts it now. Verify:

1pwd-proxy doctor
# all three checks should be ✓

5. Pull a secret

curl "http://localhost:7777/op://YourVault/YourItem/password"

You should see the secret value as plain text. Done — the proxy is ready to use.

6. (Optional) Generate a Postman pre-request script for your item

Instead of writing the script by hand and looking up each field id, let the CLI do it for you:

1pwd-proxy postman-snippet YourVault YourItem

It prints a ready-to-paste pre-request script with the right field ids and field names derived from your labels. Pipe to pbcopy (macOS) / clip (Windows) / xclip (Linux) to copy directly to your clipboard:

1pwd-proxy postman-snippet YourVault YourItem | pbcopy

Setting up 1Password for your secrets

If you already have your credentials in 1Password, skip ahead to Using with Postman.

Create a vault (optional but recommended)

A dedicated vault for automation credentials keeps things organized:

op vault create apis

Or in the desktop app: sidebar → New vault.

Add an item

Pick a category in the desktop app that matches your use case:

| category | when to use | |---|---| | Login | Username + password (+ optional TOTP) for a service | | API Credential | API key with metadata (filename, valid range, etc.) | | Secure Note | Free-form: anything that doesn't fit elsewhere |

For credentials that don't fit the built-in fields (e.g. client_secret, tenant_id, api_key), click Add more while editing the item and add custom fields.

Find the field IDs of your item

The proxy resolves fields by id, not by display label. Built-in fields have stable ids (username, password, notesPlain). Custom fields and TOTP fields have generated ids.

List them with op:

op item get "MyItem" --vault "MyVault" --format json | jq '.fields[] | {id, label, type}'

Example output:

{"id": "username", "label": "username", "type": "STRING"}
{"id": "password", "label": "password", "type": "CONCEALED"}
{"id": "notesPlain", "label": "notesPlain", "type": "STRING"}
{"id": "TOTP_abc123xyz", "label": "one-time password", "type": "OTP"}
{"id": "4a8b2c1d9e0f", "label": "client_secret", "type": "CONCEALED"}

Notes on what you'll see:

| field type | id pattern | how to read it | |---|---|---| | Built-in (username, password, notesPlain) | the literal name | GET /op://Vault/Item/username | | TOTP / one-time password | TOTP_<random> | GET /otp/Vault/Item (returns the live 6-digit code) | | Custom fields | random alphanumeric | GET /op://Vault/Item/<id> |

The label is also usable as a reference (e.g. op://Vault/Item/client_secret), but the id is stable — if anyone renames the field's label, references-by-label break, references-by-id don't.


Endpoints

All requests are local (127.0.0.1 only).

| endpoint | what it does | |---|---| | GET /health | returns ok — use this to check the proxy is up | | GET /op://<vault>/<item>/<field> | resolves a single field via op read (URL-encoded path) | | GET /otp/<vault>/<item> | returns the current 6-digit OTP via op item get --otp. Use this when a TOTP field doesn't resolve via op read. | | GET /item/<vault>/<item> | returns the full item JSON. One biometric prompt, all fields including the generated TOTP code in the totp property of the OTP field. Recommended when you need multiple fields from the same item. |

Examples

# health
curl http://localhost:7777/health

# single field
curl "http://localhost:7777/op://apis/MyService/password"

# whole item
curl http://localhost:7777/item/apis/MyService | jq

# TOTP (always 6 digits)
curl http://localhost:7777/otp/apis/MyService

Using with Postman

Postman Community has no built-in 1Password integration. With this proxy, a collection-level pre-request script can pull live secrets and inject them into requests without storing anything in environment variables.

Recommended pattern

In your collection's Scripts → Pre-request:

// clear any stale tokens lying around
pm.environment.unset('AccessToken');
pm.collectionVariables.unset('AccessToken');

// fetch the entire item in ONE biometric prompt
const item = await new Promise((resolve, reject) => {
    pm.sendRequest(
        'http://localhost:7777/item/apis/MyService',
        (err, r) => {
            if (err || r.code !== 200) return reject(err || r.text());
            resolve(r.json());
        }
    );
});

// extract fields by id (use the ids you found via `op item get ... | jq`)
const fieldById = (id) => {
    const f = item.fields.find(x => x.id === id);
    if (!f) throw new Error(`field not found: ${id}`);
    return f.totp || f.value;
};

const username      = fieldById('username');
const password      = fieldById('password');
const totp          = fieldById('TOTP_abc123xyz');     // your TOTP field id
const client_secret = fieldById('4a8b2c1d9e0f');       // your custom field id
const client_id     = pm.collectionVariables.get('client_id'); // non-secret static value

// example: OAuth password grant
const tokenRes = await new Promise((resolve, reject) => {
    pm.sendRequest({
        url: 'https://auth.example.com/oauth/token',
        method: 'POST',
        header: { 'Content-Type': 'application/x-www-form-urlencoded' },
        body: {
            mode: 'urlencoded',
            urlencoded: [
                {key: 'grant_type',    value: 'password'},
                {key: 'client_id',     value: client_id},
                {key: 'client_secret', value: client_secret},
                {key: 'username',      value: username},
                {key: 'password',      value: password},
                {key: 'totp',          value: totp},
            ]
        }
    }, (err, res) => {
        if (err) return reject(err);
        resolve(res.json());
    });
});

// expose to templates in LOCAL scope (cleared after this request finishes)
pm.variables.set('AccessToken', tokenRes.access_token);
pm.variables.set('OTP', totp);

In each request's Headers tab:

| Key | Value | |---|---| | Authorization | Bearer {{AccessToken}} | | OTP | {{OTP}} (only if your API requires it) |

pm.variables.set writes at local scope, which Postman discards after each request. The secrets never reach your collection/environment storage.

Simpler use case — single secret

If you only need one static field (no OAuth, no TOTP):

const password = await new Promise((resolve, reject) => {
    pm.sendRequest(
        'http://localhost:7777/' + encodeURIComponent('op://apis/MyService/password'),
        (err, r) => r.code === 200 ? resolve(r.text()) : reject(err || r.text())
    );
});

pm.variables.set('SERVICE_PASS', password);

CLI reference

| command | what it does | |---|---| | 1pwd-proxy doctor | check op CLI, desktop integration, and proxy health | | 1pwd-proxy start [--port N] | run in the foreground (use during development) | | 1pwd-proxy install [--port N] | register autostart for your OS and start it now | | 1pwd-proxy uninstall | remove autostart | | 1pwd-proxy status | show service status | | 1pwd-proxy logs | print log file paths | | 1pwd-proxy postman-snippet <vault> <item> | generate a Postman pre-request script tailored to that item |

Default port is 7777, configurable via --port. The server always binds to 127.0.0.1 (no remote access).


How it works

Postman ──HTTP──> 1pwd-proxy (localhost:7777) ──exec──> op CLI ──IPC──> 1Password desktop ──biometric──> you

The proxy validates request paths with a strict regex and calls op via execFile (no shell interpolation). It does no caching — every request hits op, so values are always fresh. That matters for TOTP, where stale codes get rejected.


Troubleshooting

Run 1pwd-proxy doctor first — it tells you which of the three layers is broken.

| symptom | what to check | |---|---| | op CLI not found | Install with brew/winget/apt (see step 1 above) | | op CLI cannot reach 1Password desktop | Open the desktop app → Settings → Developer → enable "Integrate with 1Password CLI", then unlock | | proxy not responding | Run 1pwd-proxy install (or 1pwd-proxy start to test in foreground) | | curl /op://... returns field not found | Verify the field id with op item get <item> --vault <vault> --format json \| jq '.fields[] \| {id, label}' | | TOTP returns the seed instead of a 6-digit code | Use GET /otp/<vault>/<item> instead of GET /op://... |

Logs

| platform | location | |---|---| | macOS | ~/.1pwd-proxy/{out,err}.log | | Linux | journalctl --user -u 1pwd-proxy.service | | Windows | Event Viewer / Task Scheduler history |


Security notes

  • The server binds to 127.0.0.1 only — no remote access.
  • Reference paths are validated by regex before being passed to execFile, blocking shell injection.
  • op only resolves secrets while the 1Password desktop is unlocked, so the attack surface is the same as any tool a logged-in user can run.
  • Resolved secret values are never logged — only timestamps, request paths, and error messages.

Uninstall

1pwd-proxy uninstall
npm uninstall -g @qitech/1pwd-proxy

Contributing / development

git clone <repo>
cd 1pwd-proxy
npm link                    # makes the local source executable as `1pwd-proxy`
1pwd-proxy doctor

Test the server directly: node bin/cli.js start. Stop with Ctrl+C.

Releasing a new version

npm version patch    # bumps version + creates git tag
npm publish          # publishes under the @qitech scope

Consumers update with:

npm install -g @qitech/1pwd-proxy@latest
1pwd-proxy uninstall && 1pwd-proxy install

The uninstall/install cycle re-registers the autostart service against the new binary path.