pollen

command module
v1.7.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 7, 2026 License: MIT Imports: 23 Imported by: 0

README

pollen

A terminal UI for testing HTTP APIs — like Postman or Thunder Client, but in your terminal. Built with Go and Bubble Tea.

Features

  • Send HTTP requests with method, headers, body (JSON / form-urlencoded / raw), and built-in Bearer / Basic auth
  • Header name autocomplete from a list of common HTTP headers
  • Request history (JSON file) with one-key restore and 5-second undo-delete
  • Collections: save named requests (Ctrl+B), browse/load/rename/delete from a sidebar (Ctrl+K), update-in-place after loading
  • Variable environments: {{varName}} expansion from env.json, multiple named environments (dev / staging / prod / …), switch at runtime with Ctrl+E
  • Request chaining: {{response.body.<jq-path>}} / {{response.headers.<name>}} / {{response.status}} expand from the last response — perfect for login → use-token flows
  • jq filter (/ in response panel) for narrowing JSON output
  • In-body search (Ctrl+F in response panel) with live highlight
  • Response diff (D): character-level diff vs the previous response
  • Copy response body (y): clipboard, with a file fallback on Linux without xclip / wl-clipboard
  • Import OpenAPI 3.x (JSON/YAML) or Postman Collection v2.1 (Ctrl+I)
  • Export all collections to Postman v2.1 JSON (--export-postman) or OpenAPI 3.x JSON / YAML (--export-openapi)
  • Intruder (Ctrl+R): fire the current request against a generated payload list (numeric range, wordlist, brute force, or case toggles), with configurable concurrency and a live result table. Inspired by Burp Suite's Sniper mode
  • Binary response detection with hex dump preview, s-to-save
  • TLS options: skip verification, custom CA certificate file, HTTP(S) proxy, cookie jar, redirect control — all toggleable from settings.json
  • Copy any request as a POSIX curl command or JavaScript fetch() call
  • Terminal-control-character sanitisation: malicious or buggy server output can't smuggle ANSI escapes through the renderer

Install

From source
go install github.com/lea-151107/pollen@latest

Or build a local checkout (lets you embed a specific version string):

git clone https://github.com/lea-151107/pollen.git
cd pollen
go build -ldflags="-X github.com/lea-151107/pollen/internal/version.Version=$(git describe --tags)" -o pollen .
./pollen --version
Pre-built binaries

Each release publishes Linux / macOS / Windows binaries (amd64 + arm64) on the Releases page. Download the archive for your platform and unpack the pollen binary into a directory on your PATH.

Requirements
  • Go 1.21+ (only for building from source)
  • On Linux, the clipboard (Ctrl+Y / y) requires xclip or wl-clipboard. Without either, pollen writes the content to ~/.config/pollen/clipboard.txt as a fallback.

Keybindings

Press Ctrl+/ inside the app for the full list at any time.

Global
Key Action
Tab / Shift+Tab Move focus between panels
Ctrl+S Send request
Ctrl+Yc / f Copy request as cURL / fetch
Ctrl+H Toggle history panel
Ctrl+K Toggle collections panel
Ctrl+B Save current request to collection (or update if loaded from one)
Ctrl+I Import OpenAPI / Postman file into collections
Ctrl+E Switch variable environment
Ctrl+T Toggle TLS verification skip (persists)
Ctrl+L Force terminal redraw (recover from stray output)
Ctrl+/ Show help overlay
Ctrl+R Open Intruder (concurrent requests against a payload list)
u Undo last history delete (within 5 s)
Ctrl+C Quit
Panel-specific
  • History: ↑/↓ move · G jump to last · gg jump to first · Enter load · d delete · / filter (Esc clears)
  • Collections: ↑/↓ move · G / gg jump · Enter load · e rename · d delete · / filter (Esc clears)
  • Method: ↑/↓ cycle methods
  • Query: ↑/↓ ←/→ navigate · Enter new row · Ctrl+D delete row
  • Auth: ←/→ switch type (None/Bearer/Basic) · Enter/↓ edit fields · Esc/↑ back
  • Headers: ↑/↓ ←/→ navigate · Enter new row · Ctrl+D delete row · Tab accept suggestion
  • Body: ←/→ switch tab · Enter enter editor · Tab indent (2 spaces) · Esc leave editor
  • Response: ↑/↓ PgUp/PgDn scroll · s save body to file · y copy body · / jq filter · Ctrl+F search in body · D toggle diff vs prev

