You cannot access the csrftoken cookie from any domain but the one that generated it. So, you have to read the csrftoken when it's generated and save it if you want to use it from your extension.
In my case, when the token was not present, it didn't cause any error, but as soon as I logged in the server, the csrftoken was set, and couldn't retrieve it from any other domain, getting the 403 error on any request that was not generated in the same domain.
To fix it, first, I had to read the cookie from the domain when I logged in and save it to chrome storage. First, I need proper permissions (Note that, where I use background/background.js you could switch to popup/popup.js if needed)
manifest.json
...,
"background": {
"scripts": ["jquery-1.11.1.min.js","background.js"],
"persistent": false
},
"permissions": ["tabs", "<all_urls>", "storage", "webNavigation"],
"content_scripts":[
{
"matches":["yourDomain"],
"js": ["jquery-1.11.1.min.js", "readCSRFToken.js"]
}],...
Now, this small script will read the cookie we need if it's present and send it to our extension. You could check the host name before sending the cookie if you want to be sure that you take the correct CSRF token.
readCSRFToken.js
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
csrftoken = getCookie("csrftoken");
if ( csrftoken ){
chrome.runtime.sendMessage({action:"setCsrfToken", csrftoken:csrftoken}, function(){});
}
In the extension code, we add a listener that will save the csrf token in chrome storage when it's sent by the injected code.
There is also a webNavigation.onComplete that will read the token from storage every time we load a page.
background.js
csrftoken = null;
chrome.webNavigation.onCompleted.addListener(function(details) {
if ( details.frameId == 0 ){
chrome.storage.sync.get(["csrftoken"], function(storage){
csrftoken = storage.csrftoken;
});}
}
);
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
switch ( request.action ){
case "setCsrfToken":{
chrome.storage.sync.set({'csrftoken': request.csrftoken}, function() {});
}
break;
}
});
Finally, we have a csrftoken variable stored that we should be able to use to set the "X-CSRFToken" header to allow our AJAX request to work properly when used from the extension.
...
var headers = {}
if ( csrftoken ) headers["X-CSRFToken"] = csrftoken;
$.ajax({
dataType: 'json',
headers: headers,
...
});