Manifest V3 modify headers

651 views
Skip to first unread message

Divya Rijhwani

unread,
May 14, 2023, 8:19:16 AM5/14/23
to Chromium Extensions
Hello Team,
Here for modify headers. I am supposed to push header on get request that is ''Authorization" and here 'chrome.webRequest.onBeforeSendHeaders.addListener' doesn't work anymore. I tried to replace webRequest with declarativeRequest and rules file it is not reflecting any static rules as well.

wOxxOm

unread,
May 14, 2023, 1:12:41 PM5/14/23
to Chromium Extensions, Divya Rijhwani
Show your code for the rule and manifest.json. There's probably a mistake e.g. host_permissions is wrong or missing.

Divya Rijhwani

unread,
May 15, 2023, 2:36:57 AM5/15/23
to Chromium Extensions, wOxxOm, Divya Rijhwani
Hello Team,
Please check this is my manifest file.
I have made changes as per document I also removed 'webRequestBlocking'  as it's no longer supported.
1. In my service-worker.js  I have header modification defined and that is on call method onBeforeSendHeaders.
2. I have also tried with implementing declarativeNetRequest for that i tried to define rules in different file as well as in manifest file itself. It didn't work.

Let me know with what approach i can go ahead and how.
Giving here my manifest file and example of pushing header in my service-worker..
e.g:  service-worker.js
   let beforeSendHeadersHandler = function(details) {

    let requestHeaders = details.requestHeaders;
    if (!getExtensionEnabled()) { // getExtensionEnabled from common.js
        return getRequestHeaders(requestHeaders);
    }
    let url = details.url.toLowerCase();
    if (!isUrlInScope(details.url, true)) {
        return getRequestHeaders(requestHeaders);
    }

    let token = getTokenFromRequestUrl(url);
    if (token) {
        addAuthorizationHeaderToRequestHeaders(requestHeaders, token)
    }

    let idToken = getIdTokenFromRequestUrl(url);
    if (idToken) {
        addIdentityHeaderToRequestHeaders(requestHeaders, idToken);
    }

    if (getHALMode()) {
        addAcceptHeaderToRequestHeaders(requestHeaders, "application/hal+json");
    }

    return getRequestHeaders(requestHeaders);
};

function addAuthorizationHeaderToRequestHeaders(requestHeaders, token) {

    requestHeaders.push({
        name: "Authorization",
        value: `Bearer ${token}`
    });
} ... { ..}

chrome.webRequest.onBeforeSendHeaders.addListener(beforeSendHeadersHandler, requestFilter, extraInfoSpec);

manifest.json

Joy Gupta

unread,
May 15, 2023, 12:56:01 PM5/15/23
to Chromium Extensions, Divya Rijhwani, wOxxOm
I was also in a similar situation, and perhaps that approach can help you too. For one of our products, we needed to trace XHR and fetch requests. So, I simply overrode the definitions of both functions and injected the script in the head of each page whenever a new tab was opened. The same approach can be used in this case as well. For example, if I want to add a header to this POST request "https://something.com/api/v1/user," I'll use an if clause to check if the URL matches, and then I can add custom headers accordingly.
PS: I am not sure if this the right way, but I found this way easier than using declarative net request.

wOxxOm

unread,
May 15, 2023, 1:10:32 PM5/15/23
to Chromium Extensions, Joy Gupta, Divya Rijhwani, wOxxOm
So, where's your code for the rule in declarativeNetRequest and manifest.json?

Divya Rijhwani

unread,
May 16, 2023, 3:14:23 AM5/16/23
to Chromium Extensions, wOxxOm, Joy Gupta, Divya Rijhwani
Hello wOxxOm,