Authentication

The Auth panel between Query and Headers offers three modes:

  • None: no Authorization header is added
  • Bearer: enter a token; the request gets Authorization: Bearer <token>
  • Basic: enter username/password; the request gets Authorization: Basic <base64(user:pass)> (password input is masked)

Use ←/→ on the type-selector row to switch modes, then Enter/ to drop into the fields. Esc or returns to the type selector.

If the Headers panel already contains an explicit Authorization entry, the Auth panel does not override it — your manual value wins.

Auth state is session-only: it's not stored in ~/.config/pollen/, and loading a history entry resets the panel to None (Authorization remains in the restored Headers, so the request still works).

Query parameters

The Query panel between the URL bar and Headers is a dedicated editor for URL query parameters. Use it instead of typing ?key=val&key2=val2 into the URL bar:

  • Keys and values are URL-encoded automatically when the request is sent
  • When the query panel has entries, any ?... already in the URL bar is discarded so the panel is the authoritative source
  • When the URL contains {{var}} tokens (un-parseable), the parameters are concatenated as a string with ? / & separators
  • Reloading an entry from history splits its full URL — the parameters land back in the Query panel, the URL bar shows only the base URL

CLI flags

pollen [--option ...]
Flag Effect
--version Print the version and exit
--config <dir> Use <dir> as the config directory instead of ~/.config/pollen
--env <name> Activate the named environment at startup (warning to stderr if unknown)
--collection <name> Open the Collections sidebar pre-filtered by this name
--init-config Write a default settings.json to the config directory and exit
--export-postman <path> Export all collections to a Postman v2.1 JSON file. Use - to write to stdout
--export-collections <path> Alias for --export-postman, kept for backwards compatibility
--export-openapi <path> Export all collections as an OpenAPI 3.x document. Format is picked by extension (.yaml / .yml → YAML, otherwise JSON). Use - for JSON on stdout
--export-intruder <path> Export the most recent Intruder run as CSV (default) or JSON (when <path> ends in .json). Use - for CSV on stdout. Exits with status 2 if no run has been recorded yet

Examples:

pollen --env staging                                   # start in staging environment
pollen --config ./myproject/.pollen                    # project-local config
pollen --collection "User API"                         # open with "User API" pre-selected
pollen --init-config                                   # seed default settings.json
pollen --export-postman /tmp/pollen-collections.json
pollen --export-openapi /tmp/pollen-openapi.yaml      # OpenAPI 3.0.3 in YAML
pollen --export-intruder /tmp/intruder.csv            # last Intruder run

Configuration

All configuration lives in ~/.config/pollen/ (or the directory passed via --config). Files are JSON and are written atomically (.tmp + rename) so a crash mid-write never leaves a corrupt half-file.

File Purpose
history.json Request/response history (most-recent first, capped at history_limit)
collections.json Named saved requests
settings.json Persistent toggles and tunables
env.json User-defined variables for {{name}} expansion
clipboard.txt Clipboard fallback if xclip/wl-clipboard missing
settings.json

Run pollen --init-config to create the file pre-populated with the defaults below. Every field is optional; missing or out-of-range values fall back to the default silently so a partial or corrupt file never blocks startup.

Field Default Notes
skip_tls_verify false Toggle at runtime with Ctrl+T
response_panel_ratio 0.5 Fraction of available width given to the response panel (0.0–1.0 exclusive)
request_timeout_secs 60 HTTP client timeout (1–600 s)
max_response_mib 32 Response body cap; bytes past this are dropped and Truncated is set (1–1024 MiB)
history_limit 200 Maximum entries kept in history.json (1–10000)
text_preview_kib 100 Display truncation threshold for text bodies; s still saves the full body (1–10240 KiB)
sidebar_max_width 40 Maximum column width of the history/collections sidebar (20–200)
hex_dump_kib 4 Bytes shown in the hex dump preview for binary bodies (1–1024 KiB)
proxy_url "" When non-empty, routes all requests through this HTTP(S) proxy
disable_redirects false When true, returns 3xx responses as-is instead of following them
ca_cert_file "" Path to a PEM file with extra trusted CAs (safer than skip_tls_verify for internal/self-signed certs)
enable_cookies false When true, cookies set by a response are replayed in subsequent requests within the same session

