<h3 dir="auto">Expected Behavior</h3>

<p dir="auto">I should be able to set <code class="notranslate">SESSION_COOKIE_SAMESITE</code> to "None" in order to explicitly set <code class="notranslate">SameSite=None</code> on my session cookie.</p>
<p dir="auto">This will allow my flask application to be loaded in an iframe with the session.</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="app.config['SESSION_COOKIE_SAMESITE'] = &quot;None&quot;"><pre class="notranslate"><span class="pl-s1">app</span>.<span class="pl-s1">config</span>[<span class="pl-s">'SESSION_COOKIE_SAMESITE'</span>] <span class="pl-c1">=</span> <span class="pl-s">"None"</span></pre></div>
<h3 dir="auto">Actual Behavior</h3>

<p dir="auto">Today I can only set <code class="notranslate">SESSION_COOKIE_SAMESITE</code> to "Strict", "Lax", or <code class="notranslate">None</code>.</p>
<p dir="auto">If set to <code class="notranslate">None</code>, it will actually <em>not</em> set a SameSite attribute at all on the session cookie, which Chrome will treat as <code class="notranslate">SameSite=Lax</code> <a href="https://web.dev/samesite-cookies-explained/" rel="nofollow">starting in Chrome 80</a>.</p>
<p dir="auto">I need to be able to set SESSION_COOKIE_SAMESITE to explicitly "None", thus causing <code class="notranslate">SameSite=None</code> to be set on the cookie, which in turn allows the cookie to be sent in cross-origin requests, such as when my flask application is loaded in an iframe.</p>
<p dir="auto">As it is, these applications load in an iframe without a session cookie, which breaks their functionality.</p>
<h3 dir="auto">Environment</h3>
<ul dir="auto">
<li>Python version: 3.7.4</li>
<li>Flask version: 1.1.1</li>
<li>Werkzeug version: 0.16.0</li>
</ul>
<p dir="auto">Note related Werkzeug issue which is tied up with the 1.0 release: <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="445714870" data-permission-text="Title is private" data-url="https://github.com/pallets/werkzeug/issues/1549" data-hovercard-type="issue" data-hovercard-url="/pallets/werkzeug/issues/1549/hovercard" href="https://github.com/pallets/werkzeug/issues/1549">pallets/werkzeug#1549</a></p>
<div class="highlight highlight-text-python-traceback notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="2020-01-14T20:33:48.807523+00:00 app[web.1]: Traceback (most recent call last):
2020-01-14T20:33:48.807525+00:00 app[web.1]: File &quot;/app/.heroku/python/lib/python3.7/site-packages/gunicorn/workers/sync.py&quot;, line 135, in handle
2020-01-14T20:33:48.807528+00:00 app[web.1]: self.handle_request(listener, req, client, addr)
2020-01-14T20:33:48.807530+00:00 app[web.1]: File &quot;/app/.heroku/python/lib/python3.7/site-packages/gunicorn/workers/sync.py&quot;, line 176, in handle_request
2020-01-14T20:33:48.807534+00:00 app[web.1]: respiter = self.wsgi(environ, resp.start_response)
2020-01-14T20:33:48.807536+00:00 app[web.1]: File &quot;/app/.heroku/python/lib/python3.7/site-packages/flask/app.py&quot;, line 2463, in __call__
2020-01-14T20:33:48.807538+00:00 app[web.1]: return self.wsgi_app(environ, start_response)
2020-01-14T20:33:48.807540+00:00 app[web.1]: File &quot;/app/.heroku/python/lib/python3.7/site-packages/flask/app.py&quot;, line 2449, in wsgi_app
2020-01-14T20:33:48.807542+00:00 app[web.1]: response = self.handle_exception(e)
2020-01-14T20:33:48.807544+00:00 app[web.1]: File &quot;/app/.heroku/python/lib/python3.7/site-packages/flask/app.py&quot;, line 1866, in handle_exception
2020-01-14T20:33:48.807546+00:00 app[web.1]: reraise(exc_type, exc_value, tb)
2020-01-14T20:33:48.807548+00:00 app[web.1]: File &quot;/app/.heroku/python/lib/python3.7/site-packages/flask/_compat.py&quot;, line 39, in reraise
2020-01-14T20:33:48.807549+00:00 app[web.1]: raise value
2020-01-14T20:33:48.807551+00:00 app[web.1]: File &quot;/app/.heroku/python/lib/python3.7/site-packages/flask/app.py&quot;, line 2446, in wsgi_app
2020-01-14T20:33:48.807553+00:00 app[web.1]: response = self.full_dispatch_request()
2020-01-14T20:33:48.807554+00:00 app[web.1]: File &quot;/app/.heroku/python/lib/python3.7/site-packages/flask/app.py&quot;, line 1952, in full_dispatch_request
2020-01-14T20:33:48.807556+00:00 app[web.1]: return self.finalize_request(rv)
2020-01-14T20:33:48.807557+00:00 app[web.1]: File &quot;/app/.heroku/python/lib/python3.7/site-packages/flask/app.py&quot;, line 1969, in finalize_request
2020-01-14T20:33:48.807559+00:00 app[web.1]: response = self.process_response(response)
2020-01-14T20:33:48.807560+00:00 app[web.1]: File &quot;/app/.heroku/python/lib/python3.7/site-packages/flask/app.py&quot;, line 2268, in process_response
2020-01-14T20:33:48.807562+00:00 app[web.1]: self.session_interface.save_session(self, ctx.session, response)
2020-01-14T20:33:48.807563+00:00 app[web.1]: File &quot;/app/.heroku/python/lib/python3.7/site-packages/flask/sessions.py&quot;, line 387, in save_session
2020-01-14T20:33:48.807565+00:00 app[web.1]: samesite=samesite,
2020-01-14T20:33:48.807567+00:00 app[web.1]: File &quot;/app/.heroku/python/lib/python3.7/site-packages/werkzeug/wrappers/base_response.py&quot;, line 481, in set_cookie
2020-01-14T20:33:48.807568+00:00 app[web.1]: samesite=samesite,
2020-01-14T20:33:48.807570+00:00 app[web.1]: File &quot;/app/.heroku/python/lib/python3.7/site-packages/werkzeug/http.py&quot;, line 1161, in dump_cookie
2020-01-14T20:33:48.807571+00:00 app[web.1]: raise ValueError(&quot;invalid SameSite value; must be 'Strict', 'Lax' or None&quot;)
2020-01-14T20:33:48.807573+00:00 app[web.1]: ValueError: invalid SameSite value; must be 'Strict', 'Lax' or None```"><pre class="notranslate">2020-01-14T20:33:48.807523+00:00 app[web.1]: Traceback (most recent call last):
2020-01-14T20:33:48.807525+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/gunicorn/workers/sync.py", line 135, in handle
2020-01-14T20:33:48.807528+00:00 app[web.1]: self.handle_request(listener, req, client, addr)
2020-01-14T20:33:48.807530+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/gunicorn/workers/sync.py", line 176, in handle_request
2020-01-14T20:33:48.807534+00:00 app[web.1]: respiter = self.wsgi(environ, resp.start_response)
2020-01-14T20:33:48.807536+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/flask/app.py", line 2463, in __call__
2020-01-14T20:33:48.807538+00:00 app[web.1]: return self.wsgi_app(environ, start_response)
2020-01-14T20:33:48.807540+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/flask/app.py", line 2449, in wsgi_app
2020-01-14T20:33:48.807542+00:00 app[web.1]: response = self.handle_exception(e)
2020-01-14T20:33:48.807544+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/flask/app.py", line 1866, in handle_exception
2020-01-14T20:33:48.807546+00:00 app[web.1]: reraise(exc_type, exc_value, tb)
2020-01-14T20:33:48.807548+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/flask/_compat.py", line 39, in reraise
2020-01-14T20:33:48.807549+00:00 app[web.1]: raise value
2020-01-14T20:33:48.807551+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/flask/app.py", line 2446, in wsgi_app
2020-01-14T20:33:48.807553+00:00 app[web.1]: response = self.full_dispatch_request()
2020-01-14T20:33:48.807554+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/flask/app.py", line 1952, in full_dispatch_request
2020-01-14T20:33:48.807556+00:00 app[web.1]: return self.finalize_request(rv)
2020-01-14T20:33:48.807557+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/flask/app.py", line 1969, in finalize_request
2020-01-14T20:33:48.807559+00:00 app[web.1]: response = self.process_response(response)
2020-01-14T20:33:48.807560+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/flask/app.py", line 2268, in process_response
2020-01-14T20:33:48.807562+00:00 app[web.1]: self.session_interface.save_session(self, ctx.session, response)
2020-01-14T20:33:48.807563+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/flask/sessions.py", line 387, in save_session
2020-01-14T20:33:48.807565+00:00 app[web.1]: samesite=samesite,
2020-01-14T20:33:48.807567+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/werkzeug/wrappers/base_response.py", line 481, in set_cookie
2020-01-14T20:33:48.807568+00:00 app[web.1]: samesite=samesite,
2020-01-14T20:33:48.807570+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/werkzeug/http.py", line 1161, in dump_cookie
2020-01-14T20:33:48.807571+00:00 app[web.1]: raise ValueError("invalid SameSite value; must be 'Strict', 'Lax' or None")
2020-01-14T20:33:48.807573+00:00 app[web.1]: ValueError: invalid SameSite value; must be 'Strict', 'Lax' or None```</pre></div>
<p dir="auto">Google's recent <a href="https://blog.chromium.org/2019/05/improving-privacy-and-security-on-web.html" rel="nofollow">blog post</a> describes changes on how they will enforce Cookies with SameSite value. The referenced <a href="https://web.dev/samesite-cookies-explained/" rel="nofollow">samesite cookies explained article</a> and <a href="https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1" rel="nofollow">RFC</a> both describe the ability to specify a SameSite value of 'None' the string (as opposed to None, not set) for SameSite.</p>
<p dir="auto">The following today produces an error stating <em>invalid SameSite value; must be 'Strict', 'Lax' or None</em></p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="resp.set_cookie('somekey', 'someval', domain='.mydomain.com', samesite='None')"><pre class="notranslate"><span class="pl-s1">resp</span>.<span class="pl-en">set_cookie</span>(<span class="pl-s">'somekey'</span>, <span class="pl-s">'someval'</span>, <span class="pl-s1">domain</span><span class="pl-c1">=</span><span class="pl-s">'.mydomain.com'</span>, <span class="pl-s1">samesite</span><span class="pl-c1">=</span><span class="pl-s">'None'</span>)</pre></div>
<p dir="auto">You would think setting <code class="notranslate">None</code> would work but instead it unsets the key and prevents the samesite attribute from being present with a None (string) value in the headers.</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="resp.set_cookie('somekey', 'someval', domain='.mydomain.com', samesite=None)"><pre class="notranslate"><span class="pl-s1">resp</span>.<span class="pl-en">set_cookie</span>(<span class="pl-s">'somekey'</span>, <span class="pl-s">'someval'</span>, <span class="pl-s1">domain</span><span class="pl-c1">=</span><span class="pl-s">'.mydomain.com'</span>, <span class="pl-s1">samesite</span><span class="pl-c1">=</span><span class="pl-c1">None</span>)</pre></div>