1. I have defined declarativeNetRequest instead of webRequest In my manifest.json
manifest.json:
{
    "name": "test",
    "description": "test1",
    "version": "3.2.4",
    "manifest_version": 3,
    "icons": {
        "19": "public/resource/icon-19.png",
        "32": "public/resource/icon-32.png",
        "36": "public/resource/icon-36.png",
        "225": "public/resource/icon.png"
    },
    "action": {
        "default_icon": "public/resource/icon.png",
        "default_popup": "popup.html"
    },
     "declarative_net_request": {
    "rule_resources": [{
      "id": "ruleset_1",
      "enabled": true,
      "path": "rules.js"
    }]
  },
    "permissions": [
    "activeTab",
    "declarativeNetRequest",
    "tabs"
   
  ],
 "host_permissions": [
    "https://*/*",
    "http://*/*"
  ],
    "background": {
        "service_worker": "public/js/service-worker.js",
        "type": "module"
    }
}

rules.js
is in same hierarchy and it is static so it is working but in my service-worker.js earlier it was working on call onBeforeSendHeaders what is the solution for this? How I can make this work with service-worker as I don't have to use static header modification.


Divya Rijhwani

unread,
May 16, 2023, 3:15:22 AM5/16/23
to Chromium Extensions, Joy Gupta, Divya Rijhwani, wOxxOm
Well for this approach can you provide sample code for fetch request? As i tried and didn't work for static approach also.

wOxxOm

unread,
May 16, 2023, 3:24:42 AM5/16/23
to Chromium Extensions, Divya Rijhwani, Joy Gupta, wOxxOm
So it looks like you don't have such a rule.

To switch from webRequestBlocking you need to convert the actual logic of your current code to declarativeNetRequest. Just declaring the permission and rules.json doesn't do anything, it's useless by itself alone. It's unclear yet whether your code can be converted because we didn't see the actual logic that is contained in getTokenFromRequestUrl,  addIdentityHeaderToRequestHeaders, getHALMode, addAcceptHeaderToRequestHeaders.

Message has been deleted
Message has been deleted

Divya Rijhwani

unread,
May 16, 2023, 5:32:23 AM5/16/23
to Chromium Extensions, wOxxOm, Divya Rijhwani, Joy Gupta
Actual logic in service-worker is attaching below.

For me static rule is defined in rules.json but besides that I am not able to call any func of service-worker.js Where current func is not working anymore.. "//chrome.webRequest.onBeforeRequest.addListener(beforeRequestHandler, requestFilter, ['blocking']);
//chrome.webRequest.onBeforeSendHeaders.addListener(beforeSendHeadersHandler, requestFilter, extraInfoSpec);
"
I want to update my rules through service-worker itself and I am also blocked in that case where I tried to define  
'In manifest file's declarativeNetRequest portion file SW instead of rules.json' It says it is not valid. 


'use strict';

const BLUE_URL_PREFIX = "";
const CHARLES_PROXY_BASE_URL = "";
const DIAGNOSTICS_VERSION_REGEX = ;
const GREEN_URL_PREFIX = "";
const GROUP_PREFIX_REGEX = ;
const INTEGRATION_BASE_URL = "";
const LOCALHOST_BASE_URL = "";
const PRODUCTION_BASE_URL = "";
const REQUEST_FILTER_URLS = [""];
const STAGING_BASE_URL = "";
const SPEED_PLATFORM_INTEGRATION_URL = "";
const API_GW_INTEGRATION_URL = "";
const API_GW_STAGING_URL = "";
const API_GW_PRODUCTION_URL = "";
const POM_PLATFORM_INTEGRATION_URL = "";
const POM_PLATFORM_STAGING_URL = "";
const POM_PLATFORM_PRODUCTION_URL = "";