History stores binary response metadata only — the body bytes are dropped to keep the JSON readable and small. In-memory body bytes are also dropped from history entries past the 10 most recent prepends to bound memory growth. Reload a binary entry from outside that window and you'll see the size / Content-Type only.

Variables and environments

Pollen expands {{name}} tokens in the URL, header values, and request body at send time, looking up the name in the currently active environment from ~/.config/pollen/env.json:

{
  "current": "dev",
  "environments": {
    "dev": {
      "baseUrl": "http://localhost:8080",
      "token": "dev-token"
    },
    "prod": {
      "baseUrl": "https://api.example.com",
      "token": "sk-live-abc123"
    }
  }
}

Use the variables in any request:

  • URL: {{baseUrl}}/v1/users
  • Header Authorization: Bearer {{token}}
  • Body: { "callback": "{{baseUrl}}/done" }

Switch environments at runtime with Ctrl+E — a menu lists every environment defined in env.json. The selection is persisted, so the next launch starts in the same environment. --env <name> at startup overrides the persisted selection for that session.

The status bar shows the active environment as [env: dev] whenever any environment is selected.

Notes:

  • The v0.1.0 flat-vars format is migrated automatically into a single default environment on first load
  • Unknown names (no entry in the active env) are left untouched so you can spot unresolved references in the response or saved history
  • Expansion is single-pass — a value that itself contains {{...}} is not re-expanded (avoids infinite loops)
  • History stores the expanded form, so secrets in env.json end up in history.json once sent. Treat history.json with the same care as any file containing credentials
Request chaining

After receiving a response, reference its values in the next request using {{response.*}} tokens. These are evaluated after env-variable tokens:

Token Value
{{response.body.<path>}} jq path applied to the last JSON response body
{{response.body}} whole response body as a string
{{response.headers.<name>}} response header value (case-insensitive name)
{{response.status}} HTTP status code as a string, e.g. "200"

Example — log in, then use the token in the next request:

  1. POST {{baseUrl}}/auth/login with credentials in the body
  2. Next request: header Authorization: Bearer {{response.body.token}}

If no previous response exists, or the jq path produces no match, the token is left untouched.

Collections

Press Ctrl+B to save the current request with a name — a dialog prompts for the name (blank defaults to "Untitled"). Saved entries are stored in ~/.config/pollen/collections.json.

Press Ctrl+K to toggle the Collections sidebar. Like the History panel, it supports:

  • ↑/↓ to move between entries (also G / gg for jump-to-end / start)
  • Enter to load the request into the editor
  • e to rename the selected entry
  • d to delete the entry
  • / to filter by name, method, or URL

Ctrl+H (History) and Ctrl+K (Collections) are mutually exclusive — showing one closes the other.

Editing saved requests
  • Press e on a selected entry to rename it — a dialog pre-fills the current name
  • Load an entry with Enter, then modify the request and press Ctrl+B to choose:
    • Enter — update the loaded entry in-place
    • n — save as a new entry (original is unchanged)
Importing from a spec

Populate collections from an existing API spec:

  • OpenAPI 3.x (.json or .yaml): each path × method pair becomes one entry. Entry names come from summaryoperationIdMETHOD /path, in that order. The first server URL is used as the base. Required query parameters are appended as empty placeholders.
  • Postman Collection v2.1 (.json): each request item (including nested folders) becomes one entry, preserving name, method, URL, headers, raw body and url-encoded form body.

Press Ctrl+I, enter the file path (supports ~), and press Enter to import. See examples/ for sample input files.

Exporting collections

Postman v2.1:

pollen --export-postman collection.json    # write to file
pollen --export-postman -                  # write to stdout (for piping)

