Skip to content

fetch() and cookies

The extension can run a request in its service worker instead of the page, so it is not bound by CORS, and it can optionally carry the user’s own session cookies. These are the extension.* capabilities. For how extension.fetch relates to the bare fetch and the cloud proxy, see API backends.

A cookieless cross-origin fetch does not use the user’s target-site session. It is severity 0, so the extension grants it automatically and records the first use of that target scope during the visit.

import {
(alias) namespace extension
import extension
extension
} from '@fkn/lib'
const
const response: Response
response
= await
(alias) namespace extension
import extension
extension
.
extension_d_exports.fetch(input: RequestInfo | URL, init?: extension.FetchInit): Promise<Response>
export extension_d_exports.fetch
fetch
('https://example.com/api/catalog')
const
const data: any
data
= await
const response: Response
response
.
Body.json(): Promise<any>
json
()

The bare fetch reaches the same cross-origin content without the extension, falling back to the cloud proxy when the extension is absent. Use extension.fetch directly when you specifically want the request to leave from the user’s own browser.

Pass credentials: 'include' and the request carries the target site’s cookies, including SameSite=Lax/Strict and httpOnly cookies the page itself could never read. This is the capability behind session relay. It prompts when no existing grant covers the target, showing exactly which site the app wants to reach through that session.

import {
(alias) namespace extension
import extension
extension
} from '@fkn/lib'
const
const response: Response
response
= await
(alias) namespace extension
import extension
extension
.
extension_d_exports.fetch(input: RequestInfo | URL, init?: extension.FetchInit): Promise<Response>
export extension_d_exports.fetch
fetch
('https://example.com/api/me', {
RequestInit.credentials?: RequestCredentials | undefined

A string indicating whether credentials will be sent with the request always, never, or only when sent to a same-origin URL. Sets request's credentials.

credentials
: 'include',
reason?: string | undefined
reason
: 'Load your watch history from your existing account',
})

The cookie values do not pass through the app’s JavaScript: the extension attaches them in its service worker via declarative request rules. A bare fetch is cookieless by default; passing credentials: 'include' in the second argument routes it through this same extension consent path, never through the cloud. Set the option explicitly there rather than relying on the credentials property of a Request object. Credentialed extension fetch also requires a window realm.

When an app genuinely needs a cookie’s value (for example a CSRF token to replay into a request body), extension.cookies.get() returns a single cookie by name for a given URL. It is gated and logged per target origin, and it never enumerates: your app must name the cookie it wants.

import {
(alias) namespace extension
import extension
extension
} from '@fkn/lib'
const
const session: extension.SiteCookie | null
session
= await
(alias) namespace extension
import extension
extension
.
const extension_d_exports.cookies: {
get: (details: extension.CookieDetails) => Promise<extension.SiteCookie | null>;
}
export extension_d_exports.cookies
cookies
.
get: (details: extension.CookieDetails) => Promise<extension.SiteCookie | null>
get
({
url: string
url
: 'https://example.com',
name: string
name
: 'csrf_token',
})
if (
const session: extension.SiteCookie | null
session
) {
var console: Console
console
.
Console.log(...data: any[]): void

The console.log() static method outputs a message to the console.

MDN Reference

log
(
const session: extension.SiteCookie
session
.
name: string
name
,
const session: extension.SiteCookie
session
.
value: string
value
)
}

Extension fetch applies a separate network.fetchLocal consent check for IP-literal and well-known local names. This includes IPv4 private, loopback, link-local, and unspecified ranges; IPv6 loopback, unique-local, link-local, and IPv4-mapped addresses; plus localhost, .localhost, .local, .internal, and .home.arpa names.

import {
(alias) namespace extension
import extension
extension
} from '@fkn/lib'
const
const response: Response
response
= await
(alias) namespace extension
import extension
extension
.
extension_d_exports.fetch(input: RequestInfo | URL, init?: extension.FetchInit): Promise<Response>
export extension_d_exports.fetch
fetch
('http://router.local/status', {
reason?: string | undefined
reason
: 'Read the status of the router you selected',
})

A public hostname that resolves to a local address is not classified at this page-side check because the extension has not resolved it yet.

extension.fetch() can set Origin and Referer, which ordinary page fetch cannot set. They are applied by the extension service worker as part of that fetch. cloud.fetch() can also forward caller-supplied Origin and Referer values when headers is a plain object.

For the page’s own subresource requests, such as an <img> or <video> URL that does not pass through fetch(), the extension exposes a separate tab-scoped rule API. It prompts for network.modifyRequestHeaders, applies until removed or the tab closes, and supports setting or removing arbitrary request headers.

import {
(alias) namespace extension
import extension
extension
} from '@fkn/lib'
const {
const ruleId: number
ruleId
} = await
(alias) namespace extension
import extension
extension
.
extension_d_exports.setRequestHeaderRule(rule: extension.RequestHeaderRule): Promise<{
ruleId: number;
}>
export extension_d_exports.setRequestHeaderRule
setRequestHeaderRule
({
domains: string[]
domains
: ['cdn.example.com'],
requestHeaders: extension.HeaderOperation[]
requestHeaders
: [
{
header: string
header
: 'Referer',
operation: "set" | "remove"
operation
: 'set',
value?: string | undefined
value
: 'https://example.com/' },
],
reason?: string | undefined
reason
: 'Load media from the selected provider',
})
await
(alias) namespace extension
import extension
extension
.
extension_d_exports.removeRequestHeaderRule(ruleId: number): Promise<void>
export extension_d_exports.removeRequestHeaderRule
removeRequestHeaderRule
(
const ruleId: number
ruleId
)

Cloud and extension can both make cookieless cross-origin requests. Only the extension can carry the user’s browser session, read a named browser cookie, reach a recognized local-network target with its dedicated consent, or apply persistent rules to the page’s own subresource requests.

fetch capabilities by execution backend

All APIs below are called from browser code. The columns show which backend performs the work.

API / featureExtensionCloudDesktop
fetch (cross-origin, cookieless)SupportedSupportedPlanned
fetch (credentials: 'include')SupportedNot availableNot available
cookies.getSupportedNot availableNot available
Origin / Referer on fetchSupportedPartialPlain header objectNot available
Local-network fetchSupportedNot availableNot available
Request-header rulesSupportedNot availableNot available