{"id":9349,"date":"2019-07-12T08:53:05","date_gmt":"2019-07-12T08:53:05","guid":{"rendered":"https:\/\/www.gmass.co\/blog\/?p=4349"},"modified":"2022-12-08T00:50:22","modified_gmt":"2022-12-08T00:50:22","slug":"send-cookie-cross-origin-xmlhttprequest-chrome-extension","status":"publish","type":"post","link":"https:\/\/www.gmass.co\/blog\/send-cookie-cross-origin-xmlhttprequest-chrome-extension\/","title":{"rendered":"How to send a cookie with a cross-origin XMLHttpRequest from a Chrome extension"},"content":{"rendered":"<p>When developing a Chrome extension, you might need\u00a0to <strong>get an XMLHttpRequest that&#8217;s part of a content script to send cookies for a domain when making a request<\/strong> to that domain, if the <strong>origin is\u00a0not that domain<\/strong>. <em>Not much has been written about how to do this.<\/em><\/p>\n<p>Dana Woodman, a Chrome extension developer <a href=\"http:\/\/dana.land\/articles\/send-session-cookies-using-a-chrome-extension\">discusses how to do this<\/a>, but she makes\u00a0a mistake, claiming that you need to designate the &#8220;cookies&#8221; permission in your <strong>manifest.json<\/strong>. This is\u00a0not\u00a0accurate. You <em>can<\/em> designate the &#8220;cookies&#8221; permission in manifest.json, but you <em>only need to do that if you want to access cookie data separately from an XmlHttpRequest<\/em>. Additionally, she makes a mistake that 99% of Chrome extension developers make, assuming that you have to put your domain in the &#8220;permissions&#8221; field in order to make cross-origin web requests to it.<\/p>\n<p>There are a few <a href=\"https:\/\/stackoverflow.com\/questions\/11091277\/send-xhr-request-from-chrome-extension-with-cookies\">Stack Overflow threads like this one<\/a> and <a href=\"https:\/\/stackoverflow.com\/questions\/23192375\/send-cookies-with-ajax-call-from-chrome-extension-content-script\">this one<\/a> that explain the issue, but they also leave out key details and insights.<\/p>\n<p>In this article, I&#8217;ll break down exactly what you need to do to pass along cookies to cross-origin XmlHttpRequests in a Chrome extension.<\/p>\n<p><strong>Why would anyone ever want to do this to begin with?<\/strong><\/p>\n<p>So that your\u00a0web server endpoint for your Chrome extension can authenticate a user. If part of your Chrome extension setup is to let the user authenticate via a webpage, then you probably set a cookie or a session ID for that authenticated user. If your Chrome extension then makes XHR requests to your web server as part of its functionality, you&#8217;ll want to pass cookies along so that you know what user you&#8217;re dealing with.<\/p>\n<p><strong>First, let&#8217;s clarify the issue of placing &#8220;hosts&#8221; in the &#8220;permissions&#8221; field:<\/strong><\/p>\n<p>Most Chrome extension developers assume that if their website is www.mydomain.com, and their Chrome extension makes XHR requests to www.mydomain.com, then you must put www.mydomain.com in the permissions field of your manifest file. This is simply not true.<\/p>\n<p>I can understand why developers are confused about this though; Google&#8217;s documentation on <a href=\"https:\/\/developer.chrome.com\/apps\/declare_permissions\">using hosts in the permissions section of manifest.json<\/a> is poor. The document doesn&#8217;t even mention the reason for listing a host, other than to &#8220;give access to one or more hosts&#8221;. But what does &#8220;give access&#8221; mean? Furthermore, while the <a href=\"https:\/\/developer.chrome.com\/apps\/match_patterns\">page on match patterns<\/a> offers a hint at what the purpose of hosts in the permissions field are, clicking on the &#8220;host permissions&#8221; definition on this page takes you back to the original permissions page with this URL (https:\/\/developer.chrome.com\/apps\/declare_permissions#host-permissions) and unfortunately there is no content tagged with #host-permissions on that page. This is probably an error on Google&#8217;s part. SO, <strong>we are left to figure out what the purpose of &#8220;hosts&#8221; in the permissions field ON OUR OWN<\/strong>.<\/p>\n<p><em>It used to be<\/em> (prior to Chrome 85) that you could <strong>avoid caring about the Access-Control-Allow-Origin header<\/strong> if you <strong>placed www.mydomain.com in the &#8220;permissions&#8221; field of the manifest<\/strong>. It used to be that to make cross origin XHR requests, listing your domain in the permissions field was <em>only needed if the web server for the domain doesn&#8217;t already allow cross-origin requests<\/em>. But now, with <a href=\"https:\/\/www.chromium.org\/Home\/chromium-security\/extension-content-script-fetches\/\">Chrome&#8217;s new CORS security policy as of Chrome 85<\/a>, to make any cross-origin XHR request <strong>from a content script<\/strong>, the <strong>server has to respond with an appropriate Access-Control-Allow-Origin header<\/strong>. So, let&#8217;s say you&#8217;re making a cross-origin request to www.facebook.com from your content script. Well, now, just having www.facebook.com in the &#8220;permissions&#8221; field isn&#8217;t enough. You would need to ensure that Access-Control-Allow-Origin for www.facebook.com was set to * or your actual content script&#8217;s origin. Now, this only applies to content scripts. If you&#8217;re making cross origin XHR requests from a background script, then as long as the domain is listed in &#8220;permissions&#8221;, it doesn&#8217;t matter if Access-Control-Allow-Origin isn&#8217;t present or isn&#8217;t set right.<\/p>\n<p>If the only reason you&#8217;re putting your domain in the permissions field is so you can make AJAX XHR requests to it, then don&#8217;t do it. Just handle it on the web server by setting the Access-Control-Allow-Origin header. Since the fact that a domain is listed in the &#8220;permissions&#8221; field of manifest.json no longer means you can make cross-origin requests to it from an extension&#8217;s content script, the &#8220;permissions&#8221; field has essentially become devalued.<\/p>\n<p>There are OTHER reasons you may need a host in the permissions field, EVEN IF the host already has the Access-Control-Allow-Origin header set to *. If you need\u00a0programatic access to the host&#8217;s cookies, and you\u00a0declare the &#8220;cookies&#8221; permission in the manifest, then you&#8217;ll also need to declare the host in the permissions field. This is only if you need to access the cookies without making an XHR request. The <a href=\"https:\/\/developer.chrome.com\/extensions\/cookies\">documentation on the cookies permission field<\/a>\u00a0states that &#8220;To use the cookies API, you must declare the &#8220;cookies&#8221; permission in your manifest, along with host permissions for any hosts whose cookies you want to access.&#8221;<\/p>\n<p>It&#8217;s important to understand this because at some point in the evolution of your Chrome extension, you may find that you separate your web server into <strong>www.mydomain.com<\/strong> and <strong>extension.mydomain.com<\/strong>, so that your marketing website can live at www.mydomain.com and your extension makes calls to extension.mydomain.com. Since Chrome extensions <a href=\"https:\/\/developer.chrome.com\/apps\/permission_warnings#declare_manifest:~:text=do%20not%20future%20proof\">don&#8217;t allow you to future-proof your code<\/a>\u00a0you may have missed putting extension.mydomain.com in the permissions when you first launched. And if you add it later, your extension will become disabled for everyone until they accept your new permissions, which can be catastrophic to the user base for an extension. So, instead of updating the permissions field, you only need to set your server to allow cross origin requests.<\/p>\n<p>It&#8217;s also important to understand this because you don&#8217;t want to scare off users when they click the &#8220;Install&#8221; button and get the permissions warning popup. If you list hosts in &#8220;permissions&#8221;, the user will be told that you want to\u00a0have the ability\u00a0to change the data on those sites. If you don&#8217;t, and\u00a0just\u00a0handle it\u00a0via the\u00a0the web server, you can reduce potentially scary permissions warnings.<\/p>\n<p><strong>Now, let&#8217;s talk about sending cookies over the wire with XmlHttpRequests.<\/strong><\/p>\n<p>Now that you\u00a0understand what is and isn&#8217;t required to make cross origin requests, let&#8217;s talk about\u00a0sending cookies with these requests.<\/p>\n<p>First, you do\u00a0<strong>not need to declare the &#8220;cookies&#8221; permission<\/strong> in your manifest.json, even though most developers assume you do. Google doesn&#8217;t do a good job of explaining what this &#8220;cookies&#8221; permission is for, but it&#8217;s NOT for passing along cookies in XHR requests. And as\u00a0discussed above, you don&#8217;t necessarily need to declare the host in your &#8220;permissions&#8221; field either.<\/p>\n<p><strong>There are three things you need to make sure of to do this:<\/strong><\/p>\n<ol>\n<li>Set <strong>withCredentials=true<\/strong> in your <strong>XMLHttpRequest<\/strong>. Here&#8217;s a <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/XMLHttpRequest\/withCredentials\">more detailed explanation of when .withCredentials is necessary<\/a>. It&#8217;s not necessary for non-cross origin requests, so if the XHR call is being made from the same domain as the destination domain of the XHR request, then .withCredentials has no effect. But for a Chrome extension&#8217;s content script the &#8220;origin&#8221; is the &#8220;<a href=\"https:\/\/developer.chrome.com\/extensions\/xhr#classSummary:~:text=web%20origin\">web origin<\/a> that the content script has been injected into&#8221;, and so you&#8217;re almost always making a cross-origin request when making an XHR call.<\/li>\n<li>Make sure that the cookie(s) that you want to transmit to the server via the XHR request were originally set with the <strong>SameSite=None<\/strong> and <strong>Secure<\/strong> attributes. This is a new requirement in 2020. If Chrome has stored 100 cookies for www.mydomain.com and you make an XHR request from mail.google.com to www.mydomain.com, only the cookies out of the 100 that have those two attributes set will be transmitted. You can see exactly what cookies are transmitted by going to the &#8220;Cookies&#8221; sub-tab in the specific network row in the Network tab. If a cookie is not transmitted, hover over the &#8220;i&#8221; circular icon for an explanation as to why.<\/li>\n<li>If your code needs access to the XHR request&#8217;s <strong>response<\/strong>, make sure the <b>Access<\/b>&#8211;<b>Control<\/b>&#8211;<b>Allow<\/b>&#8211;<b>Origin<\/b>\u00a0header of your server response is <strong>NOT set to *<\/strong>. This isn&#8217;t allowed. If you do this, then your XHR request set with withCredentials=true will be sent along with all compliant cookies, BUT your content script won&#8217;t have access to the response from the XHR request. This error will be logged in the console:<span style=\"color: #ff0000;\"><code>Access to XMLHttpRequest at 'https:\/\/www.domain.com\/ReceiveCookies' from origin 'https:\/\/mail.google.com' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.<\/code><\/span>So if your content script code needs access to the web server&#8217;s response, <b>Access<\/b>&#8211;<b>Control<\/b>&#8211;<b>Allow<\/b>&#8211;<b>Origin<\/b>\u00a0needs to be set more specifically to the origin from which the request is being made. In my case, that is https:\/\/mail.google.com since my extension works inside Gmail. Now IF you only care about transmitting a request to the server for processing and not reading the server&#8217;s response, you actually don&#8217;t need to bother with this. For example, <strong>you can make a cross-origin XHR request that SETS a cookie even though <b>Access<\/b>&#8211;<b>Control<\/b>&#8211;<b>Allow<\/b>&#8211;<b>Origin<\/b> is *<\/strong>, but your <strong>code won&#8217;t be able to read a JSON response or any kind of response<\/strong> because access to it will be blocked.What you see in <strong>Chrome Dev Tools<\/strong> can be deceptive. In the case where you make an XHR request and set <strong>withCredentials=true<\/strong>, but <strong>Access-Control-Allow-Origin=*<\/strong>, the item will show as <span style=\"color: #ff0000;\">RED<\/span> in Chrome Dev Tools and the <strong>Console<\/strong> will show an error too, BUT in actuality, <strong>compliant cookies were transmitted<\/strong> as part of the response, and <strong>any cookies set by the server are received in the response and set by the browser<\/strong>. It&#8217;s just that because Access-Control-Allow-Origin was *, your JavaScript code can&#8217;t read the XHR request&#8217;s response.<a href=\"https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2019\/07\/Access-Control-Allow-Origin-asterisk-202kb.png\" data-rel=\"lightbox-image-0\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-13751 size-full\" src=\"https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2019\/07\/Access-Control-Allow-Origin-asterisk-202kb.png\" alt=\"Access-Control-Allow-Origin-asterisk\" width=\"1224\" height=\"612\" srcset=\"https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2019\/07\/Access-Control-Allow-Origin-asterisk-202kb.png 1224w, https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2019\/07\/Access-Control-Allow-Origin-asterisk-202kb-300x150.png 300w, https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2019\/07\/Access-Control-Allow-Origin-asterisk-202kb-768x384.png 768w, https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2019\/07\/Access-Control-Allow-Origin-asterisk-202kb-1024x512.png 1024w, https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2019\/07\/Access-Control-Allow-Origin-asterisk-202kb-24x12.png 24w, https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2019\/07\/Access-Control-Allow-Origin-asterisk-202kb-36x18.png 36w, https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2019\/07\/Access-Control-Allow-Origin-asterisk-202kb-48x24.png 48w\" sizes=\"auto, (max-width: 1224px) 100vw, 1224px\" \/><\/a><br \/>\n<a href=\"https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2019\/07\/002-with-credentials-false-183kb.png\" data-rel=\"lightbox-image-1\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-13752 size-full\" src=\"https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2019\/07\/002-with-credentials-false-183kb.png\" alt=\"with credentials false\" width=\"1224\" height=\"256\" srcset=\"https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2019\/07\/002-with-credentials-false-183kb.png 1224w, https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2019\/07\/002-with-credentials-false-183kb-300x63.png 300w, https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2019\/07\/002-with-credentials-false-183kb-768x161.png 768w, https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2019\/07\/002-with-credentials-false-183kb-1024x214.png 1024w, https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2019\/07\/002-with-credentials-false-183kb-24x5.png 24w, https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2019\/07\/002-with-credentials-false-183kb-36x8.png 36w, https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2019\/07\/002-with-credentials-false-183kb-48x10.png 48w\" sizes=\"auto, (max-width: 1224px) 100vw, 1224px\" \/><\/a><br \/>\nEven more confusing is if I set <strong>withCredentials=false<\/strong>, then the item is NOT RED, everything looks normal, except the cookies aren&#8217;t transmitted, as expected, since that&#8217;s the whole point of <strong>withCredentials=false<\/strong>. BUT, the response has a <strong>Set-Cookie<\/strong> header that is trying to SET COOKIES, and this WILL FAIL, AND NOT SET THE COOKIE, but <strong>you&#8217;ll be none the wiser because Dev Tools makes it look like everything worked<\/strong>.<\/p>\n<p><a href=\"https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2019\/07\/003-set-cookie-failed-176kb.png\" data-rel=\"lightbox-image-2\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-13753 size-full\" src=\"https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2019\/07\/003-set-cookie-failed-176kb.png\" alt=\"set cookie failed\" width=\"1224\" height=\"844\" srcset=\"https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2019\/07\/003-set-cookie-failed-176kb.png 1224w, https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2019\/07\/003-set-cookie-failed-176kb-300x207.png 300w, https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2019\/07\/003-set-cookie-failed-176kb-768x530.png 768w, https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2019\/07\/003-set-cookie-failed-176kb-1024x706.png 1024w, https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2019\/07\/003-set-cookie-failed-176kb-24x17.png 24w, https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2019\/07\/003-set-cookie-failed-176kb-36x25.png 36w, https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2019\/07\/003-set-cookie-failed-176kb-48x33.png 48w\" sizes=\"auto, (max-width: 1224px) 100vw, 1224px\" \/><\/a><\/p>\n<p>Even the <strong>Cookies<\/strong> tab on that <strong>Network request<\/strong> makes it seem like everything worked:<\/p>\n<p><a href=\"https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2019\/07\/004-network-tab-red-indicator-not-accurate-40kb.png\" data-rel=\"lightbox-image-3\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-13754 size-full\" src=\"https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2019\/07\/004-network-tab-red-indicator-not-accurate-40kb.png\" alt=\"network tab red indicator not accurate\" width=\"1224\" height=\"180\" srcset=\"https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2019\/07\/004-network-tab-red-indicator-not-accurate-40kb.png 1224w, https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2019\/07\/004-network-tab-red-indicator-not-accurate-40kb-300x44.png 300w, https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2019\/07\/004-network-tab-red-indicator-not-accurate-40kb-768x113.png 768w, https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2019\/07\/004-network-tab-red-indicator-not-accurate-40kb-1024x151.png 1024w, https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2019\/07\/004-network-tab-red-indicator-not-accurate-40kb-24x4.png 24w, https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2019\/07\/004-network-tab-red-indicator-not-accurate-40kb-36x5.png 36w, https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2019\/07\/004-network-tab-red-indicator-not-accurate-40kb-48x7.png 48w\" sizes=\"auto, (max-width: 1224px) 100vw, 1224px\" \/><\/a><\/p>\n<p><strong>So the lesson is that whether the line in the Network tab is red or not is not an accurate indication of whether a cookie was SET based on the Set-Cookie header in the Response.<\/strong><\/li>\n<\/ol>\n<p><strong>If the Network tab in Dev Tools doesn&#8217;t show you the cookies&#8230;<\/strong><\/p>\n<p>A recent update to the <strong>Chrome Developer Tools<\/strong> made using the <strong>Network<\/strong> tab a lot trickier. If you&#8217;re using the Network tab to monitor your XHR requests your Chrome extension is making, you&#8217;ll often see &#8220;Provisional headers shown&#8221; for the Request Headers, and you won&#8217;t see a Cookie section, so you&#8217;ll assume Cookies aren&#8217;t being sent. Perhaps you won&#8217;t then even try to retrieve the cookie on the server side. It took me a long time to figure this one out. This <a href=\"https:\/\/stackoverflow.com\/questions\/21177387\/caution-provisional-headers-are-shown-in-chrome-debugger\">stack overflow article<\/a> explains that a recent change to Chrome has made it so that you have to modify a few Chrome flags\u00a0(chrome:\/\/flags) if you want to see the full headers, including any cookies being sent.<\/p>\n<p>Once you make that change, you&#8217;ll see that your cookies are being sent.<\/p>\n<p><strong>Bonus #1: How to control the Access-Control-Allow-Origin in IIS 8 and higher<\/strong><\/p>\n<p>I run everything on IIS, so in order for me to set the header to https:\/\/mail.google.com for some calls and * for other calls, I need to:<\/p>\n<ol>\n<li>Install the <a href=\"https:\/\/www.iis.net\/downloads\/microsoft\/iis-cors-module\">IIS CORS Module<\/a> from the Web Platform Installer.<\/li>\n<li>Modify my <strong>web.config<\/strong> and add code that looks like this:<code>&lt;cors enabled=\"true\" failUnlistedOrigins=\"true\"&gt;<\/code><br \/>\n<code>&lt;add origin=\"*\" \/&gt;<\/code><br \/>\n<code>&lt;add origin=\"https:\/\/mail.google.com\"<\/code><br \/>\n<code>allowCredentials=\"true\"<\/code><br \/>\n<code>maxAge=\"120\"&gt;<\/code><code>&lt;\/add&gt;<\/code><br \/>\n<code>&lt;add origin=\"http:\/\/*\" allowed=\"false\" \/&gt;<\/code><br \/>\n<code>&lt;\/cors&gt;<\/code>The header is generated based on specificity. So if the origin is actually https:\/\/mail.google.com, then <b>Access<\/b>&#8211;<b>Control<\/b>&#8211;<b>Allow<\/b>&#8211;<b>Origin<\/b> will be set to https:\/\/mail.google.com. Otherwise, it will be set to *.<\/li>\n<\/ol>\n<p><strong>Bonus #2: How to set the SameSite and Secure attributes for a cookie in .NET.<\/strong><\/p>\n<p>This isn&#8217;t as easy as it sounds. Microsoft only <a href=\"https:\/\/devblogs.microsoft.com\/aspnet\/upcoming-samesite-cookie-changes-in-asp-net-and-asp-net-core\/\">first introduced support for the SameSite attribute for cookies in .NET 4.7.2<\/a>, so if you&#8217;re using 4.6.1 like me, then you can&#8217;t set this property. You could upgrade your entire production environment to 4.7.2, but that could create unforseen side effects without a lot of testing. Fortunately there&#8217;s another way. You can simply add the Set-Cookie header to your methods yourself and control exactly how the cookie is set in the browser. Here&#8217;s how I do it:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\npublic ActionResult SetExtensionInstallCookie()\r\n\r\n{\r\n\r\n\/*HttpCookie cookie = new HttpCookie(&quot;GMassExtensionInstall&quot;, &quot;yes&quot;);\r\n\r\ncookie.Expires = DateTime.UtcNow.AddYears(1);\r\n\r\n\/\/cookie.SameSite = SameSiteMode.None;\r\n\r\nResponse.SetCookie(cookie);*\/\r\n\r\nHttpContext.Response.Headers.Add(&quot;Set-Cookie&quot;, &quot;GMassExtensionInstall=yes; expires=Sun, 21-Sep-2025 03:40:10 GMT; path=\/; SameSite=None; Secure&quot;);\r\n\r\nvar json = Json(new\r\n\r\n{\r\n\r\nsuccess = true\r\n\r\n}, JsonRequestBehavior.AllowGet);\r\n\r\nreturn json;\r\n\r\n}\r\n<\/pre>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>When developing a Chrome extension, you might need\u00a0to get an XMLHttpRequest that&#8217;s part of a content script to send cookies for a domain when making a request to\u2026<\/p>\n","protected":false},"author":2,"featured_media":22173,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[3770,3462],"tags":[],"class_list":["post-9349","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-chrome-extensions","category-developers"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.3 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\r\n<title>How to send a cookie with a cross-origin XMLHttpRequest from a Chrome extension<\/title>\r\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\r\n<link rel=\"canonical\" href=\"https:\/\/www.gmass.co\/blog\/send-cookie-cross-origin-xmlhttprequest-chrome-extension\/\" \/>\r\n<meta property=\"og:locale\" content=\"en_US\" \/>\r\n<meta property=\"og:type\" content=\"article\" \/>\r\n<meta property=\"og:title\" content=\"How to send a cookie with a cross-origin XMLHttpRequest from a Chrome extension\" \/>\r\n<meta property=\"og:description\" content=\"When developing a Chrome extension, you might need\u00a0to get an XMLHttpRequest that&#8217;s part of a content script to send cookies for a domain when making a request to\u2026\" \/>\r\n<meta property=\"og:url\" content=\"https:\/\/www.gmass.co\/blog\/send-cookie-cross-origin-xmlhttprequest-chrome-extension\/\" \/>\r\n<meta property=\"og:site_name\" content=\"GMass Blog\" \/>\r\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/GmailMailMerge\/\" \/>\r\n<meta property=\"article:published_time\" content=\"2019-07-12T08:53:05+00:00\" \/>\r\n<meta property=\"article:modified_time\" content=\"2022-12-08T00:50:22+00:00\" \/>\r\n<meta property=\"og:image\" content=\"https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2021\/03\/How-to-send-a-cookie-with-a-cross-origin-01-01-tinified.png\" \/>\r\n\t<meta property=\"og:image:width\" content=\"2000\" \/>\r\n\t<meta property=\"og:image:height\" content=\"936\" \/>\r\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\r\n<meta name=\"author\" content=\"Ajay Goel\" \/>\r\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\r\n<meta name=\"twitter:creator\" content=\"@PartTimeSnob\" \/>\r\n<meta name=\"twitter:site\" content=\"@GMassForGmail\" \/>\r\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Ajay Goel\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"11 minutes\" \/>\r\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.gmass.co\\\/blog\\\/send-cookie-cross-origin-xmlhttprequest-chrome-extension\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.gmass.co\\\/blog\\\/send-cookie-cross-origin-xmlhttprequest-chrome-extension\\\/\"},\"author\":{\"name\":\"Ajay Goel\",\"@id\":\"https:\\\/\\\/www.gmass.co\\\/blog\\\/#\\\/schema\\\/person\\\/b5fa74f8765b860701158fd77162fff8\"},\"headline\":\"How to send a cookie with a cross-origin XMLHttpRequest from a Chrome extension\",\"datePublished\":\"2019-07-12T08:53:05+00:00\",\"dateModified\":\"2022-12-08T00:50:22+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.gmass.co\\\/blog\\\/send-cookie-cross-origin-xmlhttprequest-chrome-extension\\\/\"},\"wordCount\":2191,\"commentCount\":4,\"image\":{\"@id\":\"https:\\\/\\\/www.gmass.co\\\/blog\\\/send-cookie-cross-origin-xmlhttprequest-chrome-extension\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.gmass.co\\\/blog\\\/wp-content\\\/uploads\\\/2021\\\/03\\\/How-to-send-a-cookie-with-a-cross-origin-01-01-tinified.png\",\"articleSection\":[\"Chrome Extensions\",\"Developers\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.gmass.co\\\/blog\\\/send-cookie-cross-origin-xmlhttprequest-chrome-extension\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.gmass.co\\\/blog\\\/send-cookie-cross-origin-xmlhttprequest-chrome-extension\\\/\",\"url\":\"https:\\\/\\\/www.gmass.co\\\/blog\\\/send-cookie-cross-origin-xmlhttprequest-chrome-extension\\\/\",\"name\":\"How to send a cookie with a cross-origin XMLHttpRequest from a Chrome extension\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.gmass.co\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.gmass.co\\\/blog\\\/send-cookie-cross-origin-xmlhttprequest-chrome-extension\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.gmass.co\\\/blog\\\/send-cookie-cross-origin-xmlhttprequest-chrome-extension\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.gmass.co\\\/blog\\\/wp-content\\\/uploads\\\/2021\\\/03\\\/How-to-send-a-cookie-with-a-cross-origin-01-01-tinified.png\",\"datePublished\":\"2019-07-12T08:53:05+00:00\",\"dateModified\":\"2022-12-08T00:50:22+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/www.gmass.co\\\/blog\\\/#\\\/schema\\\/person\\\/b5fa74f8765b860701158fd77162fff8\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.gmass.co\\\/blog\\\/send-cookie-cross-origin-xmlhttprequest-chrome-extension\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.gmass.co\\\/blog\\\/send-cookie-cross-origin-xmlhttprequest-chrome-extension\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.gmass.co\\\/blog\\\/send-cookie-cross-origin-xmlhttprequest-chrome-extension\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.gmass.co\\\/blog\\\/wp-content\\\/uploads\\\/2021\\\/03\\\/How-to-send-a-cookie-with-a-cross-origin-01-01-tinified.png\",\"contentUrl\":\"https:\\\/\\\/www.gmass.co\\\/blog\\\/wp-content\\\/uploads\\\/2021\\\/03\\\/How-to-send-a-cookie-with-a-cross-origin-01-01-tinified.png\",\"width\":2000,\"height\":936},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.gmass.co\\\/blog\\\/send-cookie-cross-origin-xmlhttprequest-chrome-extension\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.gmass.co\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"How to send a cookie with a cross-origin XMLHttpRequest from a Chrome extension\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.gmass.co\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.gmass.co\\\/blog\\\/\",\"name\":\"GMass Blog\",\"description\":\"Tips and tricks for sending mail merge and mass email campaigns directly from Gmail\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.gmass.co\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.gmass.co\\\/blog\\\/#\\\/schema\\\/person\\\/b5fa74f8765b860701158fd77162fff8\",\"name\":\"Ajay Goel\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/f3a70af05bbabe47925150d5a1320540e801b78055a74da20658fc97cd0706a2?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/f3a70af05bbabe47925150d5a1320540e801b78055a74da20658fc97cd0706a2?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/f3a70af05bbabe47925150d5a1320540e801b78055a74da20658fc97cd0706a2?s=96&d=mm&r=g\",\"caption\":\"Ajay Goel\"},\"description\":\"Ajay is the founder of GMass and has been developing email sending software for 20 years.\",\"sameAs\":[\"https:\\\/\\\/twitter.com\\\/PartTimeSnob\",\"https:\\\/\\\/x.com\\\/PartTimeSnob\"],\"url\":\"https:\\\/\\\/www.gmass.co\\\/blog\\\/author\\\/ajay-goel\\\/\"}]}<\/script>\r\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"How to send a cookie with a cross-origin XMLHttpRequest from a Chrome extension","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.gmass.co\/blog\/send-cookie-cross-origin-xmlhttprequest-chrome-extension\/","og_locale":"en_US","og_type":"article","og_title":"How to send a cookie with a cross-origin XMLHttpRequest from a Chrome extension","og_description":"When developing a Chrome extension, you might need\u00a0to get an XMLHttpRequest that&#8217;s part of a content script to send cookies for a domain when making a request to\u2026","og_url":"https:\/\/www.gmass.co\/blog\/send-cookie-cross-origin-xmlhttprequest-chrome-extension\/","og_site_name":"GMass Blog","article_publisher":"https:\/\/www.facebook.com\/GmailMailMerge\/","article_published_time":"2019-07-12T08:53:05+00:00","article_modified_time":"2022-12-08T00:50:22+00:00","og_image":[{"width":2000,"height":936,"url":"https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2021\/03\/How-to-send-a-cookie-with-a-cross-origin-01-01-tinified.png","type":"image\/png"}],"author":"Ajay Goel","twitter_card":"summary_large_image","twitter_creator":"@PartTimeSnob","twitter_site":"@GMassForGmail","twitter_misc":{"Written by":"Ajay Goel","Est. reading time":"11 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.gmass.co\/blog\/send-cookie-cross-origin-xmlhttprequest-chrome-extension\/#article","isPartOf":{"@id":"https:\/\/www.gmass.co\/blog\/send-cookie-cross-origin-xmlhttprequest-chrome-extension\/"},"author":{"name":"Ajay Goel","@id":"https:\/\/www.gmass.co\/blog\/#\/schema\/person\/b5fa74f8765b860701158fd77162fff8"},"headline":"How to send a cookie with a cross-origin XMLHttpRequest from a Chrome extension","datePublished":"2019-07-12T08:53:05+00:00","dateModified":"2022-12-08T00:50:22+00:00","mainEntityOfPage":{"@id":"https:\/\/www.gmass.co\/blog\/send-cookie-cross-origin-xmlhttprequest-chrome-extension\/"},"wordCount":2191,"commentCount":4,"image":{"@id":"https:\/\/www.gmass.co\/blog\/send-cookie-cross-origin-xmlhttprequest-chrome-extension\/#primaryimage"},"thumbnailUrl":"https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2021\/03\/How-to-send-a-cookie-with-a-cross-origin-01-01-tinified.png","articleSection":["Chrome Extensions","Developers"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.gmass.co\/blog\/send-cookie-cross-origin-xmlhttprequest-chrome-extension\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.gmass.co\/blog\/send-cookie-cross-origin-xmlhttprequest-chrome-extension\/","url":"https:\/\/www.gmass.co\/blog\/send-cookie-cross-origin-xmlhttprequest-chrome-extension\/","name":"How to send a cookie with a cross-origin XMLHttpRequest from a Chrome extension","isPartOf":{"@id":"https:\/\/www.gmass.co\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.gmass.co\/blog\/send-cookie-cross-origin-xmlhttprequest-chrome-extension\/#primaryimage"},"image":{"@id":"https:\/\/www.gmass.co\/blog\/send-cookie-cross-origin-xmlhttprequest-chrome-extension\/#primaryimage"},"thumbnailUrl":"https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2021\/03\/How-to-send-a-cookie-with-a-cross-origin-01-01-tinified.png","datePublished":"2019-07-12T08:53:05+00:00","dateModified":"2022-12-08T00:50:22+00:00","author":{"@id":"https:\/\/www.gmass.co\/blog\/#\/schema\/person\/b5fa74f8765b860701158fd77162fff8"},"breadcrumb":{"@id":"https:\/\/www.gmass.co\/blog\/send-cookie-cross-origin-xmlhttprequest-chrome-extension\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.gmass.co\/blog\/send-cookie-cross-origin-xmlhttprequest-chrome-extension\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.gmass.co\/blog\/send-cookie-cross-origin-xmlhttprequest-chrome-extension\/#primaryimage","url":"https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2021\/03\/How-to-send-a-cookie-with-a-cross-origin-01-01-tinified.png","contentUrl":"https:\/\/www.gmass.co\/blog\/wp-content\/uploads\/2021\/03\/How-to-send-a-cookie-with-a-cross-origin-01-01-tinified.png","width":2000,"height":936},{"@type":"BreadcrumbList","@id":"https:\/\/www.gmass.co\/blog\/send-cookie-cross-origin-xmlhttprequest-chrome-extension\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.gmass.co\/blog\/"},{"@type":"ListItem","position":2,"name":"How to send a cookie with a cross-origin XMLHttpRequest from a Chrome extension"}]},{"@type":"WebSite","@id":"https:\/\/www.gmass.co\/blog\/#website","url":"https:\/\/www.gmass.co\/blog\/","name":"GMass Blog","description":"Tips and tricks for sending mail merge and mass email campaigns directly from Gmail","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.gmass.co\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.gmass.co\/blog\/#\/schema\/person\/b5fa74f8765b860701158fd77162fff8","name":"Ajay Goel","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/f3a70af05bbabe47925150d5a1320540e801b78055a74da20658fc97cd0706a2?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/f3a70af05bbabe47925150d5a1320540e801b78055a74da20658fc97cd0706a2?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/f3a70af05bbabe47925150d5a1320540e801b78055a74da20658fc97cd0706a2?s=96&d=mm&r=g","caption":"Ajay Goel"},"description":"Ajay is the founder of GMass and has been developing email sending software for 20 years.","sameAs":["https:\/\/twitter.com\/PartTimeSnob","https:\/\/x.com\/PartTimeSnob"],"url":"https:\/\/www.gmass.co\/blog\/author\/ajay-goel\/"}]}},"_links":{"self":[{"href":"https:\/\/www.gmass.co\/blog\/wp-json\/wp\/v2\/posts\/9349","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.gmass.co\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.gmass.co\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.gmass.co\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.gmass.co\/blog\/wp-json\/wp\/v2\/comments?post=9349"}],"version-history":[{"count":23,"href":"https:\/\/www.gmass.co\/blog\/wp-json\/wp\/v2\/posts\/9349\/revisions"}],"predecessor-version":[{"id":22176,"href":"https:\/\/www.gmass.co\/blog\/wp-json\/wp\/v2\/posts\/9349\/revisions\/22176"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.gmass.co\/blog\/wp-json\/wp\/v2\/media\/22173"}],"wp:attachment":[{"href":"https:\/\/www.gmass.co\/blog\/wp-json\/wp\/v2\/media?parent=9349"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.gmass.co\/blog\/wp-json\/wp\/v2\/categories?post=9349"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.gmass.co\/blog\/wp-json\/wp\/v2\/tags?post=9349"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}