The output is a Postman Collection v2.1 JSON document. Form-urlencoded bodies are serialised as Postman's urlencoded array, raw bodies as mode: raw.

--export-collections is kept as an alias for --export-postman so existing scripts keep working. Specifying both flags at the same time is an error.

OpenAPI 3.x:

pollen --export-openapi api.yaml               # YAML (extension picks format)
pollen --export-openapi api.json               # JSON
pollen --export-openapi -                      # JSON on stdout

The output is OpenAPI 3.0.3. When every entry shares one scheme://host, that host is emitted as servers[0].url and each entry's path is relative; mixed or template-tokenised hosts ({{baseURL}}/users/...) skip the servers block and keep the raw URL as the path key. Headers and URL query strings become parameters entries with an example field set to the stored value. Body contents are emitted under the natural media type — application/json for JSON bodies, application/x-www-form-urlencoded for form bodies (with each pair as a typed property), text/plain (or any explicit Content-Type header) for raw bodies. No header masking is performed: Authorization, Cookie, and other sensitive headers will appear in the exported spec, so review before sharing.

Intruder

Press Ctrl+R to open the Intruder modal. It fires the current request template against a generated sequence of payloads using a worker pool — think Burp Suite's Sniper attack mode, scoped to one payload position.

Mark where the payload should go with the reserved token {{$payload}} anywhere in the URL, body, or header values:

URL:    https://api.example.com/users/{{$payload}}
Body:   {"id": "{{$payload}}"}
Header: X-API-Key: {{$payload}}

{{$payload}} survives {{varName}} and {{response.*}} expansion unchanged, so you can combine env variables, response chaining, and an Intruder run in the same request.

Pollen ships three attack modes; the config modal's first row picks which ( / to cycle):