const ENV_BASE_URLS = {
    "local": [LOCALHOST_BASE_URL, CHARLES_PROXY_BASE_URL],
    "integration": [INTEGRATION_BASE_URL, SPEED_PLATFORM_INTEGRATION_URL, API_GW_INTEGRATION_URL, POM_PLATFORM_INTEGRATION_URL],
    "staging": [STAGING_BASE_URL, API_GW_STAGING_URL, API_GW_INTEGRATION_URL, POM_PLATFORM_STAGING_URL],
    "production": [PRODUCTION_BASE_URL, API_GW_PRODUCTION_URL, POM_PLATFORM_PRODUCTION_URL]
};
const TOKEN_BASE_URLS = [CHARLES_PROXY_BASE_URL, LOCALHOST_BASE_URL, INTEGRATION_BASE_URL, STAGING_BASE_URL, PRODUCTION_BASE_URL, SPEED_PLATFORM_INTEGRATION_URL, API_GW_INTEGRATION_URL, API_GW_STAGING_URL, API_GW_PRODUCTION_URL, POM_PLATFORM_INTEGRATION_URL, POM_PLATFORM_STAGING_URL, POM_PLATFORM_PRODUCTION_URL];
const URL_PREFIXES = {
    "blue": BLUE_URL_PREFIX,
    "green": GREEN_URL_PREFIX
};

let beforeRequestHandler = function(details) {

    let url = details.url;
    // Do not redirect if this extension is disabled
    if (!getExtensionEnabled()) {
        return;
    }

    // Do not redirect for local requests
    if (ENV_BASE_URLS["local"].includes(getBaseUrlFromUrl(url))) {
        return;
    }

    // Do not redirect if the targeted Orc env is not selected
    if (!isUrlInScope(details.url.toLowerCase(), false)) {
        return;
    }

    // Do not redirect if a server group is not selected
    let serverGroupSelection = getServerGroupSelection();
    if (serverGroupSelection === "none") {
        return;
    }

    // Do not redirect if a server group prefix is already specified in the
    // URL, this can be from someone manually prepending "smartinet-g" OR
    // from a previous invocation of this method. This condition therefore
    // avoids an infinite redirect.
    if (url.match(GROUP_PREFIX_REGEX)) {
        return;
    }

    // Redirect the request, prepending the proper server group
    let parsedUrl = new URL(url);
    parsedUrl.pathname = URL_PREFIXES[serverGroupSelection] + parsedUrl.pathname;

    return getRedirectUrl(parsedUrl.href);
};


let beforeSendHeadersHandler = function(details) {

    let requestHeaders = details.requestHeaders;
    if (!getExtensionEnabled()) { // getExtensionEnabled from common.js
        return getRequestHeaders(requestHeaders);
    }
    let url = details.url.toLowerCase();
    if (!isUrlInScope(details.url, true)) {
        return getRequestHeaders(requestHeaders);
    }

    let token = getTokenFromRequestUrl(url);
    if (token) {
        addAuthorizationHeaderToRequestHeaders(requestHeaders, token)
    }

    let idToken = getIdTokenFromRequestUrl(url);
    if (idToken) {
        addIdentityHeaderToRequestHeaders(requestHeaders, idToken);
    }

    if (getHALMode()) {
        addAcceptHeaderToRequestHeaders(requestHeaders, "application/hal+json");
    }

    return getRequestHeaders(requestHeaders);
};

function addAuthorizationHeaderToRequestHeaders(requestHeaders, token) {

    requestHeaders.push({
        name: "Authorization",
        value: `Bearer ${token}`
    });
}

function addIdentityHeaderToRequestHeaders(requestHeaders, idToken) {

    requestHeaders.push({
        name: "X-Id-Token",
        value: idToken
    });
}

function addAcceptHeaderToRequestHeaders(requestHeaders, value) {

    requestHeaders.push({
        name: "Accept",
        value: value
    });
}

function getRedirectUrl(url) {
    return {
        redirectUrl: url
    };
}

function getRequestHeaders(requestHeaders) {
    return {
        requestHeaders: requestHeaders
    };
}

