Connect+Documentation
Extensions

Capabilities & consent

The permission model — the capability taxonomy, scoped grants, feature-detection, and runtime requests.

Extensions declare the capabilities they need in the manifest. On install (or when a reload widens the set) the shell shows a grouped consent prompt; the user grants a subset and can revoke per-capability later. Grants are per-profile and persisted, and every call is enforced by a single gate — default-deny, fail-closed.

Screenshot
caption: The grouped consent prompt on install. Capture the permission dialog listing the requested capabilities.
drop the image at public/docs-img/extensions/consent-prompt.png

The capability taxonomy

TokenGrants
tabs.readSee open tabs/windows and their changes.
tabs.writeOpen, close, reload, navigate, activate tabs.
storageKeep the extension's own private data on the device.
scriptingProgrammatically inject into pages it may access.
net.observeRead-only network / adblock status.
net.blockBlock/redirect requests; author declarative rules.
history.read / history.writeRead / modify browsing history.
bookmarks.read / bookmarks.writeRead / modify bookmarks & favorites.
downloadsStart downloads and observe their progress.
notificationsShow system notifications.
cookiesRead/write cookies for permitted sites (needs a host grant too).
contextMenusAdd items to the page right-click menu.
alarmsSchedule timer tasks that survive suspension.
idleSee active / idle / locked state.
sidePanelOwn a side-panel surface.
actionOwn the toolbar button + popup.
optionsOwn the options surface.
newTabReplace the page shown when a new tab opens.
historyPageReplace the History popup with the extension's view.
bookmarksPageReplace the Favorites popup with the extension's view.
profile.readRead Connect+ profile & device-rule data.
proxyControl proxy routing.

Scoped (dynamic) capabilities

Some grants take an argument — declare them as objects in capabilities:

  • { "host": "<match-pattern>" } — host access, Chrome-match-pattern shaped: https://*.example.com/*, *://example.com/*, <all_urls>. Host grants scope content-script injection, cookies, and programmatic scripting.

    "capabilities": ["cookies", { "host": "https://*.example.com/*" }]
  • { "channel": "<name>" } — permission to talk on a cross-extension channel (names match [a-z][a-zA-Z0-9]*). See connect.channel.

Check before you use

The user may grant some requested capabilities and not others. Feature-detect with capabilities.contains and skip the code paths whose permission wasn't granted, rather than calling and catching a CAPABILITY_DENIED:

if (await connect.capabilities.contains('history.read')) {
  render(await connect.history.list());          // allowed
} // else: run without history — no error thrown

// host- and multi-checks too:
if (await connect.capabilities.contains({ host: tab.url })) { /* inject */ }
if (await connect.capabilities.contains(['cookies', { host: url }])) { /* … */ }

Request at runtime

An extension can ask for already-declared capabilities it doesn't yet have, without a reload:

const { granted } = await connect.capabilities.request(['history.read']);

Only manifest-declared capabilities can be requested (no escalation). See connect.capabilities for the full API.

A background that declares gated event subscriptions (e.g. tabs.onUpdated) may boot before the user consents, so those subscriptions are silently denied. Re-arm them from runtime.onGrantsChanged — subscribing is idempotent, so calling it again after consent lands works. This applies to every backgrounded extension with capability-gated events.

On this page