Mode Lists × positions Iteration
Sniper 1 list × any positions Same payload substituted at every marker (Burp's "Battering ram" for free — mark multiple positions and each receives the same value)
Pitchfork N lists × N positions Zip (request k uses list1[k], list2[k], …, lN[k]); stops at the shortest list
ClusterBomb N lists × N positions Cartesian product (every combination, bounded by intruder_max_requests)

For Pitchfork / ClusterBomb the second row picks the number of payload positions (2–8). Mark them in the request as {{$payload1}}, {{$payload2}}, …, up to the position count you chose. {{$payload}} is preserved as an alias of {{$payload1}} so existing v1.2.x templates still run unchanged under Sniper.

URL:    https://api.example.com/login?user={{$payload1}}&pass={{$payload2}}
Body:   {"token":"{{$payload3}}"}

In each payload position pick a kind with / and enter its parameters. Format strings appear inline below the input.

Kind Format Example
Range <from>-<to> or <from>-<to>/<step> 1-100/5
List a,b,c or @/path/to/wordlist admin,root,guest
Brute <alphabet> <min>-<max> abc 1-3
CaseToggle <base> admin (16 permutations of upper/lower)

Concurrency, Delay (ms), and Max requests are pre-filled from settings.json. Press Enter to start; the modal becomes a live table that streams in as workers complete each request:

  • ↑/↓ PgUp/PgDn move the row cursor (the ▶-marked row); g / G jump to the first / last row

  • Enter opens a per-result detail view showing the full HTTP response (status, headers, body) for that row. ↑/↓ PgUp/PgDn scroll the body; Esc returns to the table. The body is body-cap truncated by intruder_response_body_cap_kib (default 64 KiB) so a 1000-payload run doesn't pin GiBs of RAM; when truncated a hint at the bottom says so

  • 4xx rows are tinted yellow, 5xx and network-error rows red

  • Outlier rows whose size deviates by more than 50% from the median (of the visible / filtered set) get a ! marker on their size cell

  • s cycles the sort column (#statussizems#). The active column shows a ▲ / ▼ marker. Shift+S reverses the current direction

  • / opens a filter prompt. The DSL is small but composable:

    Token Meaning
    admin payload substring contains "admin" (case-insensitive)
    size:>1000, size:<100, size:1000-2000, size:>=1024 size range
    dur:>500, dur:<10, dur:100-300 duration in milliseconds
    s:404, s:4xx, s:>=500, s:200-299 status range

    Tokens are AND-composed: /admin size:>=1000 s:4xx keeps rows where payload contains "admin" AND size ≥ 1000 AND status is 4xx. Enter commits, Esc drops. f cycles a status preset (All → Errors → 2xx → All) independent of the DSL

  • e opens an in-app CSV export prompt with a timestamped default path; Enter saves, Esc cancels

  • Esc (with no filter active) cancels the run and closes the overlay (the most recent run is still cached on disk for --export-intruder)

To export the most recent run from outside the TUI:

pollen --export-intruder results.csv     # CSV (default for stdout too)
pollen --export-intruder results.json    # JSON, indented
pollen --export-intruder -               # CSV on stdout

If no Intruder run has ever finished in the same config directory, the command exits with status 2.

GraphQL

Pollen has first-class support for GraphQL requests as one of the body tabs. In the Body panel, / cycle through JSON / FORM / RAW / GRAPHQL; on the GraphQL tab the editor area splits into a larger query pane on top and a smaller variables (JSON) pane below.

Ctrl+G (in editor mode) toggles focus between query and variables. Tab indents inside whichever pane is focused; Esc leaves editor mode as usual.

At send time pollen wraps the two panes in the canonical envelope:

{
  "query": "query ($id: ID!) { user(id: $id) { name email } }",
  "variables": { "id": 42 }
}

…and POSTs it with Content-Type: application/json. Variables that don't parse as JSON are silently omitted from the envelope (the server will surface the error). The query and variables both go through env expansion and response chaining, so you can write things like

variables: {"token": "{{authToken}}", "after": "{{response.body.cursor}}"}

…and they're resolved before the request leaves pollen.

Intruder runs on GraphQL templates: the {{$payload}}, {{$payload1}}, … markers are recognised inside the variables pane too, so fuzzing GraphQL inputs is just an ordinary Intruder run.

cURL / fetch exports build the envelope into the --data / body field; Postman v2.1 export/import round-trip the GraphQL body using the spec's native {"mode": "graphql", "graphql": {"query": "...", "variables": "..."}} shape.

multipart/form-data

Pollen's body editor has a MULTIPART tab alongside JSON / Form / Raw / GraphQL. Each line describes one part:

name=value                  text part
upload=@/path/to/file       file upload (default content-type)
img=@/path/x.png;type=image/png   file upload with explicit content-type

At send time pollen streams the file parts through mime/multipart, auto-generating the boundary and setting Content-Type: multipart/form-data; boundary=... for you. cURL export uses -F flags (-F 'meta=...' -F 'upload=@/tmp/x.png;type=image/png') so the exported command actually performs the upload. fetch export builds a FormData object with placeholder file references and a comment pointing at the original path (browser fetch needs a real File handle from an <input> that pollen can't materialise from a filesystem path).

Postman v2.1 export and import roundtrip the multipart body using the spec's native {"mode": "formdata", "formdata": [...]} shape.

Intruder markers ({{$payload}}, {{$payload1..N}}) and dynamic variables ({{$uuid}}, {{$timestamp}}, ...) work inside the multipart line-based DSL — typically in text values, but file paths can include them too if you want per-iteration file names.

cURL paste import

A --import-curl flag converts a curl command into a collections entry without launching the TUI. Three input modes:

pollen --import-curl 'curl -X POST https://api.example.com -d body'    # literal
pollen --import-curl @/tmp/cmd.txt                                     # file
pollen --import-curl -                                                 # stdin

Supported curl flags: -X / --request, -H / --header, -d / --data / --data-raw / --data-binary, --data-urlencode, -F / --form (multipart), -u / --user (becomes a Basic-auth header), -A / --user-agent, -e / --referer, --cookie / -b, -G / --get. Transport flags (-L, -k, -s, -v, -i, plus the clumped form -sLv) are silently dropped. Unsupported flags exit 1 with an error so the user knows to enter them by hand.

Method inference: -X explicit wins; -G forces GET; any data flag implies POST; otherwise GET. A Content-Type: application/json header promotes the inferred body to BodyJSON so the editor opens on the right tab.

The new entry is named <METHOD> <URL> and appended to collections.json. Successful import prints imported as <name> to stderr and exits 0.

Dynamic variables

Pollen expands a small set of pollen-computed {{$name}} tokens at send time. Unknown names are passed through unchanged, so the existing intruder marker {{$payload}} continues to work alongside these.

Token Replaced with
{{$timestamp}} Unix epoch seconds
{{$timestamp_ms}} Unix epoch milliseconds
{{$datetime}} RFC3339 UTC timestamp
{{$uuid}} UUID v4
{{$random}} random uint32
{{$random:N}} random 0..N-1
{{$random:M-N}} random M..N (inclusive)
{{$base64:VALUE}} base64-encode VALUE
{{$urlencode:VALUE}} URL-encode VALUE

Each request gets fresh values, so {{$uuid}} in an Intruder template yields a different UUID per iteration (the runner expands dynvars in the worker loop, not at template build time). Useful for correlation IDs, idempotency keys, timestamp-based queries, and rate-limit testing.

Expansion order is env vars → response chaining → dynamic vars, so an env value that embeds {{$uuid}} resolves correctly at send time.

OAuth 2.0 (Client Credentials)

The Auth panel's type selector now includes OAuth. Selecting it exposes four input rows — Token URL, Client ID, Client Secret, Scope — plus an action row at the bottom showing the current token state. Pressing g on the action row runs the OAuth 2.0 Client Credentials flow (RFC 6749 §4.4): pollen POSTs grant_type=client_credentials to the token URL with the credentials in a Basic-Auth header and parses the JSON response.

On success, the action row shows the masked token, time-to-expiry, and "press g to refresh". Pollen then injects Authorization: Bearer <access_token> on every Send while the OAuth type is selected. Errors (network, bad credentials, missing access_token) surface inline with the server's error_description when present.

Tokens fetched here are written to disk by default since v1.6.4 — see Token persistence below.

OAuth 2.0 Authorization Code with PKCE

The Auth panel's type selector adds a fifth option, OAuth AC, for the OAuth 2.0 Authorization Code grant with PKCE (RFC 6749 §4.1, RFC 7636, RFC 8252). It exposes six input rows — Auth URL, Token URL, Client ID, Client Secret (optional), Redirect URI, Scope — plus an action row.

Pressing g on the action row generates a 256-bit state and a PKCE code_verifier / S256 code_challenge, starts a tiny HTTP server bound to the loopback host and port of the Redirect URI, then opens the user's default browser at the authorization endpoint. When the IdP redirects back to the loopback callback, pollen validates state, exchanges the code for an access token at the Token endpoint (sending code_verifier), and stores the resulting token. Esc cancels an in-flight flow. The whole flow has a 5-minute timeout.

Redirect URI defaults to http://127.0.0.1:8765/callback, which matches what most IdPs let you register once and forget. Pollen only supports loopback redirects (127.0.0.1, ::1, localhost) on http:// with an explicit port — non-loopback hosts and custom schemes are refused. This follows RFC 8252's recommendation for native apps.

Public clients (no Client Secret) are supported: when Secret is left blank, pollen omits HTTP Basic auth on the token exchange and includes client_id in the form body instead.

Browser launch uses open on macOS, rundll32 url.dll,… on Windows, and wslview (if present) or xdg-open on Linux/WSL. If the launch fails the flow still runs; the URL is reachable manually if you copy it from the auth panel.

Auto-refresh on send

When the active auth type is OAuth (CC) or OAuth AC, the current access token is within 30 seconds of expiry, and a refresh token was issued, pollen issues a refresh before sending and sends with the new token transparently. Refresh failure aborts the send and the status line prompts you to re-authorize. Skipped silently for non-OAuth auth types or tokens without a refresh_token.

Token persistence (v1.6.4+)

Successful OAuth fetches (CC and AC) and refreshes are written to ~/.config/pollen/oauth_tokens.json with mode 0600 (owner read/write only). On next start, when the Auth panel contains a matching Token URL + Client ID, pollen automatically hydrates the access token + refresh token from disk — for Authorization Code that means no second browser dance, and for Client Credentials it means the in-memory cache survives a restart.

Entries are keyed by (token_url, client_id, grant). CC and AC tokens for the same IdP/client coexist. Scope is stored in each entry but not part of the key; re-fetching with a different scope overwrites the prior entry.

To forget the persisted token for the current Token URL + Client ID, press d on the Auth panel's action row (the same row where g triggers a fetch / refresh). The on-disk entry is removed and the in-memory token is cleared. A status toast confirms.

To disable persistence entirely, set "oauth_persist_tokens": false in settings.json. The default is true (opt-out). When disabled, pollen neither reads nor writes the token file — the file may still exist on disk from a prior session, but it's left untouched.

The auto-refresh-on-send path from v1.6.0 still works: a hydrated-but-expired token gets refreshed transparently before the next Send and the refreshed token is written back to oauth_tokens.json.

OAuth 2.0 Device Authorization Grant (v1.7.0+)

The Auth panel's type selector adds a sixth option, OAuth DC, for the OAuth 2.0 Device Authorization Grant (RFC 8628). It exposes five input rows — Device URL, Token URL, Client ID, Client Secret (optional), Scope — plus an action row. Unlike Authorization Code, pollen does not launch a browser: the IdP returns a short user_code and a verification_uri, and the user transcribes them on whatever device they already have logged in (laptop, phone). Once the user approves, pollen polls the token endpoint until the IdP issues the access token.

Pressing g on the action row issues the §3.1 device authorization request and begins polling per §3.4–3.5. The panel prominently displays the verification URL and user code; an (expires in M:SS) countdown reflects the authorization window the IdP returned. Esc cancels the in-flight Authorize or Poll stage. The whole flow has a 30-minute timeout.

Device Code is the OAuth grant of choice for pollen's typical environments — SSH sessions, WSL, CI runners, containers — where the Authorization Code flow's browser launch isn't viable. Headless terminals can't always open a browser, but they can always print a URL for the user to visit on a different device.

The slow_down response (RFC 8628 §3.5) is honoured: every slow_down adds 5 seconds to the poll interval as required by the spec. authorization_pending continues polling at the current interval. access_denied and expired_token are terminal errors.

Persisted Device Code tokens land in the same ~/.config/pollen/oauth_tokens.json as CC and AC tokens, keyed by (token_url, client_id, "device_code"). Auto- refresh-on-send and the d forget shortcut work identically.

In-TUI Settings overlay (v1.7.0+)

Pressing Ctrl+P (or Ctrl+, on terminals that speak the kitty / CSI-u keyboard protocol) opens a modal Settings panel that exposes all 17 keys from settings.json without leaving pollen. Boolean fields toggle inline on Enter; integer, float, and string fields drop into a textinput editor where Enter validates and commits and Esc discards. Validation matches the same ranges that settings.Load clamps; out-of-range values keep the editor open with an inline error: … line.

Each successful commit is applied to the relevant runtime global (HTTP timeout, response cap, intruder defaults, proxy URL, persist-tokens flag, …) and written back to settings.json immediately. Two fields — CA cert file and Enable cookies — are loaded only at startup and carry a restart badge so the user knows the change is persisted but takes effect on the next pollen launch.

Navigation mirrors the rest of pollen's overlays: ↑/↓ or j/k for the cursor, g/G for first/last, PgUp/PgDn to hop five rows, Esc / q to close. The Ctrl+/ help overlay's Global section advertises the binding so it's discoverable.

Versioning and stability

Pollen follows Semantic Versioning. Starting at v1.0.0, the following surfaces are part of the public, semver-covered API:

  • CLI flags and their semantics (everything documented in CLI flags)
  • Configuration file schemas (settings.json, env.json, history.json, collections.json) — fields may be added in minor releases; removing or renaming a field requires a major bump
  • Keybindings — additions in minor releases are fine; changing or removing a binding requires a major bump
  • Behaviour of variable expansion and request chaining — the {{name}} / {{response.*}} token syntax is stable

The following are not semver-covered and may change in any release:

  • The Go package layout under internal/ (this is an end-user tool, not a library)
  • Status-line wording, log messages, and UI colours
  • Terminal rendering details (spacing, borders, suggestion ordering)
  • The on-disk format of clipboard.txt

Deprecation policy: a CLI flag or settings field marked for removal will continue to function — with a pollen: ... warning to stderr — for at least one minor release before being removed in the following major release.

License

MIT

Documentation

The Go Gopher

There is no documentation for this package.

Directories

Path Synopsis
internal
app
Package app holds the Bubble Tea Model, the Update message dispatch, the View composition, and pollen-specific helpers (variable expansion, clipboard, save) that glue the UI panels to the storage and HTTP layers.
Package app holds the Bubble Tea Model, the Update message dispatch, the View composition, and pollen-specific helpers (variable expansion, clipboard, save) that glue the UI panels to the storage and HTTP layers.
collections
Package collections persists named saved requests in ~/.config/pollen/collections.json and exposes Add / Delete / Rename / UpdateRequest operations on the store.
Package collections persists named saved requests in ~/.config/pollen/collections.json and exposes Add / Delete / Rename / UpdateRequest operations on the store.
curlparse
Package curlparse converts a `curl` shell command into a pollen history.Request.
Package curlparse converts a `curl` shell command into a pollen history.Request.
dynvars
Package dynvars expands {{$name}} / {{$name:arg}} tokens that pollen computes at expansion time, complementing the user-defined {{varName}} substitution in env.
Package dynvars expands {{$name}} / {{$name:arg}} tokens that pollen computes at expansion time, complementing the user-defined {{varName}} substitution in env.
env
Package env stores user-defined variables, organised into named environments (e.g.
Package env stores user-defined variables, organised into named environments (e.g.
exporter
Package exporter converts pollen collections to external formats.
Package exporter converts pollen collections to external formats.
headers
Package headers holds the curated list of standard HTTP header names used for tab-completion in the Headers panel.
Package headers holds the curated list of standard HTTP header names used for tab-completion in the Headers panel.
history
Package history persists the request/response history in ~/.config/pollen/history.json and defines the Request, Response, and Header types shared with other packages.
Package history persists the request/response history in ~/.config/pollen/history.json and defines the Request, Response, and Header types shared with other packages.
httpx
Package httpx executes HTTP requests with pollen-specific transport options (TLS skip, custom CA pool, proxy, redirect control, cookie jar, byte-capped responses) and builds the request body from pollen's BodyType variants.
Package httpx executes HTTP requests with pollen-specific transport options (TLS skip, custom CA pool, proxy, redirect control, cookie jar, byte-capped responses) and builds the request body from pollen's BodyType variants.
importer
Package importer reads OpenAPI 3.x (JSON/YAML) and Postman Collection v2.1 documents and converts them into pollen collection entries.
Package importer reads OpenAPI 3.x (JSON/YAML) and Postman Collection v2.1 documents and converts them into pollen collection entries.
intruder
Package intruder runs a request template against a sequence of payloads (numeric range, wordlist, brute force, or case toggles) with configurable concurrency and produces a per-payload result row for the TUI table.
Package intruder runs a request template against a sequence of payloads (numeric range, wordlist, brute force, or case toggles) with configurable concurrency and produces a per-payload result row for the TUI table.
oauth
Package oauth implements the OAuth 2.0 token flows pollen ships in v1.5.0: Client Credentials (RFC 6749 §4.4) and Refresh Token (RFC 6749 §6).
Package oauth implements the OAuth 2.0 token flows pollen ships in v1.5.0: Client Credentials (RFC 6749 §4.4) and Refresh Token (RFC 6749 §6).
settings
Package settings persists user-toggleable options across sessions.
Package settings persists user-toggleable options across sessions.
ui
Help is the scrollable, accordion-style keybinding overlay opened with Ctrl+/.
Help is the scrollable, accordion-style keybinding overlay opened with Ctrl+/.
userconfig
Package userconfig centralises pollen's on-disk config layout.
Package userconfig centralises pollen's on-disk config layout.
version
Package version exposes the build-time-injected Version string used by the --version CLI flag.
Package version exposes the build-time-injected Version string used by the --version CLI flag.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL