Quick answer
Host permissions grant website access for specific privileged operations; they are not a URL allowlist for every part of your application. In Manifest V3, put them in host_permissions or optional_host_permissions. Declare content-script injection locations separately in content_scripts.matches. Add the API permission required by the operation, such as scripting for programmatic injection. A host grant cannot replace an API grant.
The most easily missed distinction is path scope. A content-script match can restrict where that script runs, but the path part of a host permission is ignored. Declaring https://example.com/reports/* does not confine privileged access to reports. If a feature must be limited to that path, enforce it in application logic as well. This article concentrates on that scope and execution-context distinction; the related permissions guide covers the broader feature inventory.
Practical implementation steps
Separate the target page from the remote service
For a hypothetical report helper, identify two boundaries: the page where users select a report and the API that returns metadata. A grant for the page does not imply a grant for the API's origin. Enumerate redirects and stylesheet or asset origins only when the implemented feature actually needs them. Avoid a wildcard across all hosts as a shortcut for discovering a known service's endpoint.
Choose patterns deliberately
Prefer https://api.example.com/* when one host is enough. https://*.example.com/* includes a broader subdomain family, and *:// covers HTTP as well as HTTPS. Current Chrome documentation also describes explicit ports in match patterns; older compatibility targets require checking support before relying on them. Keep a small list of representative matching and nonmatching URLs beside the manifest review, including a deceptive hostname such as api.example.com.attacker.invalid.
Put requests in the correct context
A content script's cross-origin fetch remains subject to the page's origin restrictions even when the extension has host permissions. An extension worker or extension page can make host-authorized requests. If a worker performs a request for a content script, expose a narrow operation such as lookupReport(id) rather than fetchAnything(url). Validate the sender, the identifier, and the result before returning only the required fields.
Design unavailable access as a normal state
Use temporary activeTab access for a manual inspection when that lifetime fits. Use a narrow optional host request for persistent behavior. Recheck grants before work and handle permission errors even after a successful check: a user can revoke access or the tab can navigate during the operation. Browser-internal pages, file URLs, and incognito each have additional restrictions or user controls; broader patterns do not remove those boundaries.
Implementation example
This illustrative manifest gives a worker access to one service while declaring a narrower static injection path on a separate site. It deliberately shows that the two fields serve different operations. The service hostname is a placeholder, and the example is not a claim about a portfolio product's manifest.
{
"manifest_version": 3,
"name": "Report helper",
"version": "1.0.0",
"host_permissions": ["https://api.example.com/*"],
"background": { "service_worker": "worker.js" },
"content_scripts": [{
"matches": ["https://app.example.com/reports/*"],
"js": ["report-content.js"]
}]
}
Host permission supplies browser access, not authentication or authorization on the remote server. The API must still verify the requesting user's rights to the report. A content script receiving the result should not render it as executable HTML. If your extension defines connect-src in its own CSP, ensure that policy also permits the intended API request.
Tradeoffs and alternatives
Static injection is useful when a feature should appear automatically on a known path. Programmatic injection is useful for a user-selected moment or target and requires scripting plus access to that document. Dynamic registration provides another option for persistent opt-in sites, but registration and permission lifecycle must be maintained together. Choose from timing and supported sites, not from which snippet is shortest.
Font Picker's repository description says it may fetch stylesheets already used by the inspected page to locate font sources. That is a concrete reason to distinguish DOM inspection from stylesheet requests. It does not prove any particular host grant. Confirm the packaged implementation before deciding whether temporary access, declared service hosts, or runtime site requests match a product's actual behavior.
Common mistakes
- Treating a host-permission path as an enforced data boundary.
- Assuming an API permission alone grants document access.
- Moving fetch to a content script and expecting the worker's privileges.
- Allowing a page message to choose an arbitrary privileged fetch URL.
- Confusing host access with server-side user authorization.
Production checklist
- Each origin has a feature-specific reason.
- Matching and nonmatching URLs have been checked.
- Path restrictions are enforced where the feature depends on them.
- Content-script and worker network behavior are tested separately.
- Revocation and navigation races produce a visible unavailable state.
- Remote requests and responses use a narrow message contract.
FAQ
Does host_permissions automatically inject a content script?
No. Static matches, dynamic registration, or an explicit scripting call determine injection. Host access is one part of permission to perform the relevant operation, not a request to run code everywhere it applies.
Can a narrow URL path restrict privileged fetch?
Not through host_permissions alone. Enforce your allowed endpoint, method, and identifier format in the worker. Do not forward full URLs from less trusted contexts merely because they appear to begin with the expected string.
Why does access fail after it was granted?
The user may change site access, a temporary grant may expire, or the document may navigate. Inspect the current target and grant rather than endlessly retrying. Ask for fresh access only through a clear user interaction when the feature needs it.
Conclusion
Write separate lists for injection targets and privileged request origins. Verify scheme, host, execution context, and API permission for each operation. When a path limit matters, encode it in the operation's own validation rather than relying on the host pattern to enforce it.
Primary sources
- Chrome: Match patterns
- Chrome: Cross-origin requests
- Chrome: Scripting API
- Chrome: Runtime permissions
Related guides and examples
Need this implemented in a real product?
Explore relevant product case studies or share the context for a web application, Chrome extension, API, or SaaS build.