function getTokenFromRequestUrl(url) {
    let baseUrl = getBaseUrlFromUrl(url);
    let activeToken = (localStorage.getItem("activeTab") || defaultTab).replace("Tab", "");
    if (TOKEN_BASE_URLS.includes(baseUrl)) {
        return getToken(activeToken) || null; // getToken from common.js
    }

    return null;
}

function getIdTokenFromRequestUrl(url) {
    let baseUrl = getBaseUrlFromUrl(url);
    let activeToken = (localStorage.getItem("activeTab") || defaultTab).replace("Tab", "");
    if (TOKEN_BASE_URLS.includes(baseUrl)) {
        return getIdToken(activeToken) || null;
    }

    return null;
}

function getBaseUrlFromUrl(url) {

    let parsedUrl = new URL(url);
    return parsedUrl.protocol + "//" + parsedUrl.host + "/";
}

function isUrlInScope(url, checkForDiagnosticsVersion) {

    let siteSelections = getSiteSelection(); //getSiteSelection from common.js
    if (siteSelections == null) {
        return false;
    }

    for (let i = 0; i < siteSelections.length; i++) {
        let siteSelection = siteSelections[i].toLowerCase();
        let siteSelectionUrls = ENV_BASE_URLS[siteSelection];


        if (siteSelectionUrls.includes(getBaseUrlFromUrl(url))) {
            if (!checkForDiagnosticsVersion) {
                return true;
            }

            // The diagnostics & version endpoints use different auth; Don't include the header
            return !url.match(DIAGNOSTICS_VERSION_REGEX);
        }
    }

    return false;
}

let requestFilter = {
    // Limiting request scope to Xfinity or localhost
    urls: REQUEST_FILTER_URLS
};

let extraInfoSpec = ['requestHeaders', 'blocking'];

chrome.webRequest.onBeforeRequest.addListener(beforeRequestHandler, requestFilter, ['blocking']);
chrome.webRequest.onBeforeSendHeaders.addListener(

function(details)
{
    let requestHeaders = details.requestHeaders;
    if (!getExtensionEnabled()) { // getExtensionEnabled from common.js
        return getRequestHeaders(requestHeaders);
    }
    let url = details.url.toLowerCase();
    if (!isUrlInScope(details.url, true)) {
        return getRequestHeaders(requestHeaders);
    }

    let token = getTokenFromRequestUrl(url);
        details.requestHeaders.push(
            if (token) {

            {
            "name": "Authorization",
            "value": `Bearer ${token}`
            }

        }
       
        );
     return requestHeaders;
}, requestFilter, extraInfoSpec);

//chrome.webRequest.onBeforeRequest.addListener(beforeRequestHandler, requestFilter, ['blocking']);
//chrome.webRequest.onBeforeSendHeaders.addListener(beforeSendHeadersHandler, requestFilter, extraInfoSpec);

wOxxOm

unread,
May 16, 2023, 7:41:58 AM5/16/23
to Chromium Extensions, Divya Rijhwani, wOxxOm, Joy Gupta
The new API is thoroughly different, it's not based on JS code. You'll need to rewrite the logic completely. Currently your webRequest listener checks the URL and reads the token from localStorage, but you can't do it with the new API. What you can do is to generate rules when you change siteSelections and the token in localStorage, then install the rules via chrome.declarativeNetRequest.updateDynamicRules or updateSessionRules if you want to limit it to a tab.

Here's a simplified example:

async function rebuildRules() {
  const domains = ['aaa.com', 'bbb.com'];
  /** @type {chrome.declarativeNetRequest.Rule[]} */
  const rules = [{
    id: 1,
    condition: {
      requestDomains: domains,
      resourceTypes: ['main_frame', 'sub_frame'],
    },
    action: {
      type: 'modifyHeaders',
      requestHeaders: [{
        header: 'foo',
        operation: 'set',
        value: 'bar',
      }],
    },
  }];
  await chrome.declarativeNetRequest.updateDynamicRules({
    removeRuleIds: rules.map(r => r.id),
    addRules: rules,
  });
}

As noted above you'll rebuild the rules only when the conditions change and of course in chrome.runtime.onInstalled event.

Divya Rijhwani

unread,
May 17, 2023, 8:42:23 AM5/17/23
to Chromium Extensions, wOxxOm, Divya Rijhwani, Joy Gupta
Hello wOOxxOm,

I appreciate your response here.
In my-case the function you have given for example I tried to implement as it is just to check and it didn't invoke in plugin.
Could you please help me by elaborating this as How to make sure function get invoked in our service-worker file?

wOxxOm

unread,
May 17, 2023, 11:04:12 AM5/17/23
to Chromium Extensions, Divya Rijhwani, wOxxOm, Joy Gupta
You can't use any functions with declarativeNetRequest. My comment showed how you can convert your function into a declarative rule.

Divya Rijhwani

unread,
May 22, 2023, 3:57:28 AM5/22/23
to Chromium Extensions, wOxxOm, Divya Rijhwani, Joy Gupta
Hello wOxxOm,

Here, I have tried to update rules through declarativeNetRequest.
Big loop hole is earlier it was using onBeforeSendHeaders like e.g "chrome.webRequest.onBeforeSendHeaders.addListener(beforeSendHeadersHandler, requestFilter, extraInfoSpec)"
so as per this example it will work with "let beforeSendHeadersHandler = function(details) {" where details is an argument we can get requestHeaders with that only. How i can use any other extension or Method to work like this as i need some changes for url and request headers which i can't directly perform in updateDynamicRules.

wOxxOm

unread,
May 22, 2023, 4:02:41 AM5/22/23
to Chromium Extensions, Divya Rijhwani, wOxxOm, Joy Gupta
I've already explained it and showed an example in my previous comments. I don't see how I can help further without writing everything myself. Maybe someone else will do it.

Divya Rijhwani

unread,
May 22, 2023, 4:13:45 AM5/22/23
to Chromium Extensions, wOxxOm, Divya Rijhwani, Joy Gupta
I don't want to just modify.. your example will work in that but I need to make some changes while i can get that requestHeaders,url and others parameter as well from details argument. So question is about that which extension or method can help to get request like that.

wOxxOm

unread,
May 22, 2023, 5:25:53 AM5/22/23
to Chromium Extensions, Divya Rijhwani, wOxxOm, Joy Gupta
As I explained above you can't do it with this API. 

Divya Rijhwani

unread,
May 22, 2023, 9:12:22 AM5/22/23
to Chromium Extensions, wOxxOm, Divya Rijhwani, Joy Gupta
Hello wOxxOm,

As you are referring "with this API" Did you mean it's not possible with manifest V3 or just DNR? 

wOxxOm

unread,
May 22, 2023, 9:57:25 AM5/22/23
to Chromium Extensions, Divya Rijhwani, wOxxOm, Joy Gupta
An "API" means declarativeNetRequest. If you need to run JS for a request synchronously with modifying it the only solution in ManifestV3 is to force-install the extension via enterprise policies.

That said, I don't see what specifically in your code cannot be converted. The code you've shown doesn't make any changes that need JS in the callback, although I may have missed something.

Divya Rijhwani

unread,
May 23, 2023, 3:01:32 AM5/23/23
to Chromium Extensions, wOxxOm, Divya Rijhwani, Joy Gupta
Hello wOxxOm,

Can you please give me an example about How i can import other JS thing in service_worker or how I can use  "chrome.storage.local"  in service_worker itself.
Cause I have tried examples given on google and nothing works for me.

wOxxOm

unread,
May 23, 2023, 4:11:33 AM5/23/23
to Chromium Extensions, Divya Rijhwani, wOxxOm, Joy Gupta
Make a new topic please and show your current code and manifest.json.
Reply all
Reply to author
Forward
0 new messages