Repository: thearchitector/starlette-securecookies (language: python)

Issue:
Expose encryption/decryption as utility?
Some external middlewares, like most CSRF middlewares, check tokens by comparing the cookie and a client-included header. If the cookie is automatically encrypted before the request is sent, the client browser will also send back the encrypted cookie in a custom header. Since the incoming cookie will be decrypted automatically, the CSRF token check will fail (comparing encrypted and decrypted forms of the same token).

Should this middleware expose a tool to decrypt arbitrary tokens based on the configured secret?

Follow up is that some apps may want to also check and compare things outside of the cookie scope, which would be currently infeasible to do.


Discussion / hints:

Fix patch:
diff --git a/.github/workflows/CI.yaml b/.github/workflows/CI.yaml
index aa11e94..c6be308 100644
--- a/.github/workflows/CI.yaml
+++ b/.github/workflows/CI.yaml
@@ -18,6 +18,6 @@ jobs:
           python-version: ${{ matrix.python-version }}
           cache: true
       - name: Install dependencies
-        run: pdm install --dev
+        run: pdm install -G :all
       - name: Run tests
         run: pdm run pytest
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 5982fd2..ba04dfb 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,7 +1,7 @@
 repos:
   # python
   - repo: https://github.com/charliermarsh/ruff-pre-commit
-    rev: v0.0.259
+    rev: v0.0.262
     hooks:
       - id: ruff
         args: ["--fix", "--exit-non-zero-on-fix"]
@@ -11,13 +11,14 @@ repos:
       - id: black
         language_version: python3.7
   - repo: https://github.com/pre-commit/mirrors-mypy
-    rev: v1.1.1
+    rev: v1.2.0
     hooks:
       - id: mypy
         exclude: ^tests
         require_serial: true
         args: ["--explicit-package-bases", "--check-untyped-defs"]
-        additional_dependencies: ["starlette>=0.6.1", "cryptography>=0"]
+        additional_dependencies:
+          ["starlette>=0.6.1", "cryptography>=2.2", "starlette-csrf>=1.4.2"]
 
   # docs
   - repo: https://github.com/pre-commit/mirrors-prettier
diff --git a/README.md b/README.md
index c4838f1..7cab6e6 100644
--- a/README.md
+++ b/README.md
@@ -13,10 +13,11 @@ Tested support on Python 3.7, 3.8, 3.9, and 3.10, 3.11 on macOS, Windows, and Li
 
 ```mermaid
 sequenceDiagram
-    Browser->>+Middleware: Encrypted cookies
-    Middleware->>+Application: Filtered / Decrypted cookies
+    Browser->>+Middleware: Encrypted 'Cookie' header
+    Middleware->>+Application: Decrypted cookies
     Application->>-Middleware: Plaintext cookies
-    Middleware->>-Browser: Encrypted 'Set-Cookie' headers
+    Middleware->>-Browser: Encrypted 'Set-Cookie' header
+    Note over Application: *The Application may be your service<br />or any additional middleware.
 ```
 
 For any incoming cookies:
@@ -30,9 +31,10 @@ For any incoming cookies:
 For any outgoing cookies:
 
 7. Your application sets cookies with `response.set_cookie` as usual.
-8. All responses returned by your application are intercepted by `SecureCookiesMiddleware`.
-9. Cookies in the `included_cookies` and `excluded_cookies` parameters are re-encrypted, and their attributes (like `"SameSite"` and `"HttpOnly"`) are overridden by the parameters set in `SecureCookiesMiddleware`.
-10. The cookies in the response are replaced by the re-encrypted cookies, and the response is propagated to Starlette to return to the client's browser.
+8. Other middleware run and add additional cookies, like [SessionMiddleware](https://www.starlette.io/middleware/#sessionmiddleware).
+9. All responses returned by your application are intercepted by `SecureCookiesMiddleware`.
+10. Cookies in the `included_cookies` and `excluded_cookies` parameters are re-encrypted, and their attributes (like `"SameSite"` and `"HttpOnly"`) are overridden by the parameters set in `SecureCookiesMiddleware` if set.
+11. The cookies in the response are replaced by the re-encrypted cookies, and the response is eventually propagated to the client's browser.
 
 ## Installation
 
@@ -44,7 +46,7 @@ $ python -m pip install --user starlette-securecookies
 
 ## Usage
 
-This is a Starlette-based middleware, so it can be used in any Starlette application or Starlette-based application (like [FastAPI](https://fastapi.tiangolo.com/advanced/middleware/) or [Starlite](https://starlite-api.github.io/starlite/usage/7-middleware/)).
+This is a Starlette-based middleware, so it can be used in any Starlette application or Starlette-based framework (like [FastAPI](https://fastapi.tiangolo.com/advanced/middleware/)).
 
 For example,
 
@@ -57,14 +59,20 @@ from securecookies import SecureCookiesMiddleware
 middleware = [
     Middleware(
         SecureCookiesMiddleware, secrets=["SUPER SECRET SECRET"],
-        # your other middlewares
+        # your other middleware
     )
 ]
 
 app = Starlette(routes=..., middleware=middleware)
 ```
 
-Note that if you're using another middleware that injects cookies into the response (such as SessionMiddleware), you have to make sure `SecureCookiesMiddleware` executes _after_ it so the cookie is present at encryption-time. Counter intuitively, in practice this means ensuring `SecureCookiesMiddleware` is _first_ in the list of middlewares.
+Note that if you're using another middleware that injects cookies into the response (such as [SessionMiddleware](https://www.starlette.io/middleware/#sessionmiddleware)), you have to make sure `SecureCookiesMiddleware` executes _after_ it so the cookie is present at encryption-time. Counter intuitively, in practice this means ensuring `SecureCookiesMiddleware` is _first_ in the list of middleware.
+
+### Extras
+
+`starlette-securecookies` provides some extras that introduce or patch secure cookie functionality into existing tools. They all reside in the `securecookies.extras` module. Currently there is only one, but more are welcome by recommendation or Pull Request!
+
+- **`csrf.SecureCSRFMiddleware`**: Adds compatibility to the CSRF middleware provided by [starlette_csrf](https://github.com/frankie567/starlette-csrf). To use it, simply add it to your list of middleware (keep in mind the ordering). If you don't want to specify `starlette_csrf` as a direct dependency, you can also install it through the `[csrf]` package extra.
 
 ## License
 
diff --git a/docs/securecookies.html b/docs/securecookies.html
index e3e5e2c..1b47313 100644
--- a/docs/securecookies.html
+++ b/docs/securecookies.html
@@ -3,7 +3,7 @@
   <head>
     <meta charset="utf-8" />
     <meta name="viewport" content="width=device-width, initial-scale=1" />
-    <meta name="generator" content="pdoc 13.0.1" />
+    <meta name="generator" content="pdoc 13.1.1" />
     <title>securecookies API documentation</title>
 
     <style>
@@ -1163,17 +1163,24 @@
     </style>
     <style>
       /*! custom.css */
-      .docstring > pre {
-        all: unset;
-      }
-      .docstring > pre > code {
-        all: unset;
-        visibility: hidden;
-      }
-      .docstring > pre > code[data-processed="true"] {
-        visibility: visible;
+    </style>
+    <style>
+      .pdoc .mermaid-pre {
+        border: none;
+        background: none;
       }
     </style>
+    <script type="module" defer>
+      import mermaid from "https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs";
+
+      /* Re-invoke Mermaid when DOM content changes, for example during search. */
+      document.addEventListener("DOMContentLoaded", () => {
+        new MutationObserver(() => mermaid.run()).observe(
+          document.querySelector("main.pdoc").parentNode,
+          { childList: true }
+        );
+      });
+    </script>
   </head>
   <body>
     <nav class="pdoc">
@@ -1207,6 +1214,11 @@ <h2>Contents</h2>
           </li>
         </ul>
 
+        <h2>Submodules</h2>
+        <ul>
+          <li><a href="securecookies/extras.html">extras</a></li>
+        </ul>
+
         <h2>API Documentation</h2>
         <ul class="memberlist">
           <li>
@@ -1278,6 +1290,21 @@ <h2>API Documentation</h2>
                   >included_cookies</a
                 >
               </li>
+              <li>
+                <a class="function" href="#SecureCookiesMiddleware.set_header"
+                  >set_header</a
+                >
+              </li>
+              <li>
+                <a class="function" href="#SecureCookiesMiddleware.decrypt"
+                  >decrypt</a
+                >
+              </li>
+              <li>
+                <a class="function" href="#SecureCookiesMiddleware.encrypt"
+                  >encrypt</a
+                >
+              </li>
               <li>
                 <a class="function" href="#SecureCookiesMiddleware.dispatch"
                   >dispatch</a
@@ -1307,12 +1334,14 @@ <h2>API Documentation</h2>
     </nav>
     <main class="pdoc">
       <section class="module-info">
+        <h1 class="modulename">securecookies</h1>
+
         <div class="docstring">
           <h1 id="starlette-securecookies">starlette-securecookies</h1>
 
           <p>
             <img
-              src="https://img.shields.io/github/actions/workflow/status/thearchitector/starlette-securecookies/CI.yaml?label=tests&amp;style=flat-square"
+              src="https://img.shields.io/github/actions/workflow/status/thearchitector/starlette-securecookies/CI.yaml?label=tests&style=flat-square"
               alt="GitHub Workflow Status"
             />
             <img
@@ -1343,12 +1372,13 @@ <h1 id="starlette-securecookies">starlette-securecookies</h1>
 
           <h2 id="how-it-works">How it works?</h2>
 
-          <pre><code>sequenceDiagram
-    Browser-&gt;&gt;+Middleware: Encrypted cookies
-    Middleware-&gt;&gt;+Application: Filtered / Decrypted cookies
+          <pre class="mermaid-pre"><div class="mermaid">sequenceDiagram
+    Browser-&gt;&gt;+Middleware: Encrypted 'Cookie' header
+    Middleware-&gt;&gt;+Application: Decrypted cookies
     Application-&gt;&gt;-Middleware: Plaintext cookies
-    Middleware-&gt;&gt;-Browser: Encrypted 'Set-Cookie' headers
-</code></pre>
+    Middleware-&gt;&gt;-Browser: Encrypted 'Set-Cookie' header
+    Note over Application: *The Application may be your service&lt;br /&gt;or any additional middleware.
+</div></pre>
 
           <p>For any incoming cookies:</p>
 
@@ -1386,11 +1416,17 @@ <h2 id="how-it-works">How it works?</h2>
 
           <p>For any outgoing cookies:</p>
 
-          <ol>
+          <ol start="7">
             <li>
               Your application sets cookies with
               <code>response.set_cookie</code> as usual.
             </li>
+            <li>
+              Other middleware run and add additional cookies, like
+              <a href="https://www.starlette.io/middleware/#sessionmiddleware"
+                >SessionMiddleware</a
+              >.
+            </li>
             <li>
               All responses returned by your application are intercepted by
               <code
@@ -1408,12 +1444,13 @@ <h2 id="how-it-works">How it works?</h2>
                 ><a href="#SecureCookiesMiddleware"
                   >SecureCookiesMiddleware</a
                 ></code
-              >.
+              >
+              if set.
             </li>
             <li>
               The cookies in the response are replaced by the re-encrypted
-              cookies, and the response is propagated to Starlette to return to
-              the client's browser.
+              cookies, and the response is eventually propagated to the client's
+              browser.
             </li>
           </ol>
 
@@ -1430,14 +1467,9 @@ <h2 id="usage">Usage</h2>
 
           <p>
             This is a Starlette-based middleware, so it can be used in any
-            Starlette application or Starlette-based application (like
+            Starlette application or Starlette-based framework (like
             <a href="https://fastapi.tiangolo.com/advanced/middleware/"
               >FastAPI</a
-            >
-            or
-            <a
-              href="https://starlite-api.github.io/starlite/usage/7-middleware/"
-              >Starlite</a
             >).
           </p>
 
@@ -1451,7 +1483,8 @@ <h2 id="usage">Usage</h2>
 
 <span class="n">middleware</span> <span class="o">=</span> <span class="p">[</span>
     <span class="n">Middleware</span><span class="p">(</span>
-        <span class="n">SecureCookiesMiddleware</span><span class="p">,</span> <span class="n">secrets</span><span class="o">=</span><span class="p">[</span><span class="s2">&quot;SUPER SECRET SECRET&quot;</span><span class="p">]</span>
+        <span class="n">SecureCookiesMiddleware</span><span class="p">,</span> <span class="n">secrets</span><span class="o">=</span><span class="p">[</span><span class="s2">&quot;SUPER SECRET SECRET&quot;</span><span class="p">],</span>
+        <span class="c1"># your other middleware</span>
     <span class="p">)</span>
 <span class="p">]</span>
 
@@ -1459,6 +1492,55 @@ <h2 id="usage">Usage</h2>
 </code></pre>
           </div>
 
+          <p>
+            Note that if you're using another middleware that injects cookies
+            into the response (such as
+            <a href="https://www.starlette.io/middleware/#sessionmiddleware"
+              >SessionMiddleware</a
+            >), you have to make sure
+            <code
+              ><a href="#SecureCookiesMiddleware"
+                >SecureCookiesMiddleware</a
+              ></code
+            >
+            executes _after_ it so the cookie is present at encryption-time.
+            Counter intuitively, in practice this means ensuring
+            <code
+              ><a href="#SecureCookiesMiddleware"
+                >SecureCookiesMiddleware</a
+              ></code
+            >
+            is _first_ in the list of middleware.
+          </p>
+
+          <h3 id="extras">Extras</h3>
+
+          <p>
+            <code>starlette-securecookies</code> provides some extras that
+            introduce or patch secure cookie functionality into existing tools.
+            They all reside in the
+            <code
+              ><a href="securecookies/extras.html"
+                >securecookies.extras</a
+              ></code
+            >
+            module. Currently there is only one, but more are welcome by
+            recommendation or Pull Request!
+          </p>
+
+          <ul>
+            <li>
+              <strong><code>csrf.SecureCSRFMiddleware</code></strong
+              >: Adds compatibility to the CSRF middleware provided by
+              <a href="https://github.com/frankie567/starlette-csrf"
+                >starlette_csrf</a
+              >. To use it, simply add it to your list of middleware (keep in
+              mind the ordering). If you don't want to specify
+              <code>starlette_csrf</code> as a direct dependency, you can also
+              install it through the <code>[csrf]</code> package extra.
+            </li>
+          </ul>
+
           <h2 id="license">License</h2>
 
           <p>
@@ -1474,12 +1556,28 @@ <h2 id="license">License</h2>
           </p>
         </div>
 
-        <script type="module">
-          import mermaid from "https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs";
-          const diagram = document.getElementsByTagName("code")[0];
-          mermaid.initialize({ startOnLoad: false, theme: "forest" });
-          await mermaid.run({ nodes: [diagram] });
-        </script>
+        <input
+          id="mod-securecookies-view-source"
+          class="view-source-toggle-state"
+          type="checkbox"
+          aria-hidden="true"
+          tabindex="-1"
+        />
+
+        <label class="view-source-button" for="mod-securecookies-view-source"
+          ><span>View Source</span></label
+        >
+
+        <div class="pdoc-code codehilite">
+          <pre><span></span><span id="L-1"><a href="#L-1"><span class="linenos">1</span></a><span class="sd">&quot;&quot;&quot;.. include:: ../README.md&quot;&quot;&quot;</span>
+</span><span id="L-2"><a href="#L-2"><span class="linenos">2</span></a>
+</span><span id="L-3"><a href="#L-3"><span class="linenos">3</span></a><span class="kn">from</span> <span class="nn">securecookies</span> <span class="kn">import</span> <span class="n">extras</span>
+</span><span id="L-4"><a href="#L-4"><span class="linenos">4</span></a>
+</span><span id="L-5"><a href="#L-5"><span class="linenos">5</span></a><span class="kn">from</span> <span class="nn">.middleware</span> <span class="kn">import</span> <span class="n">BadArgumentError</span><span class="p">,</span> <span class="n">SecureCookiesMiddleware</span>
+</span><span id="L-6"><a href="#L-6"><span class="linenos">6</span></a>
+</span><span id="L-7"><a href="#L-7"><span class="linenos">7</span></a><span class="n">__all__</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;SecureCookiesMiddleware&quot;</span><span class="p">,</span> <span class="s2">&quot;BadArgumentError&quot;</span><span class="p">,</span> <span class="s2">&quot;extras&quot;</span><span class="p">]</span>
+</span></pre>
+        </div>
       </section>
       <section id="SecureCookiesMiddleware">
         <input
@@ -1504,138 +1602,147 @@ <h2 id="license">License</h2>
         </div>
         <a class="headerlink" href="#SecureCookiesMiddleware"></a>
         <div class="pdoc-code codehilite">
-          <pre><span></span><span id="SecureCookiesMiddleware-19"><a href="#SecureCookiesMiddleware-19"><span class="linenos"> 19</span></a><span class="k">class</span> <span class="nc">SecureCookiesMiddleware</span><span class="p">(</span><span class="n">BaseHTTPMiddleware</span><span class="p">):</span>
-</span><span id="SecureCookiesMiddleware-20"><a href="#SecureCookiesMiddleware-20"><span class="linenos"> 20</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;</span>
-</span><span id="SecureCookiesMiddleware-21"><a href="#SecureCookiesMiddleware-21"><span class="linenos"> 21</span></a><span class="sd">    Provides automatic secure cookie support through symmetric Fernet encryption. As per</span>
-</span><span id="SecureCookiesMiddleware-22"><a href="#SecureCookiesMiddleware-22"><span class="linenos"> 22</span></a><span class="sd">    the `cryptography` docs, security is achieved through:</span>
-</span><span id="SecureCookiesMiddleware-23"><a href="#SecureCookiesMiddleware-23"><span class="linenos"> 23</span></a>
-</span><span id="SecureCookiesMiddleware-24"><a href="#SecureCookiesMiddleware-24"><span class="linenos"> 24</span></a><span class="sd">    - 128-bit key AES in CBC mode using PKCS7 padding for encryption</span>
-</span><span id="SecureCookiesMiddleware-25"><a href="#SecureCookiesMiddleware-25"><span class="linenos"> 25</span></a><span class="sd">    - HMAC using SHA256 for authentication.</span>
-</span><span id="SecureCookiesMiddleware-26"><a href="#SecureCookiesMiddleware-26"><span class="linenos"> 26</span></a><span class="sd">    &quot;&quot;&quot;</span>
-</span><span id="SecureCookiesMiddleware-27"><a href="#SecureCookiesMiddleware-27"><span class="linenos"> 27</span></a>
-</span><span id="SecureCookiesMiddleware-28"><a href="#SecureCookiesMiddleware-28"><span class="linenos"> 28</span></a>    <span class="n">secrets</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span>
-</span><span id="SecureCookiesMiddleware-29"><a href="#SecureCookiesMiddleware-29"><span class="linenos"> 29</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;</span>
-</span><span id="SecureCookiesMiddleware-30"><a href="#SecureCookiesMiddleware-30"><span class="linenos"> 30</span></a><span class="sd">    A list of secrets to use when encrypting and decrypting secure cookies. Supplying</span>
-</span><span id="SecureCookiesMiddleware-31"><a href="#SecureCookiesMiddleware-31"><span class="linenos"> 31</span></a><span class="sd">    multiple secrets enables the use of key rotation, whereby the first key is used for</span>
-</span><span id="SecureCookiesMiddleware-32"><a href="#SecureCookiesMiddleware-32"><span class="linenos"> 32</span></a><span class="sd">    all encryption, including to re-encrypt cookies previously encrypted with any of</span>
-</span><span id="SecureCookiesMiddleware-33"><a href="#SecureCookiesMiddleware-33"><span class="linenos"> 33</span></a><span class="sd">    the other list entries.</span>
-</span><span id="SecureCookiesMiddleware-34"><a href="#SecureCookiesMiddleware-34"><span class="linenos"> 34</span></a><span class="sd">    &quot;&quot;&quot;</span>
-</span><span id="SecureCookiesMiddleware-35"><a href="#SecureCookiesMiddleware-35"><span class="linenos"> 35</span></a>
-</span><span id="SecureCookiesMiddleware-36"><a href="#SecureCookiesMiddleware-36"><span class="linenos"> 36</span></a>    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span>
-</span><span id="SecureCookiesMiddleware-37"><a href="#SecureCookiesMiddleware-37"><span class="linenos"> 37</span></a>        <span class="bp">self</span><span class="p">,</span>
-</span><span id="SecureCookiesMiddleware-38"><a href="#SecureCookiesMiddleware-38"><span class="linenos"> 38</span></a>        <span class="n">app</span><span class="p">:</span> <span class="n">ASGIApp</span><span class="p">,</span>
-</span><span id="SecureCookiesMiddleware-39"><a href="#SecureCookiesMiddleware-39"><span class="linenos"> 39</span></a>        <span class="n">secrets</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">],</span>
-</span><span id="SecureCookiesMiddleware-40"><a href="#SecureCookiesMiddleware-40"><span class="linenos"> 40</span></a>        <span class="n">discard_invalid</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">True</span><span class="p">,</span>
-</span><span id="SecureCookiesMiddleware-41"><a href="#SecureCookiesMiddleware-41"><span class="linenos"> 41</span></a>        <span class="n">cookie_path</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
-</span><span id="SecureCookiesMiddleware-42"><a href="#SecureCookiesMiddleware-42"><span class="linenos"> 42</span></a>        <span class="n">cookie_domain</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
-</span><span id="SecureCookiesMiddleware-43"><a href="#SecureCookiesMiddleware-43"><span class="linenos"> 43</span></a>        <span class="n">cookie_secure</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">bool</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
-</span><span id="SecureCookiesMiddleware-44"><a href="#SecureCookiesMiddleware-44"><span class="linenos"> 44</span></a>        <span class="n">cookie_httponly</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">bool</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
-</span><span id="SecureCookiesMiddleware-45"><a href="#SecureCookiesMiddleware-45"><span class="linenos"> 45</span></a>        <span class="n">cookie_samesite</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
-</span><span id="SecureCookiesMiddleware-46"><a href="#SecureCookiesMiddleware-46"><span class="linenos"> 46</span></a>        <span class="n">excluded_cookies</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
-</span><span id="SecureCookiesMiddleware-47"><a href="#SecureCookiesMiddleware-47"><span class="linenos"> 47</span></a>        <span class="n">included_cookies</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
-</span><span id="SecureCookiesMiddleware-48"><a href="#SecureCookiesMiddleware-48"><span class="linenos"> 48</span></a>    <span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
-</span><span id="SecureCookiesMiddleware-49"><a href="#SecureCookiesMiddleware-49"><span class="linenos"> 49</span></a>        <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="n">app</span><span class="p">)</span>
-</span><span id="SecureCookiesMiddleware-50"><a href="#SecureCookiesMiddleware-50"><span class="linenos"> 50</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">mfernet</span> <span class="o">=</span> <span class="n">MultiFernet</span><span class="p">(</span><span class="n">Fernet</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="k">for</span> <span class="n">s</span> <span class="ow">in</span> <span class="n">secrets</span><span class="p">)</span>
-</span><span id="SecureCookiesMiddleware-51"><a href="#SecureCookiesMiddleware-51"><span class="linenos"> 51</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">discard_invalid</span> <span class="o">=</span> <span class="n">discard_invalid</span>
-</span><span id="SecureCookiesMiddleware-52"><a href="#SecureCookiesMiddleware-52"><span class="linenos"> 52</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot; Discard any invalid / unencrypted cookies present in the request.&quot;&quot;&quot;</span>
-</span><span id="SecureCookiesMiddleware-53"><a href="#SecureCookiesMiddleware-53"><span class="linenos"> 53</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">cookie_path</span> <span class="o">=</span> <span class="n">cookie_path</span>
-</span><span id="SecureCookiesMiddleware-54"><a href="#SecureCookiesMiddleware-54"><span class="linenos"> 54</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot; The Path field value to override on every cookie.&quot;&quot;&quot;</span>
-</span><span id="SecureCookiesMiddleware-55"><a href="#SecureCookiesMiddleware-55"><span class="linenos"> 55</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">cookie_domain</span> <span class="o">=</span> <span class="n">cookie_domain</span>
-</span><span id="SecureCookiesMiddleware-56"><a href="#SecureCookiesMiddleware-56"><span class="linenos"> 56</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot; The Domain field value to override on every cookie.&quot;&quot;&quot;</span>
-</span><span id="SecureCookiesMiddleware-57"><a href="#SecureCookiesMiddleware-57"><span class="linenos"> 57</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">cookie_secure</span> <span class="o">=</span> <span class="n">cookie_secure</span>
-</span><span id="SecureCookiesMiddleware-58"><a href="#SecureCookiesMiddleware-58"><span class="linenos"> 58</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot; The Secure field value to override on every cookie.&quot;&quot;&quot;</span>
-</span><span id="SecureCookiesMiddleware-59"><a href="#SecureCookiesMiddleware-59"><span class="linenos"> 59</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">cookie_httponly</span> <span class="o">=</span> <span class="n">cookie_httponly</span>
-</span><span id="SecureCookiesMiddleware-60"><a href="#SecureCookiesMiddleware-60"><span class="linenos"> 60</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot; The HttpOnly field value to override on every cookie.&quot;&quot;&quot;</span>
-</span><span id="SecureCookiesMiddleware-61"><a href="#SecureCookiesMiddleware-61"><span class="linenos"> 61</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">cookie_samesite</span> <span class="o">=</span> <span class="n">cookie_samesite</span>
-</span><span id="SecureCookiesMiddleware-62"><a href="#SecureCookiesMiddleware-62"><span class="linenos"> 62</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot; The SameStime field value to override on every cookie.&quot;&quot;&quot;</span>
-</span><span id="SecureCookiesMiddleware-63"><a href="#SecureCookiesMiddleware-63"><span class="linenos"> 63</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">excluded_cookies</span> <span class="o">=</span> <span class="n">excluded_cookies</span>
-</span><span id="SecureCookiesMiddleware-64"><a href="#SecureCookiesMiddleware-64"><span class="linenos"> 64</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;</span>
-</span><span id="SecureCookiesMiddleware-65"><a href="#SecureCookiesMiddleware-65"><span class="linenos"> 65</span></a><span class="sd">        The list of cookies to ignore when decrypting and encrypting in</span>
-</span><span id="SecureCookiesMiddleware-66"><a href="#SecureCookiesMiddleware-66"><span class="linenos"> 66</span></a><span class="sd">        the request --&gt; response cycle. This option is mutually exclusive with</span>
-</span><span id="SecureCookiesMiddleware-67"><a href="#SecureCookiesMiddleware-67"><span class="linenos"> 67</span></a><span class="sd">        `included_cookies`.</span>
-</span><span id="SecureCookiesMiddleware-68"><a href="#SecureCookiesMiddleware-68"><span class="linenos"> 68</span></a><span class="sd">        &quot;&quot;&quot;</span>
-</span><span id="SecureCookiesMiddleware-69"><a href="#SecureCookiesMiddleware-69"><span class="linenos"> 69</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">included_cookies</span> <span class="o">=</span> <span class="n">included_cookies</span>
-</span><span id="SecureCookiesMiddleware-70"><a href="#SecureCookiesMiddleware-70"><span class="linenos"> 70</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;</span>
-</span><span id="SecureCookiesMiddleware-71"><a href="#SecureCookiesMiddleware-71"><span class="linenos"> 71</span></a><span class="sd">        The list of cookies to decrypt and encrypt in the request --&gt; response cycle.</span>
-</span><span id="SecureCookiesMiddleware-72"><a href="#SecureCookiesMiddleware-72"><span class="linenos"> 72</span></a><span class="sd">        This option is mutually exclusive with `excluded_cookies`.</span>
-</span><span id="SecureCookiesMiddleware-73"><a href="#SecureCookiesMiddleware-73"><span class="linenos"> 73</span></a><span class="sd">        &quot;&quot;&quot;</span>
-</span><span id="SecureCookiesMiddleware-74"><a href="#SecureCookiesMiddleware-74"><span class="linenos"> 74</span></a>
-</span><span id="SecureCookiesMiddleware-75"><a href="#SecureCookiesMiddleware-75"><span class="linenos"> 75</span></a>        <span class="k">if</span> <span class="n">excluded_cookies</span> <span class="ow">and</span> <span class="n">included_cookies</span><span class="p">:</span>
-</span><span id="SecureCookiesMiddleware-76"><a href="#SecureCookiesMiddleware-76"><span class="linenos"> 76</span></a>            <span class="k">raise</span> <span class="n">BadArgumentError</span><span class="p">(</span>
-</span><span id="SecureCookiesMiddleware-77"><a href="#SecureCookiesMiddleware-77"><span class="linenos"> 77</span></a>                <span class="s2">&quot;It doesn&#39;t make sense to specify both excluded and included cookies.&quot;</span>
-</span><span id="SecureCookiesMiddleware-78"><a href="#SecureCookiesMiddleware-78"><span class="linenos"> 78</span></a>                <span class="s2">&quot; Supply with `excluded_cookies` or `included_cookies` to restrict&quot;</span>
-</span><span id="SecureCookiesMiddleware-79"><a href="#SecureCookiesMiddleware-79"><span class="linenos"> 79</span></a>                <span class="s2">&quot; which cookies should be secure.&quot;</span>
-</span><span id="SecureCookiesMiddleware-80"><a href="#SecureCookiesMiddleware-80"><span class="linenos"> 80</span></a>            <span class="p">)</span>
-</span><span id="SecureCookiesMiddleware-81"><a href="#SecureCookiesMiddleware-81"><span class="linenos"> 81</span></a>
-</span><span id="SecureCookiesMiddleware-82"><a href="#SecureCookiesMiddleware-82"><span class="linenos"> 82</span></a>        <span class="k">if</span> <span class="n">cookie_samesite</span> <span class="ow">and</span> <span class="n">cookie_samesite</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">[</span><span class="s2">&quot;strict&quot;</span><span class="p">,</span> <span class="s2">&quot;lax&quot;</span><span class="p">,</span> <span class="s2">&quot;none&quot;</span><span class="p">]:</span>
-</span><span id="SecureCookiesMiddleware-83"><a href="#SecureCookiesMiddleware-83"><span class="linenos"> 83</span></a>            <span class="k">raise</span> <span class="n">BadArgumentError</span><span class="p">(</span>
-</span><span id="SecureCookiesMiddleware-84"><a href="#SecureCookiesMiddleware-84"><span class="linenos"> 84</span></a>                <span class="s2">&quot;SameSite attribute must be either &#39;strict&#39;, &#39;lax&#39; or &#39;none&#39;&quot;</span>
-</span><span id="SecureCookiesMiddleware-85"><a href="#SecureCookiesMiddleware-85"><span class="linenos"> 85</span></a>            <span class="p">)</span>
-</span><span id="SecureCookiesMiddleware-86"><a href="#SecureCookiesMiddleware-86"><span class="linenos"> 86</span></a>
-</span><span id="SecureCookiesMiddleware-87"><a href="#SecureCookiesMiddleware-87"><span class="linenos"> 87</span></a>    <span class="k">async</span> <span class="k">def</span> <span class="nf">dispatch</span><span class="p">(</span>
-</span><span id="SecureCookiesMiddleware-88"><a href="#SecureCookiesMiddleware-88"><span class="linenos"> 88</span></a>        <span class="bp">self</span><span class="p">,</span> <span class="n">request</span><span class="p">:</span> <span class="n">Request</span><span class="p">,</span> <span class="n">call_next</span><span class="p">:</span> <span class="n">RequestResponseEndpoint</span>
-</span><span id="SecureCookiesMiddleware-89"><a href="#SecureCookiesMiddleware-89"><span class="linenos"> 89</span></a>    <span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Response</span><span class="p">:</span>
-</span><span id="SecureCookiesMiddleware-90"><a href="#SecureCookiesMiddleware-90"><span class="linenos"> 90</span></a>        <span class="c1"># request cookies are only passed along and mutable within the asgi scope</span>
-</span><span id="SecureCookiesMiddleware-91"><a href="#SecureCookiesMiddleware-91"><span class="linenos"> 91</span></a>        <span class="n">headers</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">scope</span><span class="p">[</span><span class="s2">&quot;headers&quot;</span><span class="p">]</span>
-</span><span id="SecureCookiesMiddleware-92"><a href="#SecureCookiesMiddleware-92"><span class="linenos"> 92</span></a>        <span class="n">raw_cookies</span> <span class="o">=</span> <span class="p">[</span><span class="n">h</span> <span class="k">for</span> <span class="n">h</span> <span class="ow">in</span> <span class="n">headers</span> <span class="k">if</span> <span class="n">h</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="sa">b</span><span class="s2">&quot;cookie&quot;</span><span class="p">]</span>
-</span><span id="SecureCookiesMiddleware-93"><a href="#SecureCookiesMiddleware-93"><span class="linenos"> 93</span></a>        <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">raw_cookies</span><span class="p">):</span>
-</span><span id="SecureCookiesMiddleware-94"><a href="#SecureCookiesMiddleware-94"><span class="linenos"> 94</span></a>            <span class="c1"># if encrypted cookies are present, remove and parse them</span>
-</span><span id="SecureCookiesMiddleware-95"><a href="#SecureCookiesMiddleware-95"><span class="linenos"> 95</span></a>            <span class="n">headers</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">raw_cookies</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
-</span><span id="SecureCookiesMiddleware-96"><a href="#SecureCookiesMiddleware-96"><span class="linenos"> 96</span></a>            <span class="n">cookies</span><span class="p">:</span> <span class="n">SimpleCookie</span><span class="p">[</span><span class="n">Any</span><span class="p">]</span> <span class="o">=</span> <span class="n">SimpleCookie</span><span class="p">(</span><span class="n">raw_cookies</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">decode</span><span class="p">())</span>
-</span><span id="SecureCookiesMiddleware-97"><a href="#SecureCookiesMiddleware-97"><span class="linenos"> 97</span></a>
-</span><span id="SecureCookiesMiddleware-98"><a href="#SecureCookiesMiddleware-98"><span class="linenos"> 98</span></a>            <span class="k">for</span> <span class="n">cookie</span><span class="p">,</span> <span class="n">morsel</span> <span class="ow">in</span> <span class="nb">list</span><span class="p">(</span><span class="n">cookies</span><span class="o">.</span><span class="n">items</span><span class="p">()):</span>
-</span><span id="SecureCookiesMiddleware-99"><a href="#SecureCookiesMiddleware-99"><span class="linenos"> 99</span></a>                <span class="c1"># if the cookie is included or not excluded</span>
-</span><span id="SecureCookiesMiddleware-100"><a href="#SecureCookiesMiddleware-100"><span class="linenos">100</span></a>                <span class="k">if</span> <span class="p">(</span>
-</span><span id="SecureCookiesMiddleware-101"><a href="#SecureCookiesMiddleware-101"><span class="linenos">101</span></a>                    <span class="p">(</span><span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">included_cookies</span> <span class="ow">and</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">excluded_cookies</span><span class="p">)</span>
-</span><span id="SecureCookiesMiddleware-102"><a href="#SecureCookiesMiddleware-102"><span class="linenos">102</span></a>                    <span class="ow">or</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">included_cookies</span> <span class="ow">and</span> <span class="n">cookie</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">included_cookies</span><span class="p">)</span>
-</span><span id="SecureCookiesMiddleware-103"><a href="#SecureCookiesMiddleware-103"><span class="linenos">103</span></a>                    <span class="ow">or</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">excluded_cookies</span> <span class="ow">and</span> <span class="n">cookie</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">excluded_cookies</span><span class="p">)</span>
-</span><span id="SecureCookiesMiddleware-104"><a href="#SecureCookiesMiddleware-104"><span class="linenos">104</span></a>                <span class="p">):</span>
-</span><span id="SecureCookiesMiddleware-105"><a href="#SecureCookiesMiddleware-105"><span class="linenos">105</span></a>                    <span class="k">try</span><span class="p">:</span>
-</span><span id="SecureCookiesMiddleware-106"><a href="#SecureCookiesMiddleware-106"><span class="linenos">106</span></a>                        <span class="c1"># try to decrypt the token. if you can, then it&#39;s already</span>
-</span><span id="SecureCookiesMiddleware-107"><a href="#SecureCookiesMiddleware-107"><span class="linenos">107</span></a>                        <span class="c1"># encrypted and can be passed along</span>
-</span><span id="SecureCookiesMiddleware-108"><a href="#SecureCookiesMiddleware-108"><span class="linenos">108</span></a>                        <span class="n">cookies</span><span class="p">[</span><span class="n">cookie</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">mfernet</span><span class="o">.</span><span class="n">decrypt</span><span class="p">(</span>
-</span><span id="SecureCookiesMiddleware-109"><a href="#SecureCookiesMiddleware-109"><span class="linenos">109</span></a>                            <span class="n">morsel</span><span class="o">.</span><span class="n">value</span><span class="o">.</span><span class="n">encode</span><span class="p">()</span>
-</span><span id="SecureCookiesMiddleware-110"><a href="#SecureCookiesMiddleware-110"><span class="linenos">110</span></a>                        <span class="p">)</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span>
-</span><span id="SecureCookiesMiddleware-111"><a href="#SecureCookiesMiddleware-111"><span class="linenos">111</span></a>                    <span class="k">except</span> <span class="n">InvalidToken</span><span class="p">:</span>
-</span><span id="SecureCookiesMiddleware-112"><a href="#SecureCookiesMiddleware-112"><span class="linenos">112</span></a>                        <span class="c1"># delete invalid or unencrypted cookies if enabled</span>
-</span><span id="SecureCookiesMiddleware-113"><a href="#SecureCookiesMiddleware-113"><span class="linenos">113</span></a>                        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">discard_invalid</span><span class="p">:</span>
-</span><span id="SecureCookiesMiddleware-114"><a href="#SecureCookiesMiddleware-114"><span class="linenos">114</span></a>                            <span class="k">del</span> <span class="n">cookies</span><span class="p">[</span><span class="n">cookie</span><span class="p">]</span>
-</span><span id="SecureCookiesMiddleware-115"><a href="#SecureCookiesMiddleware-115"><span class="linenos">115</span></a>
-</span><span id="SecureCookiesMiddleware-116"><a href="#SecureCookiesMiddleware-116"><span class="linenos">116</span></a>            <span class="c1"># serialize and append the decrypted cookies to the asgi scope headers</span>
-</span><span id="SecureCookiesMiddleware-117"><a href="#SecureCookiesMiddleware-117"><span class="linenos">117</span></a>            <span class="n">new_cookie</span> <span class="o">=</span> <span class="p">(</span>
-</span><span id="SecureCookiesMiddleware-118"><a href="#SecureCookiesMiddleware-118"><span class="linenos">118</span></a>                <span class="sa">b</span><span class="s2">&quot;cookie&quot;</span><span class="p">,</span>
-</span><span id="SecureCookiesMiddleware-119"><a href="#SecureCookiesMiddleware-119"><span class="linenos">119</span></a>                <span class="n">cookies</span><span class="o">.</span><span class="n">output</span><span class="p">(</span><span class="n">header</span><span class="o">=</span><span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="n">sep</span><span class="o">=</span><span class="s2">&quot;;&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span><span class="o">.</span><span class="n">encode</span><span class="p">(),</span>
-</span><span id="SecureCookiesMiddleware-120"><a href="#SecureCookiesMiddleware-120"><span class="linenos">120</span></a>            <span class="p">)</span>
-</span><span id="SecureCookiesMiddleware-121"><a href="#SecureCookiesMiddleware-121"><span class="linenos">121</span></a>            <span class="n">headers</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">new_cookie</span><span class="p">)</span>
-</span><span id="SecureCookiesMiddleware-122"><a href="#SecureCookiesMiddleware-122"><span class="linenos">122</span></a>
-</span><span id="SecureCookiesMiddleware-123"><a href="#SecureCookiesMiddleware-123"><span class="linenos">123</span></a>        <span class="c1"># propagate the modified request</span>
-</span><span id="SecureCookiesMiddleware-124"><a href="#SecureCookiesMiddleware-124"><span class="linenos">124</span></a>        <span class="n">response</span><span class="p">:</span> <span class="n">Response</span> <span class="o">=</span> <span class="k">await</span> <span class="n">call_next</span><span class="p">(</span><span class="n">request</span><span class="p">)</span>
-</span><span id="SecureCookiesMiddleware-125"><a href="#SecureCookiesMiddleware-125"><span class="linenos">125</span></a>
-</span><span id="SecureCookiesMiddleware-126"><a href="#SecureCookiesMiddleware-126"><span class="linenos">126</span></a>        <span class="c1"># for every cookie in the response</span>
-</span><span id="SecureCookiesMiddleware-127"><a href="#SecureCookiesMiddleware-127"><span class="linenos">127</span></a>        <span class="k">for</span> <span class="n">raw_cookie</span> <span class="ow">in</span> <span class="n">response</span><span class="o">.</span><span class="n">headers</span><span class="o">.</span><span class="n">getlist</span><span class="p">(</span><span class="s2">&quot;set-cookie&quot;</span><span class="p">):</span>
-</span><span id="SecureCookiesMiddleware-128"><a href="#SecureCookiesMiddleware-128"><span class="linenos">128</span></a>            <span class="c1"># decode it</span>
-</span><span id="SecureCookiesMiddleware-129"><a href="#SecureCookiesMiddleware-129"><span class="linenos">129</span></a>            <span class="n">ncookie</span><span class="p">:</span> <span class="n">SimpleCookie</span><span class="p">[</span><span class="n">Any</span><span class="p">]</span> <span class="o">=</span> <span class="n">SimpleCookie</span><span class="p">(</span><span class="n">raw_cookie</span><span class="p">)</span>
-</span><span id="SecureCookiesMiddleware-130"><a href="#SecureCookiesMiddleware-130"><span class="linenos">130</span></a>            <span class="n">key</span> <span class="o">=</span> <span class="p">[</span><span class="o">*</span><span class="n">ncookie</span><span class="o">.</span><span class="n">keys</span><span class="p">()][</span><span class="mi">0</span><span class="p">]</span>
-</span><span id="SecureCookiesMiddleware-131"><a href="#SecureCookiesMiddleware-131"><span class="linenos">131</span></a>
-</span><span id="SecureCookiesMiddleware-132"><a href="#SecureCookiesMiddleware-132"><span class="linenos">132</span></a>            <span class="c1"># if the cookie is included or not excluded</span>
-</span><span id="SecureCookiesMiddleware-133"><a href="#SecureCookiesMiddleware-133"><span class="linenos">133</span></a>            <span class="k">if</span> <span class="p">(</span>
-</span><span id="SecureCookiesMiddleware-134"><a href="#SecureCookiesMiddleware-134"><span class="linenos">134</span></a>                <span class="p">(</span><span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">included_cookies</span> <span class="ow">and</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">excluded_cookies</span><span class="p">)</span>
-</span><span id="SecureCookiesMiddleware-135"><a href="#SecureCookiesMiddleware-135"><span class="linenos">135</span></a>                <span class="ow">or</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">included_cookies</span> <span class="ow">and</span> <span class="n">key</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">included_cookies</span><span class="p">)</span>
-</span><span id="SecureCookiesMiddleware-136"><a href="#SecureCookiesMiddleware-136"><span class="linenos">136</span></a>                <span class="ow">or</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">excluded_cookies</span> <span class="ow">and</span> <span class="n">key</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">excluded_cookies</span><span class="p">)</span>
-</span><span id="SecureCookiesMiddleware-137"><a href="#SecureCookiesMiddleware-137"><span class="linenos">137</span></a>            <span class="p">):</span>
-</span><span id="SecureCookiesMiddleware-138"><a href="#SecureCookiesMiddleware-138"><span class="linenos">138</span></a>                <span class="c1"># create a new encrypted cookie with the desired attributes</span>
-</span><span id="SecureCookiesMiddleware-139"><a href="#SecureCookiesMiddleware-139"><span class="linenos">139</span></a>                <span class="n">response</span><span class="o">.</span><span class="n">set_cookie</span><span class="p">(</span>
-</span><span id="SecureCookiesMiddleware-140"><a href="#SecureCookiesMiddleware-140"><span class="linenos">140</span></a>                    <span class="n">key</span><span class="p">,</span>
-</span><span id="SecureCookiesMiddleware-141"><a href="#SecureCookiesMiddleware-141"><span class="linenos">141</span></a>                    <span class="n">value</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">mfernet</span><span class="o">.</span><span class="n">encrypt</span><span class="p">(</span><span class="n">ncookie</span><span class="p">[</span><span class="n">key</span><span class="p">]</span><span class="o">.</span><span class="n">value</span><span class="o">.</span><span class="n">encode</span><span class="p">())</span><span class="o">.</span><span class="n">decode</span><span class="p">(),</span>
-</span><span id="SecureCookiesMiddleware-142"><a href="#SecureCookiesMiddleware-142"><span class="linenos">142</span></a>                    <span class="n">path</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">cookie_path</span> <span class="ow">or</span> <span class="n">ncookie</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="s2">&quot;path&quot;</span><span class="p">],</span>
-</span><span id="SecureCookiesMiddleware-143"><a href="#SecureCookiesMiddleware-143"><span class="linenos">143</span></a>                    <span class="n">domain</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">cookie_domain</span> <span class="ow">or</span> <span class="n">ncookie</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="s2">&quot;domain&quot;</span><span class="p">],</span>
-</span><span id="SecureCookiesMiddleware-144"><a href="#SecureCookiesMiddleware-144"><span class="linenos">144</span></a>                    <span class="n">secure</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">cookie_secure</span> <span class="ow">or</span> <span class="n">ncookie</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="s2">&quot;secure&quot;</span><span class="p">],</span>
-</span><span id="SecureCookiesMiddleware-145"><a href="#SecureCookiesMiddleware-145"><span class="linenos">145</span></a>                    <span class="n">httponly</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">cookie_httponly</span> <span class="ow">or</span> <span class="n">ncookie</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="s2">&quot;httponly&quot;</span><span class="p">],</span>
-</span><span id="SecureCookiesMiddleware-146"><a href="#SecureCookiesMiddleware-146"><span class="linenos">146</span></a>                    <span class="n">samesite</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">cookie_samesite</span>
-</span><span id="SecureCookiesMiddleware-147"><a href="#SecureCookiesMiddleware-147"><span class="linenos">147</span></a>                    <span class="ow">or</span> <span class="n">ncookie</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="s2">&quot;samesite&quot;</span><span class="p">],</span>  <span class="c1"># type:ignore [arg-type]</span>
-</span><span id="SecureCookiesMiddleware-148"><a href="#SecureCookiesMiddleware-148"><span class="linenos">148</span></a>                <span class="p">)</span>
-</span><span id="SecureCookiesMiddleware-149"><a href="#SecureCookiesMiddleware-149"><span class="linenos">149</span></a>
-</span><span id="SecureCookiesMiddleware-150"><a href="#SecureCookiesMiddleware-150"><span class="linenos">150</span></a>        <span class="k">return</span> <span class="n">response</span>
+          <pre><span></span><span id="SecureCookiesMiddleware-20"><a href="#SecureCookiesMiddleware-20"><span class="linenos"> 20</span></a><span class="k">class</span> <span class="nc">SecureCookiesMiddleware</span><span class="p">(</span><span class="n">BaseHTTPMiddleware</span><span class="p">):</span>
+</span><span id="SecureCookiesMiddleware-21"><a href="#SecureCookiesMiddleware-21"><span class="linenos"> 21</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;</span>
+</span><span id="SecureCookiesMiddleware-22"><a href="#SecureCookiesMiddleware-22"><span class="linenos"> 22</span></a><span class="sd">    Provides automatic secure cookie support through symmetric Fernet encryption. As per</span>
+</span><span id="SecureCookiesMiddleware-23"><a href="#SecureCookiesMiddleware-23"><span class="linenos"> 23</span></a><span class="sd">    the `cryptography` docs, security is achieved through:</span>
+</span><span id="SecureCookiesMiddleware-24"><a href="#SecureCookiesMiddleware-24"><span class="linenos"> 24</span></a>
+</span><span id="SecureCookiesMiddleware-25"><a href="#SecureCookiesMiddleware-25"><span class="linenos"> 25</span></a><span class="sd">    - 128-bit key AES in CBC mode using PKCS7 padding for encryption.</span>
+</span><span id="SecureCookiesMiddleware-26"><a href="#SecureCookiesMiddleware-26"><span class="linenos"> 26</span></a><span class="sd">    - HMAC using SHA256 for authentication.</span>
+</span><span id="SecureCookiesMiddleware-27"><a href="#SecureCookiesMiddleware-27"><span class="linenos"> 27</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="SecureCookiesMiddleware-28"><a href="#SecureCookiesMiddleware-28"><span class="linenos"> 28</span></a>
+</span><span id="SecureCookiesMiddleware-29"><a href="#SecureCookiesMiddleware-29"><span class="linenos"> 29</span></a>    <span class="n">secrets</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span>
+</span><span id="SecureCookiesMiddleware-30"><a href="#SecureCookiesMiddleware-30"><span class="linenos"> 30</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;</span>
+</span><span id="SecureCookiesMiddleware-31"><a href="#SecureCookiesMiddleware-31"><span class="linenos"> 31</span></a><span class="sd">    A list of secrets to use when encrypting and decrypting secure cookies. Supplying</span>
+</span><span id="SecureCookiesMiddleware-32"><a href="#SecureCookiesMiddleware-32"><span class="linenos"> 32</span></a><span class="sd">    multiple secrets enables the use of key rotation, whereby the first key is used for</span>
+</span><span id="SecureCookiesMiddleware-33"><a href="#SecureCookiesMiddleware-33"><span class="linenos"> 33</span></a><span class="sd">    all encryption, including to re-encrypt cookies previously encrypted with any of</span>
+</span><span id="SecureCookiesMiddleware-34"><a href="#SecureCookiesMiddleware-34"><span class="linenos"> 34</span></a><span class="sd">    the other list entries.</span>
+</span><span id="SecureCookiesMiddleware-35"><a href="#SecureCookiesMiddleware-35"><span class="linenos"> 35</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="SecureCookiesMiddleware-36"><a href="#SecureCookiesMiddleware-36"><span class="linenos"> 36</span></a>
+</span><span id="SecureCookiesMiddleware-37"><a href="#SecureCookiesMiddleware-37"><span class="linenos"> 37</span></a>    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span>
+</span><span id="SecureCookiesMiddleware-38"><a href="#SecureCookiesMiddleware-38"><span class="linenos"> 38</span></a>        <span class="bp">self</span><span class="p">,</span>
+</span><span id="SecureCookiesMiddleware-39"><a href="#SecureCookiesMiddleware-39"><span class="linenos"> 39</span></a>        <span class="n">app</span><span class="p">:</span> <span class="n">ASGIApp</span><span class="p">,</span>
+</span><span id="SecureCookiesMiddleware-40"><a href="#SecureCookiesMiddleware-40"><span class="linenos"> 40</span></a>        <span class="n">secrets</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">],</span>
+</span><span id="SecureCookiesMiddleware-41"><a href="#SecureCookiesMiddleware-41"><span class="linenos"> 41</span></a>        <span class="n">discard_invalid</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">True</span><span class="p">,</span>
+</span><span id="SecureCookiesMiddleware-42"><a href="#SecureCookiesMiddleware-42"><span class="linenos"> 42</span></a>        <span class="n">cookie_path</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
+</span><span id="SecureCookiesMiddleware-43"><a href="#SecureCookiesMiddleware-43"><span class="linenos"> 43</span></a>        <span class="n">cookie_domain</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
+</span><span id="SecureCookiesMiddleware-44"><a href="#SecureCookiesMiddleware-44"><span class="linenos"> 44</span></a>        <span class="n">cookie_secure</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">bool</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
+</span><span id="SecureCookiesMiddleware-45"><a href="#SecureCookiesMiddleware-45"><span class="linenos"> 45</span></a>        <span class="n">cookie_httponly</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">bool</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
+</span><span id="SecureCookiesMiddleware-46"><a href="#SecureCookiesMiddleware-46"><span class="linenos"> 46</span></a>        <span class="n">cookie_samesite</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Literal</span><span class="p">[</span><span class="s2">&quot;strict&quot;</span><span class="p">,</span> <span class="s2">&quot;lax&quot;</span><span class="p">,</span> <span class="s2">&quot;none&quot;</span><span class="p">]]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
+</span><span id="SecureCookiesMiddleware-47"><a href="#SecureCookiesMiddleware-47"><span class="linenos"> 47</span></a>        <span class="n">excluded_cookies</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
+</span><span id="SecureCookiesMiddleware-48"><a href="#SecureCookiesMiddleware-48"><span class="linenos"> 48</span></a>        <span class="n">included_cookies</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
+</span><span id="SecureCookiesMiddleware-49"><a href="#SecureCookiesMiddleware-49"><span class="linenos"> 49</span></a>    <span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="SecureCookiesMiddleware-50"><a href="#SecureCookiesMiddleware-50"><span class="linenos"> 50</span></a>        <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="n">app</span><span class="p">)</span>
+</span><span id="SecureCookiesMiddleware-51"><a href="#SecureCookiesMiddleware-51"><span class="linenos"> 51</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">mfernet</span> <span class="o">=</span> <span class="n">MultiFernet</span><span class="p">(</span><span class="n">Fernet</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="k">for</span> <span class="n">s</span> <span class="ow">in</span> <span class="n">secrets</span><span class="p">)</span>
+</span><span id="SecureCookiesMiddleware-52"><a href="#SecureCookiesMiddleware-52"><span class="linenos"> 52</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">discard_invalid</span> <span class="o">=</span> <span class="n">discard_invalid</span>
+</span><span id="SecureCookiesMiddleware-53"><a href="#SecureCookiesMiddleware-53"><span class="linenos"> 53</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot; Discard any invalid / unencrypted cookies present in the request.&quot;&quot;&quot;</span>
+</span><span id="SecureCookiesMiddleware-54"><a href="#SecureCookiesMiddleware-54"><span class="linenos"> 54</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">cookie_path</span> <span class="o">=</span> <span class="n">cookie_path</span>
+</span><span id="SecureCookiesMiddleware-55"><a href="#SecureCookiesMiddleware-55"><span class="linenos"> 55</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot; The Path field value to override on every cookie.&quot;&quot;&quot;</span>
+</span><span id="SecureCookiesMiddleware-56"><a href="#SecureCookiesMiddleware-56"><span class="linenos"> 56</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">cookie_domain</span> <span class="o">=</span> <span class="n">cookie_domain</span>
+</span><span id="SecureCookiesMiddleware-57"><a href="#SecureCookiesMiddleware-57"><span class="linenos"> 57</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot; The Domain field value to override on every cookie.&quot;&quot;&quot;</span>
+</span><span id="SecureCookiesMiddleware-58"><a href="#SecureCookiesMiddleware-58"><span class="linenos"> 58</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">cookie_secure</span> <span class="o">=</span> <span class="n">cookie_secure</span>
+</span><span id="SecureCookiesMiddleware-59"><a href="#SecureCookiesMiddleware-59"><span class="linenos"> 59</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot; The Secure field value to override on every cookie.&quot;&quot;&quot;</span>
+</span><span id="SecureCookiesMiddleware-60"><a href="#SecureCookiesMiddleware-60"><span class="linenos"> 60</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">cookie_httponly</span> <span class="o">=</span> <span class="n">cookie_httponly</span>
+</span><span id="SecureCookiesMiddleware-61"><a href="#SecureCookiesMiddleware-61"><span class="linenos"> 61</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot; The HttpOnly field value to override on every cookie.&quot;&quot;&quot;</span>
+</span><span id="SecureCookiesMiddleware-62"><a href="#SecureCookiesMiddleware-62"><span class="linenos"> 62</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">cookie_samesite</span> <span class="o">=</span> <span class="n">cookie_samesite</span>
+</span><span id="SecureCookiesMiddleware-63"><a href="#SecureCookiesMiddleware-63"><span class="linenos"> 63</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot; The SameStime field value to override on every cookie.&quot;&quot;&quot;</span>
+</span><span id="SecureCookiesMiddleware-64"><a href="#SecureCookiesMiddleware-64"><span class="linenos"> 64</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">excluded_cookies</span> <span class="o">=</span> <span class="n">excluded_cookies</span>
+</span><span id="SecureCookiesMiddleware-65"><a href="#SecureCookiesMiddleware-65"><span class="linenos"> 65</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;</span>
+</span><span id="SecureCookiesMiddleware-66"><a href="#SecureCookiesMiddleware-66"><span class="linenos"> 66</span></a><span class="sd">        The list of cookies to ignore when decrypting and encrypting in</span>
+</span><span id="SecureCookiesMiddleware-67"><a href="#SecureCookiesMiddleware-67"><span class="linenos"> 67</span></a><span class="sd">        the request --&gt; response cycle. This option is mutually exclusive with</span>
+</span><span id="SecureCookiesMiddleware-68"><a href="#SecureCookiesMiddleware-68"><span class="linenos"> 68</span></a><span class="sd">        `included_cookies`.</span>
+</span><span id="SecureCookiesMiddleware-69"><a href="#SecureCookiesMiddleware-69"><span class="linenos"> 69</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="SecureCookiesMiddleware-70"><a href="#SecureCookiesMiddleware-70"><span class="linenos"> 70</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">included_cookies</span> <span class="o">=</span> <span class="n">included_cookies</span>
+</span><span id="SecureCookiesMiddleware-71"><a href="#SecureCookiesMiddleware-71"><span class="linenos"> 71</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;</span>
+</span><span id="SecureCookiesMiddleware-72"><a href="#SecureCookiesMiddleware-72"><span class="linenos"> 72</span></a><span class="sd">        The list of cookies to decrypt and encrypt in the request --&gt; response cycle.</span>
+</span><span id="SecureCookiesMiddleware-73"><a href="#SecureCookiesMiddleware-73"><span class="linenos"> 73</span></a><span class="sd">        This option is mutually exclusive with `excluded_cookies`.</span>
+</span><span id="SecureCookiesMiddleware-74"><a href="#SecureCookiesMiddleware-74"><span class="linenos"> 74</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="SecureCookiesMiddleware-75"><a href="#SecureCookiesMiddleware-75"><span class="linenos"> 75</span></a>
+</span><span id="SecureCookiesMiddleware-76"><a href="#SecureCookiesMiddleware-76"><span class="linenos"> 76</span></a>        <span class="k">if</span> <span class="n">excluded_cookies</span> <span class="ow">and</span> <span class="n">included_cookies</span><span class="p">:</span>
+</span><span id="SecureCookiesMiddleware-77"><a href="#SecureCookiesMiddleware-77"><span class="linenos"> 77</span></a>            <span class="k">raise</span> <span class="n">BadArgumentError</span><span class="p">(</span>
+</span><span id="SecureCookiesMiddleware-78"><a href="#SecureCookiesMiddleware-78"><span class="linenos"> 78</span></a>                <span class="s2">&quot;It doesn&#39;t make sense to specify both excluded and included cookies.&quot;</span>
+</span><span id="SecureCookiesMiddleware-79"><a href="#SecureCookiesMiddleware-79"><span class="linenos"> 79</span></a>                <span class="s2">&quot; Supply either `excluded_cookies` or `included_cookies` to restrict&quot;</span>
+</span><span id="SecureCookiesMiddleware-80"><a href="#SecureCookiesMiddleware-80"><span class="linenos"> 80</span></a>                <span class="s2">&quot; which cookies should be secure.&quot;</span>
+</span><span id="SecureCookiesMiddleware-81"><a href="#SecureCookiesMiddleware-81"><span class="linenos"> 81</span></a>            <span class="p">)</span>
+</span><span id="SecureCookiesMiddleware-82"><a href="#SecureCookiesMiddleware-82"><span class="linenos"> 82</span></a>
+</span><span id="SecureCookiesMiddleware-83"><a href="#SecureCookiesMiddleware-83"><span class="linenos"> 83</span></a>        <span class="k">if</span> <span class="n">cookie_samesite</span> <span class="ow">and</span> <span class="n">cookie_samesite</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">[</span><span class="s2">&quot;strict&quot;</span><span class="p">,</span> <span class="s2">&quot;lax&quot;</span><span class="p">,</span> <span class="s2">&quot;none&quot;</span><span class="p">]:</span>
+</span><span id="SecureCookiesMiddleware-84"><a href="#SecureCookiesMiddleware-84"><span class="linenos"> 84</span></a>            <span class="k">raise</span> <span class="n">BadArgumentError</span><span class="p">(</span>
+</span><span id="SecureCookiesMiddleware-85"><a href="#SecureCookiesMiddleware-85"><span class="linenos"> 85</span></a>                <span class="s2">&quot;SameSite attribute must be either &#39;strict&#39;, &#39;lax&#39; or &#39;none&#39;&quot;</span>
+</span><span id="SecureCookiesMiddleware-86"><a href="#SecureCookiesMiddleware-86"><span class="linenos"> 86</span></a>            <span class="p">)</span>
+</span><span id="SecureCookiesMiddleware-87"><a href="#SecureCookiesMiddleware-87"><span class="linenos"> 87</span></a>
+</span><span id="SecureCookiesMiddleware-88"><a href="#SecureCookiesMiddleware-88"><span class="linenos"> 88</span></a>    <span class="k">def</span> <span class="nf">set_header</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">request</span><span class="p">:</span> <span class="n">Request</span><span class="p">,</span> <span class="n">header</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="SecureCookiesMiddleware-89"><a href="#SecureCookiesMiddleware-89"><span class="linenos"> 89</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;</span>
+</span><span id="SecureCookiesMiddleware-90"><a href="#SecureCookiesMiddleware-90"><span class="linenos"> 90</span></a><span class="sd">        Adds the given Header to the available Request headers. If the Header already</span>
+</span><span id="SecureCookiesMiddleware-91"><a href="#SecureCookiesMiddleware-91"><span class="linenos"> 91</span></a><span class="sd">        exists, its value is overwritten.</span>
+</span><span id="SecureCookiesMiddleware-92"><a href="#SecureCookiesMiddleware-92"><span class="linenos"> 92</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="SecureCookiesMiddleware-93"><a href="#SecureCookiesMiddleware-93"><span class="linenos"> 93</span></a>        <span class="n">hkey</span> <span class="o">=</span> <span class="n">header</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">&quot;latin-1&quot;</span><span class="p">)</span>
+</span><span id="SecureCookiesMiddleware-94"><a href="#SecureCookiesMiddleware-94"><span class="linenos"> 94</span></a>        <span class="n">request</span><span class="o">.</span><span class="n">scope</span><span class="p">[</span><span class="s2">&quot;headers&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span>
+</span><span id="SecureCookiesMiddleware-95"><a href="#SecureCookiesMiddleware-95"><span class="linenos"> 95</span></a>            <span class="o">*</span><span class="p">(</span><span class="n">h</span> <span class="k">for</span> <span class="n">h</span> <span class="ow">in</span> <span class="n">request</span><span class="o">.</span><span class="n">scope</span><span class="p">[</span><span class="s2">&quot;headers&quot;</span><span class="p">]</span> <span class="k">if</span> <span class="n">h</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">!=</span> <span class="n">hkey</span><span class="p">),</span>
+</span><span id="SecureCookiesMiddleware-96"><a href="#SecureCookiesMiddleware-96"><span class="linenos"> 96</span></a>            <span class="p">(</span><span class="n">hkey</span><span class="p">,</span> <span class="n">value</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">&quot;latin-1&quot;</span><span class="p">)),</span>
+</span><span id="SecureCookiesMiddleware-97"><a href="#SecureCookiesMiddleware-97"><span class="linenos"> 97</span></a>        <span class="p">]</span>
+</span><span id="SecureCookiesMiddleware-98"><a href="#SecureCookiesMiddleware-98"><span class="linenos"> 98</span></a>
+</span><span id="SecureCookiesMiddleware-99"><a href="#SecureCookiesMiddleware-99"><span class="linenos"> 99</span></a>    <span class="k">def</span> <span class="nf">decrypt</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
+</span><span id="SecureCookiesMiddleware-100"><a href="#SecureCookiesMiddleware-100"><span class="linenos">100</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Decrypt the given value using any of the configured secrets.&quot;&quot;&quot;</span>
+</span><span id="SecureCookiesMiddleware-101"><a href="#SecureCookiesMiddleware-101"><span class="linenos">101</span></a>        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">mfernet</span><span class="o">.</span><span class="n">decrypt</span><span class="p">(</span><span class="n">value</span><span class="o">.</span><span class="n">encode</span><span class="p">())</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span>
+</span><span id="SecureCookiesMiddleware-102"><a href="#SecureCookiesMiddleware-102"><span class="linenos">102</span></a>
+</span><span id="SecureCookiesMiddleware-103"><a href="#SecureCookiesMiddleware-103"><span class="linenos">103</span></a>    <span class="k">def</span> <span class="nf">encrypt</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
+</span><span id="SecureCookiesMiddleware-104"><a href="#SecureCookiesMiddleware-104"><span class="linenos">104</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Encrypt the given value using the first configured secret.&quot;&quot;&quot;</span>
+</span><span id="SecureCookiesMiddleware-105"><a href="#SecureCookiesMiddleware-105"><span class="linenos">105</span></a>        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">mfernet</span><span class="o">.</span><span class="n">encrypt</span><span class="p">(</span><span class="n">value</span><span class="o">.</span><span class="n">encode</span><span class="p">())</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span>
+</span><span id="SecureCookiesMiddleware-106"><a href="#SecureCookiesMiddleware-106"><span class="linenos">106</span></a>
+</span><span id="SecureCookiesMiddleware-107"><a href="#SecureCookiesMiddleware-107"><span class="linenos">107</span></a>    <span class="k">async</span> <span class="k">def</span> <span class="nf">dispatch</span><span class="p">(</span>
+</span><span id="SecureCookiesMiddleware-108"><a href="#SecureCookiesMiddleware-108"><span class="linenos">108</span></a>        <span class="bp">self</span><span class="p">,</span> <span class="n">request</span><span class="p">:</span> <span class="n">Request</span><span class="p">,</span> <span class="n">call_next</span><span class="p">:</span> <span class="n">RequestResponseEndpoint</span>
+</span><span id="SecureCookiesMiddleware-109"><a href="#SecureCookiesMiddleware-109"><span class="linenos">109</span></a>    <span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Response</span><span class="p">:</span>
+</span><span id="SecureCookiesMiddleware-110"><a href="#SecureCookiesMiddleware-110"><span class="linenos">110</span></a>        <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">cookies</span><span class="p">):</span>
+</span><span id="SecureCookiesMiddleware-111"><a href="#SecureCookiesMiddleware-111"><span class="linenos">111</span></a>            <span class="n">cookies</span><span class="p">:</span> <span class="n">SimpleCookie</span><span class="p">[</span><span class="n">Any</span><span class="p">]</span> <span class="o">=</span> <span class="n">SimpleCookie</span><span class="p">()</span>
+</span><span id="SecureCookiesMiddleware-112"><a href="#SecureCookiesMiddleware-112"><span class="linenos">112</span></a>            <span class="k">for</span> <span class="n">cookie</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">request</span><span class="o">.</span><span class="n">cookies</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
+</span><span id="SecureCookiesMiddleware-113"><a href="#SecureCookiesMiddleware-113"><span class="linenos">113</span></a>                <span class="c1"># if the cookie is included or not excluded</span>
+</span><span id="SecureCookiesMiddleware-114"><a href="#SecureCookiesMiddleware-114"><span class="linenos">114</span></a>                <span class="k">if</span> <span class="p">(</span>
+</span><span id="SecureCookiesMiddleware-115"><a href="#SecureCookiesMiddleware-115"><span class="linenos">115</span></a>                    <span class="p">(</span><span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">included_cookies</span> <span class="ow">and</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">excluded_cookies</span><span class="p">)</span>
+</span><span id="SecureCookiesMiddleware-116"><a href="#SecureCookiesMiddleware-116"><span class="linenos">116</span></a>                    <span class="ow">or</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">included_cookies</span> <span class="ow">and</span> <span class="n">cookie</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">included_cookies</span><span class="p">)</span>
+</span><span id="SecureCookiesMiddleware-117"><a href="#SecureCookiesMiddleware-117"><span class="linenos">117</span></a>                    <span class="ow">or</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">excluded_cookies</span> <span class="ow">and</span> <span class="n">cookie</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">excluded_cookies</span><span class="p">)</span>
+</span><span id="SecureCookiesMiddleware-118"><a href="#SecureCookiesMiddleware-118"><span class="linenos">118</span></a>                <span class="p">):</span>
+</span><span id="SecureCookiesMiddleware-119"><a href="#SecureCookiesMiddleware-119"><span class="linenos">119</span></a>                    <span class="k">try</span><span class="p">:</span>
+</span><span id="SecureCookiesMiddleware-120"><a href="#SecureCookiesMiddleware-120"><span class="linenos">120</span></a>                        <span class="c1"># try to decrypt the cookie and pass it along</span>
+</span><span id="SecureCookiesMiddleware-121"><a href="#SecureCookiesMiddleware-121"><span class="linenos">121</span></a>                        <span class="n">cookies</span><span class="p">[</span><span class="n">cookie</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">decrypt</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
+</span><span id="SecureCookiesMiddleware-122"><a href="#SecureCookiesMiddleware-122"><span class="linenos">122</span></a>                    <span class="k">except</span> <span class="n">InvalidToken</span><span class="p">:</span>
+</span><span id="SecureCookiesMiddleware-123"><a href="#SecureCookiesMiddleware-123"><span class="linenos">123</span></a>                        <span class="c1"># delete invalid or unencrypted cookies unless disabled</span>
+</span><span id="SecureCookiesMiddleware-124"><a href="#SecureCookiesMiddleware-124"><span class="linenos">124</span></a>                        <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">discard_invalid</span><span class="p">:</span>
+</span><span id="SecureCookiesMiddleware-125"><a href="#SecureCookiesMiddleware-125"><span class="linenos">125</span></a>                            <span class="n">cookies</span><span class="p">[</span><span class="n">cookie</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span>
+</span><span id="SecureCookiesMiddleware-126"><a href="#SecureCookiesMiddleware-126"><span class="linenos">126</span></a>
+</span><span id="SecureCookiesMiddleware-127"><a href="#SecureCookiesMiddleware-127"><span class="linenos">127</span></a>            <span class="c1"># serialize and set the decrypted cookies to the asgi scope headers</span>
+</span><span id="SecureCookiesMiddleware-128"><a href="#SecureCookiesMiddleware-128"><span class="linenos">128</span></a>            <span class="c1"># we have to modify the scope directly because request objects are not</span>
+</span><span id="SecureCookiesMiddleware-129"><a href="#SecureCookiesMiddleware-129"><span class="linenos">129</span></a>            <span class="c1"># passed between ASGI applications / middleware.</span>
+</span><span id="SecureCookiesMiddleware-130"><a href="#SecureCookiesMiddleware-130"><span class="linenos">130</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">set_header</span><span class="p">(</span>
+</span><span id="SecureCookiesMiddleware-131"><a href="#SecureCookiesMiddleware-131"><span class="linenos">131</span></a>                <span class="n">request</span><span class="p">,</span> <span class="s2">&quot;cookie&quot;</span><span class="p">,</span> <span class="n">cookies</span><span class="o">.</span><span class="n">output</span><span class="p">(</span><span class="n">header</span><span class="o">=</span><span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="n">sep</span><span class="o">=</span><span class="s2">&quot;;&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
+</span><span id="SecureCookiesMiddleware-132"><a href="#SecureCookiesMiddleware-132"><span class="linenos">132</span></a>            <span class="p">)</span>
+</span><span id="SecureCookiesMiddleware-133"><a href="#SecureCookiesMiddleware-133"><span class="linenos">133</span></a>
+</span><span id="SecureCookiesMiddleware-134"><a href="#SecureCookiesMiddleware-134"><span class="linenos">134</span></a>        <span class="c1"># propagate the modified request</span>
+</span><span id="SecureCookiesMiddleware-135"><a href="#SecureCookiesMiddleware-135"><span class="linenos">135</span></a>        <span class="n">response</span><span class="p">:</span> <span class="n">Response</span> <span class="o">=</span> <span class="k">await</span> <span class="n">call_next</span><span class="p">(</span><span class="n">request</span><span class="p">)</span>
+</span><span id="SecureCookiesMiddleware-136"><a href="#SecureCookiesMiddleware-136"><span class="linenos">136</span></a>
+</span><span id="SecureCookiesMiddleware-137"><a href="#SecureCookiesMiddleware-137"><span class="linenos">137</span></a>        <span class="c1"># for every cookie in the response</span>
+</span><span id="SecureCookiesMiddleware-138"><a href="#SecureCookiesMiddleware-138"><span class="linenos">138</span></a>        <span class="k">for</span> <span class="n">cookie</span> <span class="ow">in</span> <span class="n">response</span><span class="o">.</span><span class="n">headers</span><span class="o">.</span><span class="n">getlist</span><span class="p">(</span><span class="s2">&quot;set-cookie&quot;</span><span class="p">):</span>
+</span><span id="SecureCookiesMiddleware-139"><a href="#SecureCookiesMiddleware-139"><span class="linenos">139</span></a>            <span class="c1"># decode it</span>
+</span><span id="SecureCookiesMiddleware-140"><a href="#SecureCookiesMiddleware-140"><span class="linenos">140</span></a>            <span class="n">ncookie</span><span class="p">:</span> <span class="n">SimpleCookie</span><span class="p">[</span><span class="n">Any</span><span class="p">]</span> <span class="o">=</span> <span class="n">SimpleCookie</span><span class="p">(</span><span class="n">cookie</span><span class="p">)</span>
+</span><span id="SecureCookiesMiddleware-141"><a href="#SecureCookiesMiddleware-141"><span class="linenos">141</span></a>            <span class="n">key</span> <span class="o">=</span> <span class="p">[</span><span class="o">*</span><span class="n">ncookie</span><span class="o">.</span><span class="n">keys</span><span class="p">()][</span><span class="mi">0</span><span class="p">]</span>
+</span><span id="SecureCookiesMiddleware-142"><a href="#SecureCookiesMiddleware-142"><span class="linenos">142</span></a>
+</span><span id="SecureCookiesMiddleware-143"><a href="#SecureCookiesMiddleware-143"><span class="linenos">143</span></a>            <span class="c1"># if the cookie is included or not excluded</span>
+</span><span id="SecureCookiesMiddleware-144"><a href="#SecureCookiesMiddleware-144"><span class="linenos">144</span></a>            <span class="k">if</span> <span class="p">(</span>
+</span><span id="SecureCookiesMiddleware-145"><a href="#SecureCookiesMiddleware-145"><span class="linenos">145</span></a>                <span class="p">(</span><span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">included_cookies</span> <span class="ow">and</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">excluded_cookies</span><span class="p">)</span>
+</span><span id="SecureCookiesMiddleware-146"><a href="#SecureCookiesMiddleware-146"><span class="linenos">146</span></a>                <span class="ow">or</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">included_cookies</span> <span class="ow">and</span> <span class="n">key</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">included_cookies</span><span class="p">)</span>
+</span><span id="SecureCookiesMiddleware-147"><a href="#SecureCookiesMiddleware-147"><span class="linenos">147</span></a>                <span class="ow">or</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">excluded_cookies</span> <span class="ow">and</span> <span class="n">key</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">excluded_cookies</span><span class="p">)</span>
+</span><span id="SecureCookiesMiddleware-148"><a href="#SecureCookiesMiddleware-148"><span class="linenos">148</span></a>            <span class="p">):</span>
+</span><span id="SecureCookiesMiddleware-149"><a href="#SecureCookiesMiddleware-149"><span class="linenos">149</span></a>                <span class="c1"># create a new encrypted cookie with the desired attributes</span>
+</span><span id="SecureCookiesMiddleware-150"><a href="#SecureCookiesMiddleware-150"><span class="linenos">150</span></a>                <span class="n">response</span><span class="o">.</span><span class="n">set_cookie</span><span class="p">(</span>
+</span><span id="SecureCookiesMiddleware-151"><a href="#SecureCookiesMiddleware-151"><span class="linenos">151</span></a>                    <span class="n">key</span><span class="p">,</span>
+</span><span id="SecureCookiesMiddleware-152"><a href="#SecureCookiesMiddleware-152"><span class="linenos">152</span></a>                    <span class="n">value</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">encrypt</span><span class="p">(</span><span class="n">ncookie</span><span class="p">[</span><span class="n">key</span><span class="p">]</span><span class="o">.</span><span class="n">value</span><span class="p">),</span>
+</span><span id="SecureCookiesMiddleware-153"><a href="#SecureCookiesMiddleware-153"><span class="linenos">153</span></a>                    <span class="n">path</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">cookie_path</span> <span class="ow">or</span> <span class="n">ncookie</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="s2">&quot;path&quot;</span><span class="p">],</span>
+</span><span id="SecureCookiesMiddleware-154"><a href="#SecureCookiesMiddleware-154"><span class="linenos">154</span></a>                    <span class="n">domain</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">cookie_domain</span> <span class="ow">or</span> <span class="n">ncookie</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="s2">&quot;domain&quot;</span><span class="p">],</span>
+</span><span id="SecureCookiesMiddleware-155"><a href="#SecureCookiesMiddleware-155"><span class="linenos">155</span></a>                    <span class="n">secure</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">cookie_secure</span> <span class="ow">or</span> <span class="n">ncookie</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="s2">&quot;secure&quot;</span><span class="p">],</span>
+</span><span id="SecureCookiesMiddleware-156"><a href="#SecureCookiesMiddleware-156"><span class="linenos">156</span></a>                    <span class="n">httponly</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">cookie_httponly</span> <span class="ow">or</span> <span class="n">ncookie</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="s2">&quot;httponly&quot;</span><span class="p">],</span>
+</span><span id="SecureCookiesMiddleware-157"><a href="#SecureCookiesMiddleware-157"><span class="linenos">157</span></a>                    <span class="n">samesite</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">cookie_samesite</span> <span class="ow">or</span> <span class="n">ncookie</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="s2">&quot;samesite&quot;</span><span class="p">],</span>
+</span><span id="SecureCookiesMiddleware-158"><a href="#SecureCookiesMiddleware-158"><span class="linenos">158</span></a>                <span class="p">)</span>
+</span><span id="SecureCookiesMiddleware-159"><a href="#SecureCookiesMiddleware-159"><span class="linenos">159</span></a>
+</span><span id="SecureCookiesMiddleware-160"><a href="#SecureCookiesMiddleware-160"><span class="linenos">160</span></a>        <span class="k">return</span> <span class="n">response</span>
 </span></pre>
         </div>
 
@@ -1648,7 +1755,7 @@ <h2 id="license">License</h2>
 
           <ul>
             <li>
-              128-bit key AES in CBC mode using PKCS7 padding for encryption
+              128-bit key AES in CBC mode using PKCS7 padding for encryption.
             </li>
             <li>HMAC using SHA256 for authentication.</li>
           </ul>
@@ -1719,9 +1826,14 @@ <h2 id="license">License</h2>
               ><span class="param">
                 <span class="n">cookie_samesite</span><span class="p">:</span>
                 <span class="n">Union</span><span class="p">[</span
-                ><span class="nb">str</span><span class="p">,</span>
-                <span class="n">NoneType</span><span class="p">]</span>
-                <span class="o">=</span> <span class="kc">None</span>,</span
+                ><span class="n">typing_extensions</span><span class="o">.</span
+                ><span class="n">Literal</span><span class="p">[</span
+                ><span class="s1">&#39;strict&#39;</span
+                ><span class="p">,</span> <span class="s1">&#39;lax&#39;</span
+                ><span class="p">,</span> <span class="s1">&#39;none&#39;</span
+                ><span class="p">],</span> <span class="n">NoneType</span
+                ><span class="p">]</span> <span class="o">=</span>
+                <span class="kc">None</span>,</span
               ><span class="param">
                 <span class="n">excluded_cookies</span><span class="p">:</span>
                 <span class="n">Union</span><span class="p">[</span
@@ -1747,56 +1859,56 @@ <h2 id="license">License</h2>
           </div>
           <a class="headerlink" href="#SecureCookiesMiddleware.__init__"></a>
           <div class="pdoc-code codehilite">
-            <pre><span></span><span id="SecureCookiesMiddleware.__init__-36"><a href="#SecureCookiesMiddleware.__init__-36"><span class="linenos">36</span></a>    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span>
-</span><span id="SecureCookiesMiddleware.__init__-37"><a href="#SecureCookiesMiddleware.__init__-37"><span class="linenos">37</span></a>        <span class="bp">self</span><span class="p">,</span>
-</span><span id="SecureCookiesMiddleware.__init__-38"><a href="#SecureCookiesMiddleware.__init__-38"><span class="linenos">38</span></a>        <span class="n">app</span><span class="p">:</span> <span class="n">ASGIApp</span><span class="p">,</span>
-</span><span id="SecureCookiesMiddleware.__init__-39"><a href="#SecureCookiesMiddleware.__init__-39"><span class="linenos">39</span></a>        <span class="n">secrets</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">],</span>
-</span><span id="SecureCookiesMiddleware.__init__-40"><a href="#SecureCookiesMiddleware.__init__-40"><span class="linenos">40</span></a>        <span class="n">discard_invalid</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">True</span><span class="p">,</span>
-</span><span id="SecureCookiesMiddleware.__init__-41"><a href="#SecureCookiesMiddleware.__init__-41"><span class="linenos">41</span></a>        <span class="n">cookie_path</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
-</span><span id="SecureCookiesMiddleware.__init__-42"><a href="#SecureCookiesMiddleware.__init__-42"><span class="linenos">42</span></a>        <span class="n">cookie_domain</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
-</span><span id="SecureCookiesMiddleware.__init__-43"><a href="#SecureCookiesMiddleware.__init__-43"><span class="linenos">43</span></a>        <span class="n">cookie_secure</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">bool</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
-</span><span id="SecureCookiesMiddleware.__init__-44"><a href="#SecureCookiesMiddleware.__init__-44"><span class="linenos">44</span></a>        <span class="n">cookie_httponly</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">bool</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
-</span><span id="SecureCookiesMiddleware.__init__-45"><a href="#SecureCookiesMiddleware.__init__-45"><span class="linenos">45</span></a>        <span class="n">cookie_samesite</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
-</span><span id="SecureCookiesMiddleware.__init__-46"><a href="#SecureCookiesMiddleware.__init__-46"><span class="linenos">46</span></a>        <span class="n">excluded_cookies</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
-</span><span id="SecureCookiesMiddleware.__init__-47"><a href="#SecureCookiesMiddleware.__init__-47"><span class="linenos">47</span></a>        <span class="n">included_cookies</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
-</span><span id="SecureCookiesMiddleware.__init__-48"><a href="#SecureCookiesMiddleware.__init__-48"><span class="linenos">48</span></a>    <span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
-</span><span id="SecureCookiesMiddleware.__init__-49"><a href="#SecureCookiesMiddleware.__init__-49"><span class="linenos">49</span></a>        <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="n">app</span><span class="p">)</span>
-</span><span id="SecureCookiesMiddleware.__init__-50"><a href="#SecureCookiesMiddleware.__init__-50"><span class="linenos">50</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">mfernet</span> <span class="o">=</span> <span class="n">MultiFernet</span><span class="p">(</span><span class="n">Fernet</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="k">for</span> <span class="n">s</span> <span class="ow">in</span> <span class="n">secrets</span><span class="p">)</span>
-</span><span id="SecureCookiesMiddleware.__init__-51"><a href="#SecureCookiesMiddleware.__init__-51"><span class="linenos">51</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">discard_invalid</span> <span class="o">=</span> <span class="n">discard_invalid</span>
-</span><span id="SecureCookiesMiddleware.__init__-52"><a href="#SecureCookiesMiddleware.__init__-52"><span class="linenos">52</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot; Discard any invalid / unencrypted cookies present in the request.&quot;&quot;&quot;</span>
-</span><span id="SecureCookiesMiddleware.__init__-53"><a href="#SecureCookiesMiddleware.__init__-53"><span class="linenos">53</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">cookie_path</span> <span class="o">=</span> <span class="n">cookie_path</span>
-</span><span id="SecureCookiesMiddleware.__init__-54"><a href="#SecureCookiesMiddleware.__init__-54"><span class="linenos">54</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot; The Path field value to override on every cookie.&quot;&quot;&quot;</span>
-</span><span id="SecureCookiesMiddleware.__init__-55"><a href="#SecureCookiesMiddleware.__init__-55"><span class="linenos">55</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">cookie_domain</span> <span class="o">=</span> <span class="n">cookie_domain</span>
-</span><span id="SecureCookiesMiddleware.__init__-56"><a href="#SecureCookiesMiddleware.__init__-56"><span class="linenos">56</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot; The Domain field value to override on every cookie.&quot;&quot;&quot;</span>
-</span><span id="SecureCookiesMiddleware.__init__-57"><a href="#SecureCookiesMiddleware.__init__-57"><span class="linenos">57</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">cookie_secure</span> <span class="o">=</span> <span class="n">cookie_secure</span>
-</span><span id="SecureCookiesMiddleware.__init__-58"><a href="#SecureCookiesMiddleware.__init__-58"><span class="linenos">58</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot; The Secure field value to override on every cookie.&quot;&quot;&quot;</span>
-</span><span id="SecureCookiesMiddleware.__init__-59"><a href="#SecureCookiesMiddleware.__init__-59"><span class="linenos">59</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">cookie_httponly</span> <span class="o">=</span> <span class="n">cookie_httponly</span>
-</span><span id="SecureCookiesMiddleware.__init__-60"><a href="#SecureCookiesMiddleware.__init__-60"><span class="linenos">60</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot; The HttpOnly field value to override on every cookie.&quot;&quot;&quot;</span>
-</span><span id="SecureCookiesMiddleware.__init__-61"><a href="#SecureCookiesMiddleware.__init__-61"><span class="linenos">61</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">cookie_samesite</span> <span class="o">=</span> <span class="n">cookie_samesite</span>
-</span><span id="SecureCookiesMiddleware.__init__-62"><a href="#SecureCookiesMiddleware.__init__-62"><span class="linenos">62</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot; The SameStime field value to override on every cookie.&quot;&quot;&quot;</span>
-</span><span id="SecureCookiesMiddleware.__init__-63"><a href="#SecureCookiesMiddleware.__init__-63"><span class="linenos">63</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">excluded_cookies</span> <span class="o">=</span> <span class="n">excluded_cookies</span>
-</span><span id="SecureCookiesMiddleware.__init__-64"><a href="#SecureCookiesMiddleware.__init__-64"><span class="linenos">64</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;</span>
-</span><span id="SecureCookiesMiddleware.__init__-65"><a href="#SecureCookiesMiddleware.__init__-65"><span class="linenos">65</span></a><span class="sd">        The list of cookies to ignore when decrypting and encrypting in</span>
-</span><span id="SecureCookiesMiddleware.__init__-66"><a href="#SecureCookiesMiddleware.__init__-66"><span class="linenos">66</span></a><span class="sd">        the request --&gt; response cycle. This option is mutually exclusive with</span>
-</span><span id="SecureCookiesMiddleware.__init__-67"><a href="#SecureCookiesMiddleware.__init__-67"><span class="linenos">67</span></a><span class="sd">        `included_cookies`.</span>
-</span><span id="SecureCookiesMiddleware.__init__-68"><a href="#SecureCookiesMiddleware.__init__-68"><span class="linenos">68</span></a><span class="sd">        &quot;&quot;&quot;</span>
-</span><span id="SecureCookiesMiddleware.__init__-69"><a href="#SecureCookiesMiddleware.__init__-69"><span class="linenos">69</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">included_cookies</span> <span class="o">=</span> <span class="n">included_cookies</span>
-</span><span id="SecureCookiesMiddleware.__init__-70"><a href="#SecureCookiesMiddleware.__init__-70"><span class="linenos">70</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;</span>
-</span><span id="SecureCookiesMiddleware.__init__-71"><a href="#SecureCookiesMiddleware.__init__-71"><span class="linenos">71</span></a><span class="sd">        The list of cookies to decrypt and encrypt in the request --&gt; response cycle.</span>
-</span><span id="SecureCookiesMiddleware.__init__-72"><a href="#SecureCookiesMiddleware.__init__-72"><span class="linenos">72</span></a><span class="sd">        This option is mutually exclusive with `excluded_cookies`.</span>
-</span><span id="SecureCookiesMiddleware.__init__-73"><a href="#SecureCookiesMiddleware.__init__-73"><span class="linenos">73</span></a><span class="sd">        &quot;&quot;&quot;</span>
-</span><span id="SecureCookiesMiddleware.__init__-74"><a href="#SecureCookiesMiddleware.__init__-74"><span class="linenos">74</span></a>
-</span><span id="SecureCookiesMiddleware.__init__-75"><a href="#SecureCookiesMiddleware.__init__-75"><span class="linenos">75</span></a>        <span class="k">if</span> <span class="n">excluded_cookies</span> <span class="ow">and</span> <span class="n">included_cookies</span><span class="p">:</span>
-</span><span id="SecureCookiesMiddleware.__init__-76"><a href="#SecureCookiesMiddleware.__init__-76"><span class="linenos">76</span></a>            <span class="k">raise</span> <span class="n">BadArgumentError</span><span class="p">(</span>
-</span><span id="SecureCookiesMiddleware.__init__-77"><a href="#SecureCookiesMiddleware.__init__-77"><span class="linenos">77</span></a>                <span class="s2">&quot;It doesn&#39;t make sense to specify both excluded and included cookies.&quot;</span>
-</span><span id="SecureCookiesMiddleware.__init__-78"><a href="#SecureCookiesMiddleware.__init__-78"><span class="linenos">78</span></a>                <span class="s2">&quot; Supply with `excluded_cookies` or `included_cookies` to restrict&quot;</span>
-</span><span id="SecureCookiesMiddleware.__init__-79"><a href="#SecureCookiesMiddleware.__init__-79"><span class="linenos">79</span></a>                <span class="s2">&quot; which cookies should be secure.&quot;</span>
-</span><span id="SecureCookiesMiddleware.__init__-80"><a href="#SecureCookiesMiddleware.__init__-80"><span class="linenos">80</span></a>            <span class="p">)</span>
-</span><span id="SecureCookiesMiddleware.__init__-81"><a href="#SecureCookiesMiddleware.__init__-81"><span class="linenos">81</span></a>
-</span><span id="SecureCookiesMiddleware.__init__-82"><a href="#SecureCookiesMiddleware.__init__-82"><span class="linenos">82</span></a>        <span class="k">if</span> <span class="n">cookie_samesite</span> <span class="ow">and</span> <span class="n">cookie_samesite</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">[</span><span class="s2">&quot;strict&quot;</span><span class="p">,</span> <span class="s2">&quot;lax&quot;</span><span class="p">,</span> <span class="s2">&quot;none&quot;</span><span class="p">]:</span>
-</span><span id="SecureCookiesMiddleware.__init__-83"><a href="#SecureCookiesMiddleware.__init__-83"><span class="linenos">83</span></a>            <span class="k">raise</span> <span class="n">BadArgumentError</span><span class="p">(</span>
-</span><span id="SecureCookiesMiddleware.__init__-84"><a href="#SecureCookiesMiddleware.__init__-84"><span class="linenos">84</span></a>                <span class="s2">&quot;SameSite attribute must be either &#39;strict&#39;, &#39;lax&#39; or &#39;none&#39;&quot;</span>
-</span><span id="SecureCookiesMiddleware.__init__-85"><a href="#SecureCookiesMiddleware.__init__-85"><span class="linenos">85</span></a>            <span class="p">)</span>
+            <pre><span></span><span id="SecureCookiesMiddleware.__init__-37"><a href="#SecureCookiesMiddleware.__init__-37"><span class="linenos">37</span></a>    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span>
+</span><span id="SecureCookiesMiddleware.__init__-38"><a href="#SecureCookiesMiddleware.__init__-38"><span class="linenos">38</span></a>        <span class="bp">self</span><span class="p">,</span>
+</span><span id="SecureCookiesMiddleware.__init__-39"><a href="#SecureCookiesMiddleware.__init__-39"><span class="linenos">39</span></a>        <span class="n">app</span><span class="p">:</span> <span class="n">ASGIApp</span><span class="p">,</span>
+</span><span id="SecureCookiesMiddleware.__init__-40"><a href="#SecureCookiesMiddleware.__init__-40"><span class="linenos">40</span></a>        <span class="n">secrets</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">],</span>
+</span><span id="SecureCookiesMiddleware.__init__-41"><a href="#SecureCookiesMiddleware.__init__-41"><span class="linenos">41</span></a>        <span class="n">discard_invalid</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">True</span><span class="p">,</span>
+</span><span id="SecureCookiesMiddleware.__init__-42"><a href="#SecureCookiesMiddleware.__init__-42"><span class="linenos">42</span></a>        <span class="n">cookie_path</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
+</span><span id="SecureCookiesMiddleware.__init__-43"><a href="#SecureCookiesMiddleware.__init__-43"><span class="linenos">43</span></a>        <span class="n">cookie_domain</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
+</span><span id="SecureCookiesMiddleware.__init__-44"><a href="#SecureCookiesMiddleware.__init__-44"><span class="linenos">44</span></a>        <span class="n">cookie_secure</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">bool</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
+</span><span id="SecureCookiesMiddleware.__init__-45"><a href="#SecureCookiesMiddleware.__init__-45"><span class="linenos">45</span></a>        <span class="n">cookie_httponly</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">bool</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
+</span><span id="SecureCookiesMiddleware.__init__-46"><a href="#SecureCookiesMiddleware.__init__-46"><span class="linenos">46</span></a>        <span class="n">cookie_samesite</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Literal</span><span class="p">[</span><span class="s2">&quot;strict&quot;</span><span class="p">,</span> <span class="s2">&quot;lax&quot;</span><span class="p">,</span> <span class="s2">&quot;none&quot;</span><span class="p">]]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
+</span><span id="SecureCookiesMiddleware.__init__-47"><a href="#SecureCookiesMiddleware.__init__-47"><span class="linenos">47</span></a>        <span class="n">excluded_cookies</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
+</span><span id="SecureCookiesMiddleware.__init__-48"><a href="#SecureCookiesMiddleware.__init__-48"><span class="linenos">48</span></a>        <span class="n">included_cookies</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
+</span><span id="SecureCookiesMiddleware.__init__-49"><a href="#SecureCookiesMiddleware.__init__-49"><span class="linenos">49</span></a>    <span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="SecureCookiesMiddleware.__init__-50"><a href="#SecureCookiesMiddleware.__init__-50"><span class="linenos">50</span></a>        <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="n">app</span><span class="p">)</span>
+</span><span id="SecureCookiesMiddleware.__init__-51"><a href="#SecureCookiesMiddleware.__init__-51"><span class="linenos">51</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">mfernet</span> <span class="o">=</span> <span class="n">MultiFernet</span><span class="p">(</span><span class="n">Fernet</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="k">for</span> <span class="n">s</span> <span class="ow">in</span> <span class="n">secrets</span><span class="p">)</span>
+</span><span id="SecureCookiesMiddleware.__init__-52"><a href="#SecureCookiesMiddleware.__init__-52"><span class="linenos">52</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">discard_invalid</span> <span class="o">=</span> <span class="n">discard_invalid</span>
+</span><span id="SecureCookiesMiddleware.__init__-53"><a href="#SecureCookiesMiddleware.__init__-53"><span class="linenos">53</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot; Discard any invalid / unencrypted cookies present in the request.&quot;&quot;&quot;</span>
+</span><span id="SecureCookiesMiddleware.__init__-54"><a href="#SecureCookiesMiddleware.__init__-54"><span class="linenos">54</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">cookie_path</span> <span class="o">=</span> <span class="n">cookie_path</span>
+</span><span id="SecureCookiesMiddleware.__init__-55"><a href="#SecureCookiesMiddleware.__init__-55"><span class="linenos">55</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot; The Path field value to override on every cookie.&quot;&quot;&quot;</span>
+</span><span id="SecureCookiesMiddleware.__init__-56"><a href="#SecureCookiesMiddleware.__init__-56"><span class="linenos">56</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">cookie_domain</span> <span class="o">=</span> <span class="n">cookie_domain</span>
+</span><span id="SecureCookiesMiddleware.__init__-57"><a href="#SecureCookiesMiddleware.__init__-57"><span class="linenos">57</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot; The Domain field value to override on every cookie.&quot;&quot;&quot;</span>
+</span><span id="SecureCookiesMiddleware.__init__-58"><a href="#SecureCookiesMiddleware.__init__-58"><span class="linenos">58</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">cookie_secure</span> <span class="o">=</span> <span class="n">cookie_secure</span>
+</span><span id="SecureCookiesMiddleware.__init__-59"><a href="#SecureCookiesMiddleware.__init__-59"><span class="linenos">59</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot; The Secure field value to override on every cookie.&quot;&quot;&quot;</span>
+</span><span id="SecureCookiesMiddleware.__init__-60"><a href="#SecureCookiesMiddleware.__init__-60"><span class="linenos">60</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">cookie_httponly</span> <span class="o">=</span> <span class="n">cookie_httponly</span>
+</span><span id="SecureCookiesMiddleware.__init__-61"><a href="#SecureCookiesMiddleware.__init__-61"><span class="linenos">61</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot; The HttpOnly field value to override on every cookie.&quot;&quot;&quot;</span>
+</span><span id="SecureCookiesMiddleware.__init__-62"><a href="#SecureCookiesMiddleware.__init__-62"><span class="linenos">62</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">cookie_samesite</span> <span class="o">=</span> <span class="n">cookie_samesite</span>
+</span><span id="SecureCookiesMiddleware.__init__-63"><a href="#SecureCookiesMiddleware.__init__-63"><span class="linenos">63</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot; The SameStime field value to override on every cookie.&quot;&quot;&quot;</span>
+</span><span id="SecureCookiesMiddleware.__init__-64"><a href="#SecureCookiesMiddleware.__init__-64"><span class="linenos">64</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">excluded_cookies</span> <span class="o">=</span> <span class="n">excluded_cookies</span>
+</span><span id="SecureCookiesMiddleware.__init__-65"><a href="#SecureCookiesMiddleware.__init__-65"><span class="linenos">65</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;</span>
+</span><span id="SecureCookiesMiddleware.__init__-66"><a href="#SecureCookiesMiddleware.__init__-66"><span class="linenos">66</span></a><span class="sd">        The list of cookies to ignore when decrypting and encrypting in</span>
+</span><span id="SecureCookiesMiddleware.__init__-67"><a href="#SecureCookiesMiddleware.__init__-67"><span class="linenos">67</span></a><span class="sd">        the request --&gt; response cycle. This option is mutually exclusive with</span>
+</span><span id="SecureCookiesMiddleware.__init__-68"><a href="#SecureCookiesMiddleware.__init__-68"><span class="linenos">68</span></a><span class="sd">        `included_cookies`.</span>
+</span><span id="SecureCookiesMiddleware.__init__-69"><a href="#SecureCookiesMiddleware.__init__-69"><span class="linenos">69</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="SecureCookiesMiddleware.__init__-70"><a href="#SecureCookiesMiddleware.__init__-70"><span class="linenos">70</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">included_cookies</span> <span class="o">=</span> <span class="n">included_cookies</span>
+</span><span id="SecureCookiesMiddleware.__init__-71"><a href="#SecureCookiesMiddleware.__init__-71"><span class="linenos">71</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;</span>
+</span><span id="SecureCookiesMiddleware.__init__-72"><a href="#SecureCookiesMiddleware.__init__-72"><span class="linenos">72</span></a><span class="sd">        The list of cookies to decrypt and encrypt in the request --&gt; response cycle.</span>
+</span><span id="SecureCookiesMiddleware.__init__-73"><a href="#SecureCookiesMiddleware.__init__-73"><span class="linenos">73</span></a><span class="sd">        This option is mutually exclusive with `excluded_cookies`.</span>
+</span><span id="SecureCookiesMiddleware.__init__-74"><a href="#SecureCookiesMiddleware.__init__-74"><span class="linenos">74</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="SecureCookiesMiddleware.__init__-75"><a href="#SecureCookiesMiddleware.__init__-75"><span class="linenos">75</span></a>
+</span><span id="SecureCookiesMiddleware.__init__-76"><a href="#SecureCookiesMiddleware.__init__-76"><span class="linenos">76</span></a>        <span class="k">if</span> <span class="n">excluded_cookies</span> <span class="ow">and</span> <span class="n">included_cookies</span><span class="p">:</span>
+</span><span id="SecureCookiesMiddleware.__init__-77"><a href="#SecureCookiesMiddleware.__init__-77"><span class="linenos">77</span></a>            <span class="k">raise</span> <span class="n">BadArgumentError</span><span class="p">(</span>
+</span><span id="SecureCookiesMiddleware.__init__-78"><a href="#SecureCookiesMiddleware.__init__-78"><span class="linenos">78</span></a>                <span class="s2">&quot;It doesn&#39;t make sense to specify both excluded and included cookies.&quot;</span>
+</span><span id="SecureCookiesMiddleware.__init__-79"><a href="#SecureCookiesMiddleware.__init__-79"><span class="linenos">79</span></a>                <span class="s2">&quot; Supply either `excluded_cookies` or `included_cookies` to restrict&quot;</span>
+</span><span id="SecureCookiesMiddleware.__init__-80"><a href="#SecureCookiesMiddleware.__init__-80"><span class="linenos">80</span></a>                <span class="s2">&quot; which cookies should be secure.&quot;</span>
+</span><span id="SecureCookiesMiddleware.__init__-81"><a href="#SecureCookiesMiddleware.__init__-81"><span class="linenos">81</span></a>            <span class="p">)</span>
+</span><span id="SecureCookiesMiddleware.__init__-82"><a href="#SecureCookiesMiddleware.__init__-82"><span class="linenos">82</span></a>
+</span><span id="SecureCookiesMiddleware.__init__-83"><a href="#SecureCookiesMiddleware.__init__-83"><span class="linenos">83</span></a>        <span class="k">if</span> <span class="n">cookie_samesite</span> <span class="ow">and</span> <span class="n">cookie_samesite</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">[</span><span class="s2">&quot;strict&quot;</span><span class="p">,</span> <span class="s2">&quot;lax&quot;</span><span class="p">,</span> <span class="s2">&quot;none&quot;</span><span class="p">]:</span>
+</span><span id="SecureCookiesMiddleware.__init__-84"><a href="#SecureCookiesMiddleware.__init__-84"><span class="linenos">84</span></a>            <span class="k">raise</span> <span class="n">BadArgumentError</span><span class="p">(</span>
+</span><span id="SecureCookiesMiddleware.__init__-85"><a href="#SecureCookiesMiddleware.__init__-85"><span class="linenos">85</span></a>                <span class="s2">&quot;SameSite attribute must be either &#39;strict&#39;, &#39;lax&#39; or &#39;none&#39;&quot;</span>
+</span><span id="SecureCookiesMiddleware.__init__-86"><a href="#SecureCookiesMiddleware.__init__-86"><span class="linenos">86</span></a>            <span class="p">)</span>
 </span></pre>
           </div>
         </div>
@@ -1937,6 +2049,141 @@ <h2 id="license">License</h2>
             </p>
           </div>
         </div>
+        <div id="SecureCookiesMiddleware.set_header" class="classattr">
+          <input
+            id="SecureCookiesMiddleware.set_header-view-source"
+            class="view-source-toggle-state"
+            type="checkbox"
+            aria-hidden="true"
+            tabindex="-1"
+          />
+          <div class="attr function">
+            <span class="def">def</span>
+            <span class="name">set_header</span
+            ><span class="signature pdoc-code multiline"
+              >(<span class="param"> <span class="bp">self</span>,</span
+              ><span class="param">
+                <span class="n">request</span><span class="p">:</span>
+                <span class="n">starlette</span><span class="o">.</span
+                ><span class="n">requests</span><span class="o">.</span
+                ><span class="n">Request</span>,</span
+              ><span class="param">
+                <span class="n">header</span><span class="p">:</span>
+                <span class="nb">str</span>,</span
+              ><span class="param">
+                <span class="n">value</span><span class="p">:</span>
+                <span class="nb">str</span></span
+              ><span class="return-annotation"
+                >) -> <span class="kc">None</span>:</span
+              ></span
+            >
+
+            <label
+              class="view-source-button"
+              for="SecureCookiesMiddleware.set_header-view-source"
+              ><span>View Source</span></label
+            >
+          </div>
+          <a class="headerlink" href="#SecureCookiesMiddleware.set_header"></a>
+          <div class="pdoc-code codehilite">
+            <pre><span></span><span id="SecureCookiesMiddleware.set_header-88"><a href="#SecureCookiesMiddleware.set_header-88"><span class="linenos">88</span></a>    <span class="k">def</span> <span class="nf">set_header</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">request</span><span class="p">:</span> <span class="n">Request</span><span class="p">,</span> <span class="n">header</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="SecureCookiesMiddleware.set_header-89"><a href="#SecureCookiesMiddleware.set_header-89"><span class="linenos">89</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;</span>
+</span><span id="SecureCookiesMiddleware.set_header-90"><a href="#SecureCookiesMiddleware.set_header-90"><span class="linenos">90</span></a><span class="sd">        Adds the given Header to the available Request headers. If the Header already</span>
+</span><span id="SecureCookiesMiddleware.set_header-91"><a href="#SecureCookiesMiddleware.set_header-91"><span class="linenos">91</span></a><span class="sd">        exists, its value is overwritten.</span>
+</span><span id="SecureCookiesMiddleware.set_header-92"><a href="#SecureCookiesMiddleware.set_header-92"><span class="linenos">92</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="SecureCookiesMiddleware.set_header-93"><a href="#SecureCookiesMiddleware.set_header-93"><span class="linenos">93</span></a>        <span class="n">hkey</span> <span class="o">=</span> <span class="n">header</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">&quot;latin-1&quot;</span><span class="p">)</span>
+</span><span id="SecureCookiesMiddleware.set_header-94"><a href="#SecureCookiesMiddleware.set_header-94"><span class="linenos">94</span></a>        <span class="n">request</span><span class="o">.</span><span class="n">scope</span><span class="p">[</span><span class="s2">&quot;headers&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span>
+</span><span id="SecureCookiesMiddleware.set_header-95"><a href="#SecureCookiesMiddleware.set_header-95"><span class="linenos">95</span></a>            <span class="o">*</span><span class="p">(</span><span class="n">h</span> <span class="k">for</span> <span class="n">h</span> <span class="ow">in</span> <span class="n">request</span><span class="o">.</span><span class="n">scope</span><span class="p">[</span><span class="s2">&quot;headers&quot;</span><span class="p">]</span> <span class="k">if</span> <span class="n">h</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">!=</span> <span class="n">hkey</span><span class="p">),</span>
+</span><span id="SecureCookiesMiddleware.set_header-96"><a href="#SecureCookiesMiddleware.set_header-96"><span class="linenos">96</span></a>            <span class="p">(</span><span class="n">hkey</span><span class="p">,</span> <span class="n">value</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">&quot;latin-1&quot;</span><span class="p">)),</span>
+</span><span id="SecureCookiesMiddleware.set_header-97"><a href="#SecureCookiesMiddleware.set_header-97"><span class="linenos">97</span></a>        <span class="p">]</span>
+</span></pre>
+          </div>
+
+          <div class="docstring">
+            <p>
+              Adds the given Header to the available Request headers. If the
+              Header already exists, its value is overwritten.
+            </p>
+          </div>
+        </div>
+        <div id="SecureCookiesMiddleware.decrypt" class="classattr">
+          <input
+            id="SecureCookiesMiddleware.decrypt-view-source"
+            class="view-source-toggle-state"
+            type="checkbox"
+            aria-hidden="true"
+            tabindex="-1"
+          />
+          <div class="attr function">
+            <span class="def">def</span>
+            <span class="name">decrypt</span
+            ><span class="signature pdoc-code condensed"
+              >(<span class="param"><span class="bp">self</span>, </span
+              ><span class="param"
+                ><span class="n">value</span><span class="p">:</span>
+                <span class="nb">str</span></span
+              ><span class="return-annotation"
+                >) -> <span class="nb">str</span>:</span
+              ></span
+            >
+
+            <label
+              class="view-source-button"
+              for="SecureCookiesMiddleware.decrypt-view-source"
+              ><span>View Source</span></label
+            >
+          </div>
+          <a class="headerlink" href="#SecureCookiesMiddleware.decrypt"></a>
+          <div class="pdoc-code codehilite">
+            <pre><span></span><span id="SecureCookiesMiddleware.decrypt-99"><a href="#SecureCookiesMiddleware.decrypt-99"><span class="linenos"> 99</span></a>    <span class="k">def</span> <span class="nf">decrypt</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
+</span><span id="SecureCookiesMiddleware.decrypt-100"><a href="#SecureCookiesMiddleware.decrypt-100"><span class="linenos">100</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Decrypt the given value using any of the configured secrets.&quot;&quot;&quot;</span>
+</span><span id="SecureCookiesMiddleware.decrypt-101"><a href="#SecureCookiesMiddleware.decrypt-101"><span class="linenos">101</span></a>        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">mfernet</span><span class="o">.</span><span class="n">decrypt</span><span class="p">(</span><span class="n">value</span><span class="o">.</span><span class="n">encode</span><span class="p">())</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span>
+</span></pre>
+          </div>
+
+          <div class="docstring">
+            <p>Decrypt the given value using any of the configured secrets.</p>
+          </div>
+        </div>
+        <div id="SecureCookiesMiddleware.encrypt" class="classattr">
+          <input
+            id="SecureCookiesMiddleware.encrypt-view-source"
+            class="view-source-toggle-state"
+            type="checkbox"
+            aria-hidden="true"
+            tabindex="-1"
+          />
+          <div class="attr function">
+            <span class="def">def</span>
+            <span class="name">encrypt</span
+            ><span class="signature pdoc-code condensed"
+              >(<span class="param"><span class="bp">self</span>, </span
+              ><span class="param"
+                ><span class="n">value</span><span class="p">:</span>
+                <span class="nb">str</span></span
+              ><span class="return-annotation"
+                >) -> <span class="nb">str</span>:</span
+              ></span
+            >
+
+            <label
+              class="view-source-button"
+              for="SecureCookiesMiddleware.encrypt-view-source"
+              ><span>View Source</span></label
+            >
+          </div>
+          <a class="headerlink" href="#SecureCookiesMiddleware.encrypt"></a>
+          <div class="pdoc-code codehilite">
+            <pre><span></span><span id="SecureCookiesMiddleware.encrypt-103"><a href="#SecureCookiesMiddleware.encrypt-103"><span class="linenos">103</span></a>    <span class="k">def</span> <span class="nf">encrypt</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
+</span><span id="SecureCookiesMiddleware.encrypt-104"><a href="#SecureCookiesMiddleware.encrypt-104"><span class="linenos">104</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Encrypt the given value using the first configured secret.&quot;&quot;&quot;</span>
+</span><span id="SecureCookiesMiddleware.encrypt-105"><a href="#SecureCookiesMiddleware.encrypt-105"><span class="linenos">105</span></a>        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">mfernet</span><span class="o">.</span><span class="n">encrypt</span><span class="p">(</span><span class="n">value</span><span class="o">.</span><span class="n">encode</span><span class="p">())</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span>
+</span></pre>
+          </div>
+
+          <div class="docstring">
+            <p>Encrypt the given value using the first configured secret.</p>
+          </div>
+        </div>
         <div id="SecureCookiesMiddleware.dispatch" class="classattr">
           <input
             id="SecureCookiesMiddleware.dispatch-view-source"
@@ -1980,70 +2227,60 @@ <h2 id="license">License</h2>
           </div>
           <a class="headerlink" href="#SecureCookiesMiddleware.dispatch"></a>
           <div class="pdoc-code codehilite">
-            <pre><span></span><span id="SecureCookiesMiddleware.dispatch-87"><a href="#SecureCookiesMiddleware.dispatch-87"><span class="linenos"> 87</span></a>    <span class="k">async</span> <span class="k">def</span> <span class="nf">dispatch</span><span class="p">(</span>
-</span><span id="SecureCookiesMiddleware.dispatch-88"><a href="#SecureCookiesMiddleware.dispatch-88"><span class="linenos"> 88</span></a>        <span class="bp">self</span><span class="p">,</span> <span class="n">request</span><span class="p">:</span> <span class="n">Request</span><span class="p">,</span> <span class="n">call_next</span><span class="p">:</span> <span class="n">RequestResponseEndpoint</span>
-</span><span id="SecureCookiesMiddleware.dispatch-89"><a href="#SecureCookiesMiddleware.dispatch-89"><span class="linenos"> 89</span></a>    <span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Response</span><span class="p">:</span>
-</span><span id="SecureCookiesMiddleware.dispatch-90"><a href="#SecureCookiesMiddleware.dispatch-90"><span class="linenos"> 90</span></a>        <span class="c1"># request cookies are only passed along and mutable within the asgi scope</span>
-</span><span id="SecureCookiesMiddleware.dispatch-91"><a href="#SecureCookiesMiddleware.dispatch-91"><span class="linenos"> 91</span></a>        <span class="n">headers</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">scope</span><span class="p">[</span><span class="s2">&quot;headers&quot;</span><span class="p">]</span>
-</span><span id="SecureCookiesMiddleware.dispatch-92"><a href="#SecureCookiesMiddleware.dispatch-92"><span class="linenos"> 92</span></a>        <span class="n">raw_cookies</span> <span class="o">=</span> <span class="p">[</span><span class="n">h</span> <span class="k">for</span> <span class="n">h</span> <span class="ow">in</span> <span class="n">headers</span> <span class="k">if</span> <span class="n">h</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="sa">b</span><span class="s2">&quot;cookie&quot;</span><span class="p">]</span>
-</span><span id="SecureCookiesMiddleware.dispatch-93"><a href="#SecureCookiesMiddleware.dispatch-93"><span class="linenos"> 93</span></a>        <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">raw_cookies</span><span class="p">):</span>
-</span><span id="SecureCookiesMiddleware.dispatch-94"><a href="#SecureCookiesMiddleware.dispatch-94"><span class="linenos"> 94</span></a>            <span class="c1"># if encrypted cookies are present, remove and parse them</span>
-</span><span id="SecureCookiesMiddleware.dispatch-95"><a href="#SecureCookiesMiddleware.dispatch-95"><span class="linenos"> 95</span></a>            <span class="n">headers</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">raw_cookies</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
-</span><span id="SecureCookiesMiddleware.dispatch-96"><a href="#SecureCookiesMiddleware.dispatch-96"><span class="linenos"> 96</span></a>            <span class="n">cookies</span><span class="p">:</span> <span class="n">SimpleCookie</span><span class="p">[</span><span class="n">Any</span><span class="p">]</span> <span class="o">=</span> <span class="n">SimpleCookie</span><span class="p">(</span><span class="n">raw_cookies</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">decode</span><span class="p">())</span>
-</span><span id="SecureCookiesMiddleware.dispatch-97"><a href="#SecureCookiesMiddleware.dispatch-97"><span class="linenos"> 97</span></a>
-</span><span id="SecureCookiesMiddleware.dispatch-98"><a href="#SecureCookiesMiddleware.dispatch-98"><span class="linenos"> 98</span></a>            <span class="k">for</span> <span class="n">cookie</span><span class="p">,</span> <span class="n">morsel</span> <span class="ow">in</span> <span class="nb">list</span><span class="p">(</span><span class="n">cookies</span><span class="o">.</span><span class="n">items</span><span class="p">()):</span>
-</span><span id="SecureCookiesMiddleware.dispatch-99"><a href="#SecureCookiesMiddleware.dispatch-99"><span class="linenos"> 99</span></a>                <span class="c1"># if the cookie is included or not excluded</span>
-</span><span id="SecureCookiesMiddleware.dispatch-100"><a href="#SecureCookiesMiddleware.dispatch-100"><span class="linenos">100</span></a>                <span class="k">if</span> <span class="p">(</span>
-</span><span id="SecureCookiesMiddleware.dispatch-101"><a href="#SecureCookiesMiddleware.dispatch-101"><span class="linenos">101</span></a>                    <span class="p">(</span><span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">included_cookies</span> <span class="ow">and</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">excluded_cookies</span><span class="p">)</span>
-</span><span id="SecureCookiesMiddleware.dispatch-102"><a href="#SecureCookiesMiddleware.dispatch-102"><span class="linenos">102</span></a>                    <span class="ow">or</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">included_cookies</span> <span class="ow">and</span> <span class="n">cookie</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">included_cookies</span><span class="p">)</span>
-</span><span id="SecureCookiesMiddleware.dispatch-103"><a href="#SecureCookiesMiddleware.dispatch-103"><span class="linenos">103</span></a>                    <span class="ow">or</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">excluded_cookies</span> <span class="ow">and</span> <span class="n">cookie</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">excluded_cookies</span><span class="p">)</span>
-</span><span id="SecureCookiesMiddleware.dispatch-104"><a href="#SecureCookiesMiddleware.dispatch-104"><span class="linenos">104</span></a>                <span class="p">):</span>
-</span><span id="SecureCookiesMiddleware.dispatch-105"><a href="#SecureCookiesMiddleware.dispatch-105"><span class="linenos">105</span></a>                    <span class="k">try</span><span class="p">:</span>
-</span><span id="SecureCookiesMiddleware.dispatch-106"><a href="#SecureCookiesMiddleware.dispatch-106"><span class="linenos">106</span></a>                        <span class="c1"># try to decrypt the token. if you can, then it&#39;s already</span>
-</span><span id="SecureCookiesMiddleware.dispatch-107"><a href="#SecureCookiesMiddleware.dispatch-107"><span class="linenos">107</span></a>                        <span class="c1"># encrypted and can be passed along</span>
-</span><span id="SecureCookiesMiddleware.dispatch-108"><a href="#SecureCookiesMiddleware.dispatch-108"><span class="linenos">108</span></a>                        <span class="n">cookies</span><span class="p">[</span><span class="n">cookie</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">mfernet</span><span class="o">.</span><span class="n">decrypt</span><span class="p">(</span>
-</span><span id="SecureCookiesMiddleware.dispatch-109"><a href="#SecureCookiesMiddleware.dispatch-109"><span class="linenos">109</span></a>                            <span class="n">morsel</span><span class="o">.</span><span class="n">value</span><span class="o">.</span><span class="n">encode</span><span class="p">()</span>
-</span><span id="SecureCookiesMiddleware.dispatch-110"><a href="#SecureCookiesMiddleware.dispatch-110"><span class="linenos">110</span></a>                        <span class="p">)</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span>
-</span><span id="SecureCookiesMiddleware.dispatch-111"><a href="#SecureCookiesMiddleware.dispatch-111"><span class="linenos">111</span></a>                    <span class="k">except</span> <span class="n">InvalidToken</span><span class="p">:</span>
-</span><span id="SecureCookiesMiddleware.dispatch-112"><a href="#SecureCookiesMiddleware.dispatch-112"><span class="linenos">112</span></a>                        <span class="c1"># delete invalid or unencrypted cookies if enabled</span>
-</span><span id="SecureCookiesMiddleware.dispatch-113"><a href="#SecureCookiesMiddleware.dispatch-113"><span class="linenos">113</span></a>                        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">discard_invalid</span><span class="p">:</span>
-</span><span id="SecureCookiesMiddleware.dispatch-114"><a href="#SecureCookiesMiddleware.dispatch-114"><span class="linenos">114</span></a>                            <span class="k">del</span> <span class="n">cookies</span><span class="p">[</span><span class="n">cookie</span><span class="p">]</span>
-</span><span id="SecureCookiesMiddleware.dispatch-115"><a href="#SecureCookiesMiddleware.dispatch-115"><span class="linenos">115</span></a>
-</span><span id="SecureCookiesMiddleware.dispatch-116"><a href="#SecureCookiesMiddleware.dispatch-116"><span class="linenos">116</span></a>            <span class="c1"># serialize and append the decrypted cookies to the asgi scope headers</span>
-</span><span id="SecureCookiesMiddleware.dispatch-117"><a href="#SecureCookiesMiddleware.dispatch-117"><span class="linenos">117</span></a>            <span class="n">new_cookie</span> <span class="o">=</span> <span class="p">(</span>
-</span><span id="SecureCookiesMiddleware.dispatch-118"><a href="#SecureCookiesMiddleware.dispatch-118"><span class="linenos">118</span></a>                <span class="sa">b</span><span class="s2">&quot;cookie&quot;</span><span class="p">,</span>
-</span><span id="SecureCookiesMiddleware.dispatch-119"><a href="#SecureCookiesMiddleware.dispatch-119"><span class="linenos">119</span></a>                <span class="n">cookies</span><span class="o">.</span><span class="n">output</span><span class="p">(</span><span class="n">header</span><span class="o">=</span><span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="n">sep</span><span class="o">=</span><span class="s2">&quot;;&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span><span class="o">.</span><span class="n">encode</span><span class="p">(),</span>
-</span><span id="SecureCookiesMiddleware.dispatch-120"><a href="#SecureCookiesMiddleware.dispatch-120"><span class="linenos">120</span></a>            <span class="p">)</span>
-</span><span id="SecureCookiesMiddleware.dispatch-121"><a href="#SecureCookiesMiddleware.dispatch-121"><span class="linenos">121</span></a>            <span class="n">headers</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">new_cookie</span><span class="p">)</span>
-</span><span id="SecureCookiesMiddleware.dispatch-122"><a href="#SecureCookiesMiddleware.dispatch-122"><span class="linenos">122</span></a>
-</span><span id="SecureCookiesMiddleware.dispatch-123"><a href="#SecureCookiesMiddleware.dispatch-123"><span class="linenos">123</span></a>        <span class="c1"># propagate the modified request</span>
-</span><span id="SecureCookiesMiddleware.dispatch-124"><a href="#SecureCookiesMiddleware.dispatch-124"><span class="linenos">124</span></a>        <span class="n">response</span><span class="p">:</span> <span class="n">Response</span> <span class="o">=</span> <span class="k">await</span> <span class="n">call_next</span><span class="p">(</span><span class="n">request</span><span class="p">)</span>
-</span><span id="SecureCookiesMiddleware.dispatch-125"><a href="#SecureCookiesMiddleware.dispatch-125"><span class="linenos">125</span></a>
-</span><span id="SecureCookiesMiddleware.dispatch-126"><a href="#SecureCookiesMiddleware.dispatch-126"><span class="linenos">126</span></a>        <span class="c1"># for every cookie in the response</span>
-</span><span id="SecureCookiesMiddleware.dispatch-127"><a href="#SecureCookiesMiddleware.dispatch-127"><span class="linenos">127</span></a>        <span class="k">for</span> <span class="n">raw_cookie</span> <span class="ow">in</span> <span class="n">response</span><span class="o">.</span><span class="n">headers</span><span class="o">.</span><span class="n">getlist</span><span class="p">(</span><span class="s2">&quot;set-cookie&quot;</span><span class="p">):</span>
-</span><span id="SecureCookiesMiddleware.dispatch-128"><a href="#SecureCookiesMiddleware.dispatch-128"><span class="linenos">128</span></a>            <span class="c1"># decode it</span>
-</span><span id="SecureCookiesMiddleware.dispatch-129"><a href="#SecureCookiesMiddleware.dispatch-129"><span class="linenos">129</span></a>            <span class="n">ncookie</span><span class="p">:</span> <span class="n">SimpleCookie</span><span class="p">[</span><span class="n">Any</span><span class="p">]</span> <span class="o">=</span> <span class="n">SimpleCookie</span><span class="p">(</span><span class="n">raw_cookie</span><span class="p">)</span>
-</span><span id="SecureCookiesMiddleware.dispatch-130"><a href="#SecureCookiesMiddleware.dispatch-130"><span class="linenos">130</span></a>            <span class="n">key</span> <span class="o">=</span> <span class="p">[</span><span class="o">*</span><span class="n">ncookie</span><span class="o">.</span><span class="n">keys</span><span class="p">()][</span><span class="mi">0</span><span class="p">]</span>
-</span><span id="SecureCookiesMiddleware.dispatch-131"><a href="#SecureCookiesMiddleware.dispatch-131"><span class="linenos">131</span></a>
-</span><span id="SecureCookiesMiddleware.dispatch-132"><a href="#SecureCookiesMiddleware.dispatch-132"><span class="linenos">132</span></a>            <span class="c1"># if the cookie is included or not excluded</span>
-</span><span id="SecureCookiesMiddleware.dispatch-133"><a href="#SecureCookiesMiddleware.dispatch-133"><span class="linenos">133</span></a>            <span class="k">if</span> <span class="p">(</span>
-</span><span id="SecureCookiesMiddleware.dispatch-134"><a href="#SecureCookiesMiddleware.dispatch-134"><span class="linenos">134</span></a>                <span class="p">(</span><span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">included_cookies</span> <span class="ow">and</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">excluded_cookies</span><span class="p">)</span>
-</span><span id="SecureCookiesMiddleware.dispatch-135"><a href="#SecureCookiesMiddleware.dispatch-135"><span class="linenos">135</span></a>                <span class="ow">or</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">included_cookies</span> <span class="ow">and</span> <span class="n">key</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">included_cookies</span><span class="p">)</span>
-</span><span id="SecureCookiesMiddleware.dispatch-136"><a href="#SecureCookiesMiddleware.dispatch-136"><span class="linenos">136</span></a>                <span class="ow">or</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">excluded_cookies</span> <span class="ow">and</span> <span class="n">key</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">excluded_cookies</span><span class="p">)</span>
-</span><span id="SecureCookiesMiddleware.dispatch-137"><a href="#SecureCookiesMiddleware.dispatch-137"><span class="linenos">137</span></a>            <span class="p">):</span>
-</span><span id="SecureCookiesMiddleware.dispatch-138"><a href="#SecureCookiesMiddleware.dispatch-138"><span class="linenos">138</span></a>                <span class="c1"># create a new encrypted cookie with the desired attributes</span>
-</span><span id="SecureCookiesMiddleware.dispatch-139"><a href="#SecureCookiesMiddleware.dispatch-139"><span class="linenos">139</span></a>                <span class="n">response</span><span class="o">.</span><span class="n">set_cookie</span><span class="p">(</span>
-</span><span id="SecureCookiesMiddleware.dispatch-140"><a href="#SecureCookiesMiddleware.dispatch-140"><span class="linenos">140</span></a>                    <span class="n">key</span><span class="p">,</span>
-</span><span id="SecureCookiesMiddleware.dispatch-141"><a href="#SecureCookiesMiddleware.dispatch-141"><span class="linenos">141</span></a>                    <span class="n">value</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">mfernet</span><span class="o">.</span><span class="n">encrypt</span><span class="p">(</span><span class="n">ncookie</span><span class="p">[</span><span class="n">key</span><span class="p">]</span><span class="o">.</span><span class="n">value</span><span class="o">.</span><span class="n">encode</span><span class="p">())</span><span class="o">.</span><span class="n">decode</span><span class="p">(),</span>
-</span><span id="SecureCookiesMiddleware.dispatch-142"><a href="#SecureCookiesMiddleware.dispatch-142"><span class="linenos">142</span></a>                    <span class="n">path</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">cookie_path</span> <span class="ow">or</span> <span class="n">ncookie</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="s2">&quot;path&quot;</span><span class="p">],</span>
-</span><span id="SecureCookiesMiddleware.dispatch-143"><a href="#SecureCookiesMiddleware.dispatch-143"><span class="linenos">143</span></a>                    <span class="n">domain</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">cookie_domain</span> <span class="ow">or</span> <span class="n">ncookie</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="s2">&quot;domain&quot;</span><span class="p">],</span>
-</span><span id="SecureCookiesMiddleware.dispatch-144"><a href="#SecureCookiesMiddleware.dispatch-144"><span class="linenos">144</span></a>                    <span class="n">secure</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">cookie_secure</span> <span class="ow">or</span> <span class="n">ncookie</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="s2">&quot;secure&quot;</span><span class="p">],</span>
-</span><span id="SecureCookiesMiddleware.dispatch-145"><a href="#SecureCookiesMiddleware.dispatch-145"><span class="linenos">145</span></a>                    <span class="n">httponly</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">cookie_httponly</span> <span class="ow">or</span> <span class="n">ncookie</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="s2">&quot;httponly&quot;</span><span class="p">],</span>
-</span><span id="SecureCookiesMiddleware.dispatch-146"><a href="#SecureCookiesMiddleware.dispatch-146"><span class="linenos">146</span></a>                    <span class="n">samesite</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">cookie_samesite</span>
-</span><span id="SecureCookiesMiddleware.dispatch-147"><a href="#SecureCookiesMiddleware.dispatch-147"><span class="linenos">147</span></a>                    <span class="ow">or</span> <span class="n">ncookie</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="s2">&quot;samesite&quot;</span><span class="p">],</span>  <span class="c1"># type:ignore [arg-type]</span>
-</span><span id="SecureCookiesMiddleware.dispatch-148"><a href="#SecureCookiesMiddleware.dispatch-148"><span class="linenos">148</span></a>                <span class="p">)</span>
-</span><span id="SecureCookiesMiddleware.dispatch-149"><a href="#SecureCookiesMiddleware.dispatch-149"><span class="linenos">149</span></a>
-</span><span id="SecureCookiesMiddleware.dispatch-150"><a href="#SecureCookiesMiddleware.dispatch-150"><span class="linenos">150</span></a>        <span class="k">return</span> <span class="n">response</span>
+            <pre><span></span><span id="SecureCookiesMiddleware.dispatch-107"><a href="#SecureCookiesMiddleware.dispatch-107"><span class="linenos">107</span></a>    <span class="k">async</span> <span class="k">def</span> <span class="nf">dispatch</span><span class="p">(</span>
+</span><span id="SecureCookiesMiddleware.dispatch-108"><a href="#SecureCookiesMiddleware.dispatch-108"><span class="linenos">108</span></a>        <span class="bp">self</span><span class="p">,</span> <span class="n">request</span><span class="p">:</span> <span class="n">Request</span><span class="p">,</span> <span class="n">call_next</span><span class="p">:</span> <span class="n">RequestResponseEndpoint</span>
+</span><span id="SecureCookiesMiddleware.dispatch-109"><a href="#SecureCookiesMiddleware.dispatch-109"><span class="linenos">109</span></a>    <span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Response</span><span class="p">:</span>
+</span><span id="SecureCookiesMiddleware.dispatch-110"><a href="#SecureCookiesMiddleware.dispatch-110"><span class="linenos">110</span></a>        <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">cookies</span><span class="p">):</span>
+</span><span id="SecureCookiesMiddleware.dispatch-111"><a href="#SecureCookiesMiddleware.dispatch-111"><span class="linenos">111</span></a>            <span class="n">cookies</span><span class="p">:</span> <span class="n">SimpleCookie</span><span class="p">[</span><span class="n">Any</span><span class="p">]</span> <span class="o">=</span> <span class="n">SimpleCookie</span><span class="p">()</span>
+</span><span id="SecureCookiesMiddleware.dispatch-112"><a href="#SecureCookiesMiddleware.dispatch-112"><span class="linenos">112</span></a>            <span class="k">for</span> <span class="n">cookie</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">request</span><span class="o">.</span><span class="n">cookies</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
+</span><span id="SecureCookiesMiddleware.dispatch-113"><a href="#SecureCookiesMiddleware.dispatch-113"><span class="linenos">113</span></a>                <span class="c1"># if the cookie is included or not excluded</span>
+</span><span id="SecureCookiesMiddleware.dispatch-114"><a href="#SecureCookiesMiddleware.dispatch-114"><span class="linenos">114</span></a>                <span class="k">if</span> <span class="p">(</span>
+</span><span id="SecureCookiesMiddleware.dispatch-115"><a href="#SecureCookiesMiddleware.dispatch-115"><span class="linenos">115</span></a>                    <span class="p">(</span><span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">included_cookies</span> <span class="ow">and</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">excluded_cookies</span><span class="p">)</span>
+</span><span id="SecureCookiesMiddleware.dispatch-116"><a href="#SecureCookiesMiddleware.dispatch-116"><span class="linenos">116</span></a>                    <span class="ow">or</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">included_cookies</span> <span class="ow">and</span> <span class="n">cookie</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">included_cookies</span><span class="p">)</span>
+</span><span id="SecureCookiesMiddleware.dispatch-117"><a href="#SecureCookiesMiddleware.dispatch-117"><span class="linenos">117</span></a>                    <span class="ow">or</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">excluded_cookies</span> <span class="ow">and</span> <span class="n">cookie</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">excluded_cookies</span><span class="p">)</span>
+</span><span id="SecureCookiesMiddleware.dispatch-118"><a href="#SecureCookiesMiddleware.dispatch-118"><span class="linenos">118</span></a>                <span class="p">):</span>
+</span><span id="SecureCookiesMiddleware.dispatch-119"><a href="#SecureCookiesMiddleware.dispatch-119"><span class="linenos">119</span></a>                    <span class="k">try</span><span class="p">:</span>
+</span><span id="SecureCookiesMiddleware.dispatch-120"><a href="#SecureCookiesMiddleware.dispatch-120"><span class="linenos">120</span></a>                        <span class="c1"># try to decrypt the cookie and pass it along</span>
+</span><span id="SecureCookiesMiddleware.dispatch-121"><a href="#SecureCookiesMiddleware.dispatch-121"><span class="linenos">121</span></a>                        <span class="n">cookies</span><span class="p">[</span><span class="n">cookie</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">decrypt</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
+</span><span id="SecureCookiesMiddleware.dispatch-122"><a href="#SecureCookiesMiddleware.dispatch-122"><span class="linenos">122</span></a>                    <span class="k">except</span> <span class="n">InvalidToken</span><span class="p">:</span>
+</span><span id="SecureCookiesMiddleware.dispatch-123"><a href="#SecureCookiesMiddleware.dispatch-123"><span class="linenos">123</span></a>                        <span class="c1"># delete invalid or unencrypted cookies unless disabled</span>
+</span><span id="SecureCookiesMiddleware.dispatch-124"><a href="#SecureCookiesMiddleware.dispatch-124"><span class="linenos">124</span></a>                        <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">discard_invalid</span><span class="p">:</span>
+</span><span id="SecureCookiesMiddleware.dispatch-125"><a href="#SecureCookiesMiddleware.dispatch-125"><span class="linenos">125</span></a>                            <span class="n">cookies</span><span class="p">[</span><span class="n">cookie</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span>
+</span><span id="SecureCookiesMiddleware.dispatch-126"><a href="#SecureCookiesMiddleware.dispatch-126"><span class="linenos">126</span></a>
+</span><span id="SecureCookiesMiddleware.dispatch-127"><a href="#SecureCookiesMiddleware.dispatch-127"><span class="linenos">127</span></a>            <span class="c1"># serialize and set the decrypted cookies to the asgi scope headers</span>
+</span><span id="SecureCookiesMiddleware.dispatch-128"><a href="#SecureCookiesMiddleware.dispatch-128"><span class="linenos">128</span></a>            <span class="c1"># we have to modify the scope directly because request objects are not</span>
+</span><span id="SecureCookiesMiddleware.dispatch-129"><a href="#SecureCookiesMiddleware.dispatch-129"><span class="linenos">129</span></a>            <span class="c1"># passed between ASGI applications / middleware.</span>
+</span><span id="SecureCookiesMiddleware.dispatch-130"><a href="#SecureCookiesMiddleware.dispatch-130"><span class="linenos">130</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">set_header</span><span class="p">(</span>
+</span><span id="SecureCookiesMiddleware.dispatch-131"><a href="#SecureCookiesMiddleware.dispatch-131"><span class="linenos">131</span></a>                <span class="n">request</span><span class="p">,</span> <span class="s2">&quot;cookie&quot;</span><span class="p">,</span> <span class="n">cookies</span><span class="o">.</span><span class="n">output</span><span class="p">(</span><span class="n">header</span><span class="o">=</span><span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="n">sep</span><span class="o">=</span><span class="s2">&quot;;&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
+</span><span id="SecureCookiesMiddleware.dispatch-132"><a href="#SecureCookiesMiddleware.dispatch-132"><span class="linenos">132</span></a>            <span class="p">)</span>
+</span><span id="SecureCookiesMiddleware.dispatch-133"><a href="#SecureCookiesMiddleware.dispatch-133"><span class="linenos">133</span></a>
+</span><span id="SecureCookiesMiddleware.dispatch-134"><a href="#SecureCookiesMiddleware.dispatch-134"><span class="linenos">134</span></a>        <span class="c1"># propagate the modified request</span>
+</span><span id="SecureCookiesMiddleware.dispatch-135"><a href="#SecureCookiesMiddleware.dispatch-135"><span class="linenos">135</span></a>        <span class="n">response</span><span class="p">:</span> <span class="n">Response</span> <span class="o">=</span> <span class="k">await</span> <span class="n">call_next</span><span class="p">(</span><span class="n">request</span><span class="p">)</span>
+</span><span id="SecureCookiesMiddleware.dispatch-136"><a href="#SecureCookiesMiddleware.dispatch-136"><span class="linenos">136</span></a>
+</span><span id="SecureCookiesMiddleware.dispatch-137"><a href="#SecureCookiesMiddleware.dispatch-137"><span class="linenos">137</span></a>        <span class="c1"># for every cookie in the response</span>
+</span><span id="SecureCookiesMiddleware.dispatch-138"><a href="#SecureCookiesMiddleware.dispatch-138"><span class="linenos">138</span></a>        <span class="k">for</span> <span class="n">cookie</span> <span class="ow">in</span> <span class="n">response</span><span class="o">.</span><span class="n">headers</span><span class="o">.</span><span class="n">getlist</span><span class="p">(</span><span class="s2">&quot;set-cookie&quot;</span><span class="p">):</span>
+</span><span id="SecureCookiesMiddleware.dispatch-139"><a href="#SecureCookiesMiddleware.dispatch-139"><span class="linenos">139</span></a>            <span class="c1"># decode it</span>
+</span><span id="SecureCookiesMiddleware.dispatch-140"><a href="#SecureCookiesMiddleware.dispatch-140"><span class="linenos">140</span></a>            <span class="n">ncookie</span><span class="p">:</span> <span class="n">SimpleCookie</span><span class="p">[</span><span class="n">Any</span><span class="p">]</span> <span class="o">=</span> <span class="n">SimpleCookie</span><span class="p">(</span><span class="n">cookie</span><span class="p">)</span>
+</span><span id="SecureCookiesMiddleware.dispatch-141"><a href="#SecureCookiesMiddleware.dispatch-141"><span class="linenos">141</span></a>            <span class="n">key</span> <span class="o">=</span> <span class="p">[</span><span class="o">*</span><span class="n">ncookie</span><span class="o">.</span><span class="n">keys</span><span class="p">()][</span><span class="mi">0</span><span class="p">]</span>
+</span><span id="SecureCookiesMiddleware.dispatch-142"><a href="#SecureCookiesMiddleware.dispatch-142"><span class="linenos">142</span></a>
+</span><span id="SecureCookiesMiddleware.dispatch-143"><a href="#SecureCookiesMiddleware.dispatch-143"><span class="linenos">143</span></a>            <span class="c1"># if the cookie is included or not excluded</span>
+</span><span id="SecureCookiesMiddleware.dispatch-144"><a href="#SecureCookiesMiddleware.dispatch-144"><span class="linenos">144</span></a>            <span class="k">if</span> <span class="p">(</span>
+</span><span id="SecureCookiesMiddleware.dispatch-145"><a href="#SecureCookiesMiddleware.dispatch-145"><span class="linenos">145</span></a>                <span class="p">(</span><span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">included_cookies</span> <span class="ow">and</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">excluded_cookies</span><span class="p">)</span>
+</span><span id="SecureCookiesMiddleware.dispatch-146"><a href="#SecureCookiesMiddleware.dispatch-146"><span class="linenos">146</span></a>                <span class="ow">or</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">included_cookies</span> <span class="ow">and</span> <span class="n">key</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">included_cookies</span><span class="p">)</span>
+</span><span id="SecureCookiesMiddleware.dispatch-147"><a href="#SecureCookiesMiddleware.dispatch-147"><span class="linenos">147</span></a>                <span class="ow">or</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">excluded_cookies</span> <span class="ow">and</span> <span class="n">key</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">excluded_cookies</span><span class="p">)</span>
+</span><span id="SecureCookiesMiddleware.dispatch-148"><a href="#SecureCookiesMiddleware.dispatch-148"><span class="linenos">148</span></a>            <span class="p">):</span>
+</span><span id="SecureCookiesMiddleware.dispatch-149"><a href="#SecureCookiesMiddleware.dispatch-149"><span class="linenos">149</span></a>                <span class="c1"># create a new encrypted cookie with the desired attributes</span>
+</span><span id="SecureCookiesMiddleware.dispatch-150"><a href="#SecureCookiesMiddleware.dispatch-150"><span class="linenos">150</span></a>                <span class="n">response</span><span class="o">.</span><span class="n">set_cookie</span><span class="p">(</span>
+</span><span id="SecureCookiesMiddleware.dispatch-151"><a href="#SecureCookiesMiddleware.dispatch-151"><span class="linenos">151</span></a>                    <span class="n">key</span><span class="p">,</span>
+</span><span id="SecureCookiesMiddleware.dispatch-152"><a href="#SecureCookiesMiddleware.dispatch-152"><span class="linenos">152</span></a>                    <span class="n">value</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">encrypt</span><span class="p">(</span><span class="n">ncookie</span><span class="p">[</span><span class="n">key</span><span class="p">]</span><span class="o">.</span><span class="n">value</span><span class="p">),</span>
+</span><span id="SecureCookiesMiddleware.dispatch-153"><a href="#SecureCookiesMiddleware.dispatch-153"><span class="linenos">153</span></a>                    <span class="n">path</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">cookie_path</span> <span class="ow">or</span> <span class="n">ncookie</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="s2">&quot;path&quot;</span><span class="p">],</span>
+</span><span id="SecureCookiesMiddleware.dispatch-154"><a href="#SecureCookiesMiddleware.dispatch-154"><span class="linenos">154</span></a>                    <span class="n">domain</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">cookie_domain</span> <span class="ow">or</span> <span class="n">ncookie</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="s2">&quot;domain&quot;</span><span class="p">],</span>
+</span><span id="SecureCookiesMiddleware.dispatch-155"><a href="#SecureCookiesMiddleware.dispatch-155"><span class="linenos">155</span></a>                    <span class="n">secure</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">cookie_secure</span> <span class="ow">or</span> <span class="n">ncookie</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="s2">&quot;secure&quot;</span><span class="p">],</span>
+</span><span id="SecureCookiesMiddleware.dispatch-156"><a href="#SecureCookiesMiddleware.dispatch-156"><span class="linenos">156</span></a>                    <span class="n">httponly</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">cookie_httponly</span> <span class="ow">or</span> <span class="n">ncookie</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="s2">&quot;httponly&quot;</span><span class="p">],</span>
+</span><span id="SecureCookiesMiddleware.dispatch-157"><a href="#SecureCookiesMiddleware.dispatch-157"><span class="linenos">157</span></a>                    <span class="n">samesite</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">cookie_samesite</span> <span class="ow">or</span> <span class="n">ncookie</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="s2">&quot;samesite&quot;</span><span class="p">],</span>
+</span><span id="SecureCookiesMiddleware.dispatch-158"><a href="#SecureCookiesMiddleware.dispatch-158"><span class="linenos">158</span></a>                <span class="p">)</span>
+</span><span id="SecureCookiesMiddleware.dispatch-159"><a href="#SecureCookiesMiddleware.dispatch-159"><span class="linenos">159</span></a>
+</span><span id="SecureCookiesMiddleware.dispatch-160"><a href="#SecureCookiesMiddleware.dispatch-160"><span class="linenos">160</span></a>        <span class="k">return</span> <span class="n">response</span>
 </span></pre>
           </div>
         </div>
@@ -2068,11 +2305,11 @@ <h2 id="license">License</h2>
         </div>
         <a class="headerlink" href="#BadArgumentError"></a>
         <div class="pdoc-code codehilite">
-          <pre><span></span><span id="BadArgumentError-12"><a href="#BadArgumentError-12"><span class="linenos">12</span></a><span class="k">class</span> <span class="nc">BadArgumentError</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
-</span><span id="BadArgumentError-13"><a href="#BadArgumentError-13"><span class="linenos">13</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;</span>
-</span><span id="BadArgumentError-14"><a href="#BadArgumentError-14"><span class="linenos">14</span></a><span class="sd">    Generic error arguments with invalid values, or combinations of conflicting</span>
-</span><span id="BadArgumentError-15"><a href="#BadArgumentError-15"><span class="linenos">15</span></a><span class="sd">    arguments.</span>
-</span><span id="BadArgumentError-16"><a href="#BadArgumentError-16"><span class="linenos">16</span></a><span class="sd">    &quot;&quot;&quot;</span>
+          <pre><span></span><span id="BadArgumentError-13"><a href="#BadArgumentError-13"><span class="linenos">13</span></a><span class="k">class</span> <span class="nc">BadArgumentError</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
+</span><span id="BadArgumentError-14"><a href="#BadArgumentError-14"><span class="linenos">14</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;</span>
+</span><span id="BadArgumentError-15"><a href="#BadArgumentError-15"><span class="linenos">15</span></a><span class="sd">    Generic error arguments with invalid values, or combinations of conflicting</span>
+</span><span id="BadArgumentError-16"><a href="#BadArgumentError-16"><span class="linenos">16</span></a><span class="sd">    arguments.</span>
+</span><span id="BadArgumentError-17"><a href="#BadArgumentError-17"><span class="linenos">17</span></a><span class="sd">    &quot;&quot;&quot;</span>
 </span></pre>
         </div>
 
diff --git a/docs/securecookies/extras.html b/docs/securecookies/extras.html
new file mode 100644
index 0000000..ea3dabc
--- /dev/null
+++ b/docs/securecookies/extras.html
@@ -0,0 +1,1304 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="utf-8" />
+    <meta name="viewport" content="width=device-width, initial-scale=1" />
+    <meta name="generator" content="pdoc 13.1.1" />
+    <title>securecookies.extras API documentation</title>
+
+    <style>
+      /*! * Bootstrap Reboot v5.0.0 (https://getbootstrap.com/) * Copyright 2011-2021 The Bootstrap Authors * Copyright 2011-2021 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) */
+      *,
+      ::after,
+      ::before {
+        box-sizing: border-box;
+      }
+      @media (prefers-reduced-motion: no-preference) {
+        :root {
+          scroll-behavior: smooth;
+        }
+      }
+      body {
+        margin: 0;
+        font-family: system-ui, -apple-system, "Segoe UI", Roboto,
+          "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif,
+          "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
+          "Noto Color Emoji";
+        font-size: 1rem;
+        font-weight: 400;
+        line-height: 1.5;
+        color: #212529;
+        background-color: #fff;
+        -webkit-text-size-adjust: 100%;
+        -webkit-tap-highlight-color: transparent;
+      }
+      hr {
+        margin: 1rem 0;
+        color: inherit;
+        background-color: currentColor;
+        border: 0;
+        opacity: 0.25;
+      }
+      hr:not([size]) {
+        height: 1px;
+      }
+      h1,
+      h2,
+      h3,
+      h4,
+      h5,
+      h6 {
+        margin-top: 0;
+        margin-bottom: 0.5rem;
+        font-weight: 500;
+        line-height: 1.2;
+      }
+      h1 {
+        font-size: calc(1.375rem + 1.5vw);
+      }
+      @media (min-width: 1200px) {
+        h1 {
+          font-size: 2.5rem;
+        }
+      }
+      h2 {
+        font-size: calc(1.325rem + 0.9vw);
+      }
+      @media (min-width: 1200px) {
+        h2 {
+          font-size: 2rem;
+        }
+      }
+      h3 {
+        font-size: calc(1.3rem + 0.6vw);
+      }
+      @media (min-width: 1200px) {
+        h3 {
+          font-size: 1.75rem;
+        }
+      }
+      h4 {
+        font-size: calc(1.275rem + 0.3vw);
+      }
+      @media (min-width: 1200px) {
+        h4 {
+          font-size: 1.5rem;
+        }
+      }
+      h5 {
+        font-size: 1.25rem;
+      }
+      h6 {
+        font-size: 1rem;
+      }
+      p {
+        margin-top: 0;
+        margin-bottom: 1rem;
+      }
+      abbr[data-bs-original-title],
+      abbr[title] {
+        -webkit-text-decoration: underline dotted;
+        text-decoration: underline dotted;
+        cursor: help;
+        -webkit-text-decoration-skip-ink: none;
+        text-decoration-skip-ink: none;
+      }
+      address {
+        margin-bottom: 1rem;
+        font-style: normal;
+        line-height: inherit;
+      }
+      ol,
+      ul {
+        padding-left: 2rem;
+      }
+      dl,
+      ol,
+      ul {
+        margin-top: 0;
+        margin-bottom: 1rem;
+      }
+      ol ol,
+      ol ul,
+      ul ol,
+      ul ul {
+        margin-bottom: 0;
+      }
+      dt {
+        font-weight: 700;
+      }
+      dd {
+        margin-bottom: 0.5rem;
+        margin-left: 0;
+      }
+      blockquote {
+        margin: 0 0 1rem;
+      }
+      b,
+      strong {
+        font-weight: bolder;
+      }
+      small {
+        font-size: 0.875em;
+      }
+      mark {
+        padding: 0.2em;
+        background-color: #fcf8e3;
+      }
+      sub,
+      sup {
+        position: relative;
+        font-size: 0.75em;
+        line-height: 0;
+        vertical-align: baseline;
+      }
+      sub {
+        bottom: -0.25em;
+      }
+      sup {
+        top: -0.5em;
+      }
+      a {
+        color: #0d6efd;
+        text-decoration: underline;
+      }
+      a:hover {
+        color: #0a58ca;
+      }
+      a:not([href]):not([class]),
+      a:not([href]):not([class]):hover {
+        color: inherit;
+        text-decoration: none;
+      }
+      code,
+      kbd,
+      pre,
+      samp {
+        font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
+          "Courier New", monospace;
+        font-size: 1em;
+        direction: ltr;
+        unicode-bidi: bidi-override;
+      }
+      pre {
+        display: block;
+        margin-top: 0;
+        margin-bottom: 1rem;
+        overflow: auto;
+        font-size: 0.875em;
+      }
+      pre code {
+        font-size: inherit;
+        color: inherit;
+        word-break: normal;
+      }
+      code {
+        font-size: 0.875em;
+        color: #d63384;
+        word-wrap: break-word;
+      }
+      a > code {
+        color: inherit;
+      }
+      kbd {
+        padding: 0.2rem 0.4rem;
+        font-size: 0.875em;
+        color: #fff;
+        background-color: #212529;
+        border-radius: 0.2rem;
+      }
+      kbd kbd {
+        padding: 0;
+        font-size: 1em;
+        font-weight: 700;
+      }
+      figure {
+        margin: 0 0 1rem;
+      }
+      img,
+      svg {
+        vertical-align: middle;
+      }
+      table {
+        caption-side: bottom;
+        border-collapse: collapse;
+      }
+      caption {
+        padding-top: 0.5rem;
+        padding-bottom: 0.5rem;
+        color: #6c757d;
+        text-align: left;
+      }
+      th {
+        text-align: inherit;
+        text-align: -webkit-match-parent;
+      }
+      tbody,
+      td,
+      tfoot,
+      th,
+      thead,
+      tr {
+        border-color: inherit;
+        border-style: solid;
+        border-width: 0;
+      }
+      label {
+        display: inline-block;
+      }
+      button {
+        border-radius: 0;
+      }
+      button:focus:not(:focus-visible) {
+        outline: 0;
+      }
+      button,
+      input,
+      optgroup,
+      select,
+      textarea {
+        margin: 0;
+        font-family: inherit;
+        font-size: inherit;
+        line-height: inherit;
+      }
+      button,
+      select {
+        text-transform: none;
+      }
+      [role="button"] {
+        cursor: pointer;
+      }
+      select {
+        word-wrap: normal;
+      }
+      select:disabled {
+        opacity: 1;
+      }
+      [list]::-webkit-calendar-picker-indicator {
+        display: none;
+      }
+      [type="button"],
+      [type="reset"],
+      [type="submit"],
+      button {
+        -webkit-appearance: button;
+      }
+      [type="button"]:not(:disabled),
+      [type="reset"]:not(:disabled),
+      [type="submit"]:not(:disabled),
+      button:not(:disabled) {
+        cursor: pointer;
+      }
+      ::-moz-focus-inner {
+        padding: 0;
+        border-style: none;
+      }
+      textarea {
+        resize: vertical;
+      }
+      fieldset {
+        min-width: 0;
+        padding: 0;
+        margin: 0;
+        border: 0;
+      }
+      legend {
+        float: left;
+        width: 100%;
+        padding: 0;
+        margin-bottom: 0.5rem;
+        font-size: calc(1.275rem + 0.3vw);
+        line-height: inherit;
+      }
+      @media (min-width: 1200px) {
+        legend {
+          font-size: 1.5rem;
+        }
+      }
+      legend + * {
+        clear: left;
+      }
+      ::-webkit-datetime-edit-day-field,
+      ::-webkit-datetime-edit-fields-wrapper,
+      ::-webkit-datetime-edit-hour-field,
+      ::-webkit-datetime-edit-minute,
+      ::-webkit-datetime-edit-month-field,
+      ::-webkit-datetime-edit-text,
+      ::-webkit-datetime-edit-year-field {
+        padding: 0;
+      }
+      ::-webkit-inner-spin-button {
+        height: auto;
+      }
+      [type="search"] {
+        outline-offset: -2px;
+        -webkit-appearance: textfield;
+      }
+      ::-webkit-search-decoration {
+        -webkit-appearance: none;
+      }
+      ::-webkit-color-swatch-wrapper {
+        padding: 0;
+      }
+      ::file-selector-button {
+        font: inherit;
+      }
+      ::-webkit-file-upload-button {
+        font: inherit;
+        -webkit-appearance: button;
+      }
+      output {
+        display: inline-block;
+      }
+      iframe {
+        border: 0;
+      }
+      summary {
+        display: list-item;
+        cursor: pointer;
+      }
+      progress {
+        vertical-align: baseline;
+      }
+      [hidden] {
+        display: none !important;
+      }
+    </style>
+    <style>
+      /*! syntax-highlighting.css */
+      pre {
+        line-height: 125%;
+      }
+      span.linenos {
+        color: inherit;
+        background-color: transparent;
+        padding-left: 5px;
+        padding-right: 20px;
+      }
+      .pdoc-code .hll {
+        background-color: #ffffcc;
+      }
+      .pdoc-code {
+        background: #f8f8f8;
+      }
+      .pdoc-code .c {
+        color: #3d7b7b;
+        font-style: italic;
+      }
+      .pdoc-code .err {
+        border: 1px solid #ff0000;
+      }
+      .pdoc-code .k {
+        color: #008000;
+        font-weight: bold;
+      }
+      .pdoc-code .o {
+        color: #666666;
+      }
+      .pdoc-code .ch {
+        color: #3d7b7b;
+        font-style: italic;
+      }
+      .pdoc-code .cm {
+        color: #3d7b7b;
+        font-style: italic;
+      }
+      .pdoc-code .cp {
+        color: #9c6500;
+      }
+      .pdoc-code .cpf {
+        color: #3d7b7b;
+        font-style: italic;
+      }
+      .pdoc-code .c1 {
+        color: #3d7b7b;
+        font-style: italic;
+      }
+      .pdoc-code .cs {
+        color: #3d7b7b;
+        font-style: italic;
+      }
+      .pdoc-code .gd {
+        color: #a00000;
+      }
+      .pdoc-code .ge {
+        font-style: italic;
+      }
+      .pdoc-code .gr {
+        color: #e40000;
+      }
+      .pdoc-code .gh {
+        color: #000080;
+        font-weight: bold;
+      }
+      .pdoc-code .gi {
+        color: #008400;
+      }
+      .pdoc-code .go {
+        color: #717171;
+      }
+      .pdoc-code .gp {
+        color: #000080;
+        font-weight: bold;
+      }
+      .pdoc-code .gs {
+        font-weight: bold;
+      }
+      .pdoc-code .gu {
+        color: #800080;
+        font-weight: bold;
+      }
+      .pdoc-code .gt {
+        color: #0044dd;
+      }
+      .pdoc-code .kc {
+        color: #008000;
+        font-weight: bold;
+      }
+      .pdoc-code .kd {
+        color: #008000;
+        font-weight: bold;
+      }
+      .pdoc-code .kn {
+        color: #008000;
+        font-weight: bold;
+      }
+      .pdoc-code .kp {
+        color: #008000;
+      }
+      .pdoc-code .kr {
+        color: #008000;
+        font-weight: bold;
+      }
+      .pdoc-code .kt {
+        color: #b00040;
+      }
+      .pdoc-code .m {
+        color: #666666;
+      }
+      .pdoc-code .s {
+        color: #ba2121;
+      }
+      .pdoc-code .na {
+        color: #687822;
+      }
+      .pdoc-code .nb {
+        color: #008000;
+      }
+      .pdoc-code .nc {
+        color: #0000ff;
+        font-weight: bold;
+      }
+      .pdoc-code .no {
+        color: #880000;
+      }
+      .pdoc-code .nd {
+        color: #aa22ff;
+      }
+      .pdoc-code .ni {
+        color: #717171;
+        font-weight: bold;
+      }
+      .pdoc-code .ne {
+        color: #cb3f38;
+        font-weight: bold;
+      }
+      .pdoc-code .nf {
+        color: #0000ff;
+      }
+      .pdoc-code .nl {
+        color: #767600;
+      }
+      .pdoc-code .nn {
+        color: #0000ff;
+        font-weight: bold;
+      }
+      .pdoc-code .nt {
+        color: #008000;
+        font-weight: bold;
+      }
+      .pdoc-code .nv {
+        color: #19177c;
+      }
+      .pdoc-code .ow {
+        color: #aa22ff;
+        font-weight: bold;
+      }
+      .pdoc-code .w {
+        color: #bbbbbb;
+      }
+      .pdoc-code .mb {
+        color: #666666;
+      }
+      .pdoc-code .mf {
+        color: #666666;
+      }
+      .pdoc-code .mh {
+        color: #666666;
+      }
+      .pdoc-code .mi {
+        color: #666666;
+      }
+      .pdoc-code .mo {
+        color: #666666;
+      }
+      .pdoc-code .sa {
+        color: #ba2121;
+      }
+      .pdoc-code .sb {
+        color: #ba2121;
+      }
+      .pdoc-code .sc {
+        color: #ba2121;
+      }
+      .pdoc-code .dl {
+        color: #ba2121;
+      }
+      .pdoc-code .sd {
+        color: #ba2121;
+        font-style: italic;
+      }
+      .pdoc-code .s2 {
+        color: #ba2121;
+      }
+      .pdoc-code .se {
+        color: #aa5d1f;
+        font-weight: bold;
+      }
+      .pdoc-code .sh {
+        color: #ba2121;
+      }
+      .pdoc-code .si {
+        color: #a45a77;
+        font-weight: bold;
+      }
+      .pdoc-code .sx {
+        color: #008000;
+      }
+      .pdoc-code .sr {
+        color: #a45a77;
+      }
+      .pdoc-code .s1 {
+        color: #ba2121;
+      }
+      .pdoc-code .ss {
+        color: #19177c;
+      }
+      .pdoc-code .bp {
+        color: #008000;
+      }
+      .pdoc-code .fm {
+        color: #0000ff;
+      }
+      .pdoc-code .vc {
+        color: #19177c;
+      }
+      .pdoc-code .vg {
+        color: #19177c;
+      }
+      .pdoc-code .vi {
+        color: #19177c;
+      }
+      .pdoc-code .vm {
+        color: #19177c;
+      }
+      .pdoc-code .il {
+        color: #666666;
+      }
+    </style>
+    <style>
+      /*! theme.css */
+      :root {
+        --pdoc-background: #fff;
+      }
+      .pdoc {
+        --text: #212529;
+        --muted: #6c757d;
+        --link: #3660a5;
+        --link-hover: #1659c5;
+        --code: #f8f8f8;
+        --active: #fff598;
+        --accent: #eee;
+        --accent2: #c1c1c1;
+        --nav-hover: rgba(255, 255, 255, 0.5);
+        --name: #0066bb;
+        --def: #008800;
+        --annotation: #007020;
+      }
+    </style>
+    <style>
+      /*! layout.css */
+      html,
+      body {
+        width: 100%;
+        height: 100%;
+      }
+      html,
+      main {
+        scroll-behavior: smooth;
+      }
+      body {
+        background-color: var(--pdoc-background);
+      }
+      @media (max-width: 769px) {
+        #navtoggle {
+          cursor: pointer;
+          position: absolute;
+          width: 50px;
+          height: 40px;
+          top: 1rem;
+          right: 1rem;
+          border-color: var(--text);
+          color: var(--text);
+          display: flex;
+          opacity: 0.8;
+          z-index: 999;
+        }
+        #navtoggle:hover {
+          opacity: 1;
+        }
+        #togglestate + div {
+          display: none;
+        }
+        #togglestate:checked + div {
+          display: inherit;
+        }
+        main,
+        header {
+          padding: 2rem 3vw;
+        }
+        header + main {
+          margin-top: -3rem;
+        }
+        .git-button {
+          display: none !important;
+        }
+        nav input[type="search"] {
+          max-width: 77%;
+        }
+        nav input[type="search"]:first-child {
+          margin-top: -6px;
+        }
+        nav input[type="search"]:valid ~ * {
+          display: none !important;
+        }
+      }
+      @media (min-width: 770px) {
+        :root {
+          --sidebar-width: clamp(12.5rem, 28vw, 22rem);
+        }
+        nav {
+          position: fixed;
+          overflow: auto;
+          height: 100vh;
+          width: var(--sidebar-width);
+        }
+        main,
+        header {
+          padding: 3rem 2rem 3rem calc(var(--sidebar-width) + 3rem);
+          width: calc(54rem + var(--sidebar-width));
+          max-width: 100%;
+        }
+        header + main {
+          margin-top: -4rem;
+        }
+        #navtoggle {
+          display: none;
+        }
+      }
+      #togglestate {
+        position: absolute;
+        height: 0;
+        opacity: 0;
+      }
+      nav.pdoc {
+        --pad: clamp(0.5rem, 2vw, 1.75rem);
+        --indent: 1.5rem;
+        background-color: var(--accent);
+        border-right: 1px solid var(--accent2);
+        box-shadow: 0 0 20px rgba(50, 50, 50, 0.2) inset;
+        padding: 0 0 0 var(--pad);
+        overflow-wrap: anywhere;
+        scrollbar-width: thin;
+        scrollbar-color: var(--accent2) transparent;
+      }
+      nav.pdoc::-webkit-scrollbar {
+        width: 0.4rem;
+      }
+      nav.pdoc::-webkit-scrollbar-thumb {
+        background-color: var(--accent2);
+      }
+      nav.pdoc > div {
+        padding: var(--pad) 0;
+      }
+      nav.pdoc .module-list-button {
+        display: inline-flex;
+        align-items: center;
+        color: var(--text);
+        border-color: var(--muted);
+        margin-bottom: 1rem;
+      }
+      nav.pdoc .module-list-button:hover {
+        border-color: var(--text);
+      }
+      nav.pdoc input[type="search"] {
+        display: block;
+        outline-offset: 0;
+        width: calc(100% - var(--pad));
+      }
+      nav.pdoc .logo {
+        max-width: calc(100% - var(--pad));
+        max-height: 35vh;
+        display: block;
+        margin: 0 auto 1rem;
+        transform: translate(calc(-0.5 * var(--pad)), 0);
+      }
+      nav.pdoc ul {
+        list-style: none;
+        padding-left: 0;
+      }
+      nav.pdoc > div > ul {
+        margin-left: calc(0px - var(--pad));
+      }
+      nav.pdoc li a {
+        padding: 0.2rem 0 0.2rem calc(var(--pad) + var(--indent));
+      }
+      nav.pdoc > div > ul > li > a {
+        padding-left: var(--pad);
+      }
+      nav.pdoc li {
+        transition: all 100ms;
+      }
+      nav.pdoc li:hover {
+        background-color: var(--nav-hover);
+      }
+      nav.pdoc a,
+      nav.pdoc a:hover {
+        color: var(--text);
+      }
+      nav.pdoc a {
+        display: block;
+      }
+      nav.pdoc > h2:first-of-type {
+        margin-top: 1.5rem;
+      }
+      nav.pdoc .class:before {
+        content: "class ";
+        color: var(--muted);
+      }
+      nav.pdoc .function:after {
+        content: "()";
+        color: var(--muted);
+      }
+      nav.pdoc footer:before {
+        content: "";
+        display: block;
+        width: calc(100% - var(--pad));
+        border-top: solid var(--accent2) 1px;
+        margin-top: 1.5rem;
+        padding-top: 0.5rem;
+      }
+      nav.pdoc footer {
+        font-size: small;
+      }
+    </style>
+    <style>
+      /*! content.css */
+      .pdoc {
+        color: var(--text);
+        box-sizing: border-box;
+        line-height: 1.5;
+        background: none;
+      }
+      .pdoc .pdoc-button {
+        cursor: pointer;
+        display: inline-block;
+        border: solid black 1px;
+        border-radius: 2px;
+        font-size: 0.75rem;
+        padding: calc(0.5em - 1px) 1em;
+        transition: 100ms all;
+      }
+      .pdoc .pdoc-alert {
+        padding: 1rem 1rem 1rem calc(1.5rem + 24px);
+        border: 1px solid transparent;
+        border-radius: 0.25rem;
+        background-repeat: no-repeat;
+        background-position: 1rem center;
+        margin-bottom: 1rem;
+      }
+      .pdoc .pdoc-alert > *:last-child {
+        margin-bottom: 0;
+      }
+      .pdoc .pdoc-alert-note {
+        color: #084298;
+        background-color: #cfe2ff;
+        border-color: #b6d4fe;
+        background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23084298%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M8%2016A8%208%200%201%200%208%200a8%208%200%200%200%200%2016zm.93-9.412-1%204.705c-.07.34.029.533.304.533.194%200%20.487-.07.686-.246l-.088.416c-.287.346-.92.598-1.465.598-.703%200-1.002-.422-.808-1.319l.738-3.468c.064-.293.006-.399-.287-.47l-.451-.081.082-.381%202.29-.287zM8%205.5a1%201%200%201%201%200-2%201%201%200%200%201%200%202z%22/%3E%3C/svg%3E");
+      }
+      .pdoc .pdoc-alert-warning {
+        color: #664d03;
+        background-color: #fff3cd;
+        border-color: #ffecb5;
+        background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23664d03%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M8.982%201.566a1.13%201.13%200%200%200-1.96%200L.165%2013.233c-.457.778.091%201.767.98%201.767h13.713c.889%200%201.438-.99.98-1.767L8.982%201.566zM8%205c.535%200%20.954.462.9.995l-.35%203.507a.552.552%200%200%201-1.1%200L7.1%205.995A.905.905%200%200%201%208%205zm.002%206a1%201%200%201%201%200%202%201%201%200%200%201%200-2z%22/%3E%3C/svg%3E");
+      }
+      .pdoc .pdoc-alert-danger {
+        color: #842029;
+        background-color: #f8d7da;
+        border-color: #f5c2c7;
+        background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23842029%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M5.52.359A.5.5%200%200%201%206%200h4a.5.5%200%200%201%20.474.658L8.694%206H12.5a.5.5%200%200%201%20.395.807l-7%209a.5.5%200%200%201-.873-.454L6.823%209.5H3.5a.5.5%200%200%201-.48-.641l2.5-8.5z%22/%3E%3C/svg%3E");
+      }
+      .pdoc .visually-hidden {
+        position: absolute !important;
+        width: 1px !important;
+        height: 1px !important;
+        padding: 0 !important;
+        margin: -1px !important;
+        overflow: hidden !important;
+        clip: rect(0, 0, 0, 0) !important;
+        white-space: nowrap !important;
+        border: 0 !important;
+      }
+      .pdoc h1,
+      .pdoc h2,
+      .pdoc h3 {
+        font-weight: 300;
+        margin: 0.3em 0;
+        padding: 0.2em 0;
+      }
+      .pdoc > section:not(.module-info) h1 {
+        font-size: 1.5rem;
+        font-weight: 500;
+      }
+      .pdoc > section:not(.module-info) h2 {
+        font-size: 1.4rem;
+        font-weight: 500;
+      }
+      .pdoc > section:not(.module-info) h3 {
+        font-size: 1.3rem;
+        font-weight: 500;
+      }
+      .pdoc > section:not(.module-info) h4 {
+        font-size: 1.2rem;
+      }
+      .pdoc > section:not(.module-info) h5 {
+        font-size: 1.1rem;
+      }
+      .pdoc a {
+        text-decoration: none;
+        color: var(--link);
+      }
+      .pdoc a:hover {
+        color: var(--link-hover);
+      }
+      .pdoc blockquote {
+        margin-left: 2rem;
+      }
+      .pdoc pre {
+        border-top: 1px solid var(--accent2);
+        border-bottom: 1px solid var(--accent2);
+        margin-top: 0;
+        margin-bottom: 1em;
+        padding: 0.5rem 0 0.5rem 0.5rem;
+        overflow-x: auto;
+        background-color: var(--code);
+      }
+      .pdoc code {
+        color: var(--text);
+        padding: 0.2em 0.4em;
+        margin: 0;
+        font-size: 85%;
+        background-color: var(--code);
+        border-radius: 6px;
+      }
+      .pdoc a > code {
+        color: inherit;
+      }
+      .pdoc pre > code {
+        display: inline-block;
+        font-size: inherit;
+        background: none;
+        border: none;
+        padding: 0;
+      }
+      .pdoc > section:not(.module-info) {
+        margin-bottom: 1.5rem;
+      }
+      .pdoc .modulename {
+        margin-top: 0;
+        font-weight: bold;
+      }
+      .pdoc .modulename a {
+        color: var(--link);
+        transition: 100ms all;
+      }
+      .pdoc .git-button {
+        float: right;
+        border: solid var(--link) 1px;
+      }
+      .pdoc .git-button:hover {
+        background-color: var(--link);
+        color: var(--pdoc-background);
+      }
+      .view-source-toggle-state,
+      .view-source-toggle-state ~ .pdoc-code {
+        display: none;
+      }
+      .view-source-toggle-state:checked ~ .pdoc-code {
+        display: block;
+      }
+      .view-source-button {
+        display: inline-block;
+        float: right;
+        font-size: 0.75rem;
+        line-height: 1.5rem;
+        color: var(--muted);
+        padding: 0 0.4rem 0 1.3rem;
+        cursor: pointer;
+        text-indent: -2px;
+      }
+      .view-source-button > span {
+        visibility: hidden;
+      }
+      .module-info .view-source-button {
+        float: none;
+        display: flex;
+        justify-content: flex-end;
+        margin: -1.2rem 0.4rem -0.2rem 0;
+      }
+      .view-source-button::before {
+        position: absolute;
+        content: "View Source";
+        display: list-item;
+        list-style-type: disclosure-closed;
+      }
+      .view-source-toggle-state:checked ~ .attr .view-source-button::before,
+      .view-source-toggle-state:checked ~ .view-source-button::before {
+        list-style-type: disclosure-open;
+      }
+      .pdoc .docstring {
+        margin-bottom: 1.5rem;
+      }
+      .pdoc section:not(.module-info) .docstring {
+        margin-left: clamp(0rem, 5vw - 2rem, 1rem);
+      }
+      .pdoc .docstring .pdoc-code {
+        margin-left: 1em;
+        margin-right: 1em;
+      }
+      .pdoc h1:target,
+      .pdoc h2:target,
+      .pdoc h3:target,
+      .pdoc h4:target,
+      .pdoc h5:target,
+      .pdoc h6:target,
+      .pdoc .pdoc-code > pre > span:target {
+        background-color: var(--active);
+        box-shadow: -1rem 0 0 0 var(--active);
+      }
+      .pdoc .pdoc-code > pre > span:target {
+        display: block;
+      }
+      .pdoc div:target > .attr,
+      .pdoc section:target > .attr,
+      .pdoc dd:target > a {
+        background-color: var(--active);
+      }
+      .pdoc * {
+        scroll-margin: 2rem;
+      }
+      .pdoc .pdoc-code .linenos {
+        user-select: none;
+      }
+      .pdoc .attr:hover {
+        filter: contrast(0.95);
+      }
+      .pdoc section,
+      .pdoc .classattr {
+        position: relative;
+      }
+      .pdoc .headerlink {
+        --width: clamp(1rem, 3vw, 2rem);
+        position: absolute;
+        top: 0;
+        left: calc(0rem - var(--width));
+        transition: all 100ms ease-in-out;
+        opacity: 0;
+      }
+      .pdoc .headerlink::before {
+        content: "#";
+        display: block;
+        text-align: center;
+        width: var(--width);
+        height: 2.3rem;
+        line-height: 2.3rem;
+        font-size: 1.5rem;
+      }
+      .pdoc .attr:hover ~ .headerlink,
+      .pdoc *:target > .headerlink,
+      .pdoc .headerlink:hover {
+        opacity: 1;
+      }
+      .pdoc .attr {
+        display: block;
+        margin: 0.5rem 0 0.5rem;
+        padding: 0.4rem 0.4rem 0.4rem 1rem;
+        background-color: var(--accent);
+        overflow-x: auto;
+      }
+      .pdoc .classattr {
+        margin-left: 2rem;
+      }
+      .pdoc .name {
+        color: var(--name);
+        font-weight: bold;
+      }
+      .pdoc .def {
+        color: var(--def);
+        font-weight: bold;
+      }
+      .pdoc .signature {
+        background-color: transparent;
+      }
+      .pdoc .param,
+      .pdoc .return-annotation {
+        white-space: pre;
+      }
+      .pdoc .signature.multiline .param {
+        display: block;
+      }
+      .pdoc .signature.condensed .param {
+        display: inline-block;
+      }
+      .pdoc .annotation {
+        color: var(--annotation);
+      }
+      .pdoc .view-value-toggle-state,
+      .pdoc .view-value-toggle-state ~ .default_value {
+        display: none;
+      }
+      .pdoc .view-value-toggle-state:checked ~ .default_value {
+        display: inherit;
+      }
+      .pdoc .view-value-button {
+        font-size: 0.5rem;
+        vertical-align: middle;
+        border-style: dashed;
+        margin-top: -0.1rem;
+      }
+      .pdoc .view-value-button:hover {
+        background: white;
+      }
+      .pdoc .view-value-button::before {
+        content: "show";
+        text-align: center;
+        width: 2.2em;
+        display: inline-block;
+      }
+      .pdoc .view-value-toggle-state:checked ~ .view-value-button::before {
+        content: "hide";
+      }
+      .pdoc .inherited {
+        margin-left: 2rem;
+      }
+      .pdoc .inherited dt {
+        font-weight: 700;
+      }
+      .pdoc .inherited dt,
+      .pdoc .inherited dd {
+        display: inline;
+        margin-left: 0;
+        margin-bottom: 0.5rem;
+      }
+      .pdoc .inherited dd:not(:last-child):after {
+        content: ", ";
+      }
+      .pdoc .inherited .class:before {
+        content: "class ";
+      }
+      .pdoc .inherited .function a:after {
+        content: "()";
+      }
+      .pdoc .search-result .docstring {
+        overflow: auto;
+        max-height: 25vh;
+      }
+      .pdoc .search-result.focused > .attr {
+        background-color: var(--active);
+      }
+      .pdoc .attribution {
+        margin-top: 2rem;
+        display: block;
+        opacity: 0.5;
+        transition: all 200ms;
+        filter: grayscale(100%);
+      }
+      .pdoc .attribution:hover {
+        opacity: 1;
+        filter: grayscale(0%);
+      }
+      .pdoc .attribution img {
+        margin-left: 5px;
+        height: 35px;
+        vertical-align: middle;
+        width: 70px;
+        transition: all 200ms;
+      }
+      .pdoc table {
+        display: block;
+        width: max-content;
+        max-width: 100%;
+        overflow: auto;
+        margin-bottom: 1rem;
+      }
+      .pdoc table th {
+        font-weight: 600;
+      }
+      .pdoc table th,
+      .pdoc table td {
+        padding: 6px 13px;
+        border: 1px solid var(--accent2);
+      }
+    </style>
+    <style>
+      /*! custom.css */
+    </style>
+    <style>
+      .pdoc .mermaid-pre {
+        border: none;
+        background: none;
+      }
+    </style>
+    <script type="module" defer>
+      import mermaid from "https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs";
+
+      /* Re-invoke Mermaid when DOM content changes, for example during search. */
+      document.addEventListener("DOMContentLoaded", () => {
+        new MutationObserver(() => mermaid.run()).observe(
+          document.querySelector("main.pdoc").parentNode,
+          { childList: true }
+        );
+      });
+    </script>
+  </head>
+  <body>
+    <nav class="pdoc">
+      <label id="navtoggle" for="togglestate" class="pdoc-button"
+        ><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30">
+          <path
+            stroke-linecap="round"
+            stroke="currentColor"
+            stroke-miterlimit="10"
+            stroke-width="2"
+            d="M4 7h22M4 15h22M4 23h22"
+          /></svg
+      ></label>
+      <input
+        id="togglestate"
+        type="checkbox"
+        aria-hidden="true"
+        tabindex="-1"
+      />
+      <div>
+        <a class="pdoc-button module-list-button" href="../securecookies.html">
+          <svg
+            xmlns="http://www.w3.org/2000/svg"
+            width="16"
+            height="16"
+            fill="currentColor"
+            class="bi bi-box-arrow-in-left"
+            viewBox="0 0 16 16"
+          >
+            <path
+              fill-rule="evenodd"
+              d="M10 3.5a.5.5 0 0 0-.5-.5h-8a.5.5 0 0 0-.5.5v9a.5.5 0 0 0 .5.5h8a.5.5 0 0 0 .5-.5v-2a.5.5 0 0 1 1 0v2A1.5 1.5 0 0 1 9.5 14h-8A1.5 1.5 0 0 1 0 12.5v-9A1.5 1.5 0 0 1 1.5 2h8A1.5 1.5 0 0 1 11 3.5v2a.5.5 0 0 1-1 0v-2z"
+            />
+            <path
+              fill-rule="evenodd"
+              d="M4.146 8.354a.5.5 0 0 1 0-.708l3-3a.5.5 0 1 1 .708.708L5.707 7.5H14.5a.5.5 0 0 1 0 1H5.707l2.147 2.146a.5.5 0 0 1-.708.708l-3-3z"
+            />
+          </svg>
+          &nbsp;securecookies</a
+        >
+
+        <h2>Contents</h2>
+        <ul>
+          <li><a href="#securecookiesextras">securecookies.extras</a></li>
+        </ul>
+
+        <a
+          class="attribution"
+          title="pdoc: Python API documentation generator"
+          href="https://pdoc.dev"
+          target="_blank"
+        >
+          built with <span class="visually-hidden">pdoc</span
+          ><img
+            alt="pdoc logo"
+            src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20role%3D%22img%22%20aria-label%3D%22pdoc%20logo%22%20width%3D%22300%22%20height%3D%22150%22%20viewBox%3D%22-1%200%2060%2030%22%3E%3Ctitle%3Epdoc%3C/title%3E%3Cpath%20d%3D%22M29.621%2021.293c-.011-.273-.214-.475-.511-.481a.5.5%200%200%200-.489.503l-.044%201.393c-.097.551-.695%201.215-1.566%201.704-.577.428-1.306.486-2.193.182-1.426-.617-2.467-1.654-3.304-2.487l-.173-.172a3.43%203.43%200%200%200-.365-.306.49.49%200%200%200-.286-.196c-1.718-1.06-4.931-1.47-7.353.191l-.219.15c-1.707%201.187-3.413%202.131-4.328%201.03-.02-.027-.49-.685-.141-1.763.233-.721.546-2.408.772-4.076.042-.09.067-.187.046-.288.166-1.347.277-2.625.241-3.351%201.378-1.008%202.271-2.586%202.271-4.362%200-.976-.272-1.935-.788-2.774-.057-.094-.122-.18-.184-.268.033-.167.052-.339.052-.516%200-1.477-1.202-2.679-2.679-2.679-.791%200-1.496.352-1.987.9a6.3%206.3%200%200%200-1.001.029c-.492-.564-1.207-.929-2.012-.929-1.477%200-2.679%201.202-2.679%202.679A2.65%202.65%200%200%200%20.97%206.554c-.383.747-.595%201.572-.595%202.41%200%202.311%201.507%204.29%203.635%205.107-.037.699-.147%202.27-.423%203.294l-.137.461c-.622%202.042-2.515%208.257%201.727%2010.643%201.614.908%203.06%201.248%204.317%201.248%202.665%200%204.492-1.524%205.322-2.401%201.476-1.559%202.886-1.854%206.491.82%201.877%201.393%203.514%201.753%204.861%201.068%202.223-1.713%202.811-3.867%203.399-6.374.077-.846.056-1.469.054-1.537zm-4.835%204.313c-.054.305-.156.586-.242.629-.034-.007-.131-.022-.307-.157-.145-.111-.314-.478-.456-.908.221.121.432.25.675.355.115.039.219.051.33.081zm-2.251-1.238c-.05.33-.158.648-.252.694-.022.001-.125-.018-.307-.157-.217-.166-.488-.906-.639-1.573.358.344.754.693%201.198%201.036zm-3.887-2.337c-.006-.116-.018-.231-.041-.342.635.145%201.189.368%201.599.625.097.231.166.481.174.642-.03.049-.055.101-.067.158-.046.013-.128.026-.298.004-.278-.037-.901-.57-1.367-1.087zm-1.127-.497c.116.306.176.625.12.71-.019.014-.117.045-.345.016-.206-.027-.604-.332-.986-.695.41-.051.816-.056%201.211-.031zm-4.535%201.535c.209.22.379.47.358.598-.006.041-.088.138-.351.234-.144.055-.539-.063-.979-.259a11.66%2011.66%200%200%200%20.972-.573zm.983-.664c.359-.237.738-.418%201.126-.554.25.237.479.548.457.694-.006.042-.087.138-.351.235-.174.064-.694-.105-1.232-.375zm-3.381%201.794c-.022.145-.061.29-.149.401-.133.166-.358.248-.69.251h-.002c-.133%200-.306-.26-.45-.621.417.091.854.07%201.291-.031zm-2.066-8.077a4.78%204.78%200%200%201-.775-.584c.172-.115.505-.254.88-.378l-.105.962zm-.331%202.302a10.32%2010.32%200%200%201-.828-.502c.202-.143.576-.328.984-.49l-.156.992zm-.45%202.157l-.701-.403c.214-.115.536-.249.891-.376a11.57%2011.57%200%200%201-.19.779zm-.181%201.716c.064.398.194.702.298.893-.194-.051-.435-.162-.736-.398.061-.119.224-.3.438-.495zM8.87%204.141c0%20.152-.123.276-.276.276s-.275-.124-.275-.276.123-.276.276-.276.275.124.275.276zm-.735-.389a1.15%201.15%200%200%200-.314.783%201.16%201.16%200%200%200%201.162%201.162c.457%200%20.842-.27%201.032-.653.026.117.042.238.042.362a1.68%201.68%200%200%201-1.679%201.679%201.68%201.68%200%200%201-1.679-1.679c0-.843.626-1.535%201.436-1.654zM5.059%205.406A1.68%201.68%200%200%201%203.38%207.085a1.68%201.68%200%200%201-1.679-1.679c0-.037.009-.072.011-.109.21.3.541.508.935.508a1.16%201.16%200%200%200%201.162-1.162%201.14%201.14%200%200%200-.474-.912c.015%200%20.03-.005.045-.005.926.001%201.679.754%201.679%201.68zM3.198%204.141c0%20.152-.123.276-.276.276s-.275-.124-.275-.276.123-.276.276-.276.275.124.275.276zM1.375%208.964c0-.52.103-1.035.288-1.52.466.394%201.06.64%201.717.64%201.144%200%202.116-.725%202.499-1.738.383%201.012%201.355%201.738%202.499%201.738.867%200%201.631-.421%202.121-1.062.307.605.478%201.267.478%201.942%200%202.486-2.153%204.51-4.801%204.51s-4.801-2.023-4.801-4.51zm24.342%2019.349c-.985.498-2.267.168-3.813-.979-3.073-2.281-5.453-3.199-7.813-.705-1.315%201.391-4.163%203.365-8.423.97-3.174-1.786-2.239-6.266-1.261-9.479l.146-.492c.276-1.02.395-2.457.444-3.268a6.11%206.11%200%200%200%201.18.115%206.01%206.01%200%200%200%202.536-.562l-.006.175c-.802.215-1.848.612-2.021%201.25-.079.295.021.601.274.837.219.203.415.364.598.501-.667.304-1.243.698-1.311%201.179-.02.144-.022.507.393.787.213.144.395.26.564.365-1.285.521-1.361.96-1.381%201.126-.018.142-.011.496.427.746l.854.489c-.473.389-.971.914-.999%201.429-.018.278.095.532.316.713.675.556%201.231.721%201.653.721.059%200%20.104-.014.158-.02.207.707.641%201.64%201.513%201.64h.013c.8-.008%201.236-.345%201.462-.626.173-.216.268-.457.325-.692.424.195.93.374%201.372.374.151%200%20.294-.021.423-.068.732-.27.944-.704.993-1.021.009-.061.003-.119.002-.179.266.086.538.147.789.147.15%200%20.294-.021.423-.069.542-.2.797-.489.914-.754.237.147.478.258.704.288.106.014.205.021.296.021.356%200%20.595-.101.767-.229.438.435%201.094.992%201.656%201.067.106.014.205.021.296.021a1.56%201.56%200%200%200%20.323-.035c.17.575.453%201.289.866%201.605.358.273.665.362.914.362a.99.99%200%200%200%20.421-.093%201.03%201.03%200%200%200%20.245-.164c.168.428.39.846.68%201.068.358.273.665.362.913.362a.99.99%200%200%200%20.421-.093c.317-.148.512-.448.639-.762.251.157.495.257.726.257.127%200%20.25-.024.37-.071.427-.17.706-.617.841-1.314.022-.015.047-.022.068-.038.067-.051.133-.104.196-.159-.443%201.486-1.107%202.761-2.086%203.257zM8.66%209.925a.5.5%200%201%200-1%200c0%20.653-.818%201.205-1.787%201.205s-1.787-.552-1.787-1.205a.5.5%200%201%200-1%200c0%201.216%201.25%202.205%202.787%202.205s2.787-.989%202.787-2.205zm4.4%2015.965l-.208.097c-2.661%201.258-4.708%201.436-6.086.527-1.542-1.017-1.88-3.19-1.844-4.198a.4.4%200%200%200-.385-.414c-.242-.029-.406.164-.414.385-.046%201.249.367%203.686%202.202%204.896.708.467%201.547.7%202.51.7%201.248%200%202.706-.392%204.362-1.174l.185-.086a.4.4%200%200%200%20.205-.527c-.089-.204-.326-.291-.527-.206zM9.547%202.292c.093.077.205.114.317.114a.5.5%200%200%200%20.318-.886L8.817.397a.5.5%200%200%200-.703.068.5.5%200%200%200%20.069.703l1.364%201.124zm-7.661-.065c.086%200%20.173-.022.253-.068l1.523-.893a.5.5%200%200%200-.506-.863l-1.523.892a.5.5%200%200%200-.179.685c.094.158.261.247.432.247z%22%20transform%3D%22matrix%28-1%200%200%201%2058%200%29%22%20fill%3D%22%233bb300%22/%3E%3Cpath%20d%3D%22M.3%2021.86V10.18q0-.46.02-.68.04-.22.18-.5.28-.54%201.34-.54%201.06%200%201.42.28.38.26.44.78.76-1.04%202.38-1.04%201.64%200%203.1%201.54%201.46%201.54%201.46%203.58%200%202.04-1.46%203.58-1.44%201.54-3.08%201.54-1.64%200-2.38-.92v4.04q0%20.46-.04.68-.02.22-.18.5-.14.3-.5.42-.36.12-.98.12-.62%200-1-.12-.36-.12-.52-.4-.14-.28-.18-.5-.02-.22-.02-.68zm3.96-9.42q-.46.54-.46%201.18%200%20.64.46%201.18.48.52%201.2.52.74%200%201.24-.52.52-.52.52-1.18%200-.66-.48-1.18-.48-.54-1.26-.54-.76%200-1.22.54zm14.741-8.36q.16-.3.54-.42.38-.12%201-.12.64%200%201.02.12.38.12.52.42.16.3.18.54.04.22.04.68v11.94q0%20.46-.04.7-.02.22-.18.5-.3.54-1.7.54-1.38%200-1.54-.98-.84.96-2.34.96-1.8%200-3.28-1.56-1.48-1.58-1.48-3.66%200-2.1%201.48-3.68%201.5-1.58%203.28-1.58%201.48%200%202.3%201v-4.2q0-.46.02-.68.04-.24.18-.52zm-3.24%2010.86q.52.54%201.26.54.74%200%201.22-.54.5-.54.5-1.18%200-.66-.48-1.22-.46-.56-1.26-.56-.8%200-1.28.56-.48.54-.48%201.2%200%20.66.52%201.2zm7.833-1.2q0-2.4%201.68-3.96%201.68-1.56%203.84-1.56%202.16%200%203.82%201.56%201.66%201.54%201.66%203.94%200%201.66-.86%202.96-.86%201.28-2.1%201.9-1.22.6-2.54.6-1.32%200-2.56-.64-1.24-.66-2.1-1.92-.84-1.28-.84-2.88zm4.18%201.44q.64.48%201.3.48.66%200%201.32-.5.66-.5.66-1.48%200-.98-.62-1.46-.62-.48-1.34-.48-.72%200-1.34.5-.62.5-.62%201.48%200%20.96.64%201.46zm11.412-1.44q0%20.84.56%201.32.56.46%201.18.46.64%200%201.18-.36.56-.38.9-.38.6%200%201.46%201.06.46.58.46%201.04%200%20.76-1.1%201.42-1.14.8-2.8.8-1.86%200-3.58-1.34-.82-.64-1.34-1.7-.52-1.08-.52-2.36%200-1.3.52-2.34.52-1.06%201.34-1.7%201.66-1.32%203.54-1.32.76%200%201.48.22.72.2%201.06.4l.32.2q.36.24.56.38.52.4.52.92%200%20.5-.42%201.14-.72%201.1-1.38%201.1-.38%200-1.08-.44-.36-.34-1.04-.34-.66%200-1.24.48-.58.48-.58%201.34z%22%20fill%3D%22green%22/%3E%3C/svg%3E"
+          />
+        </a>
+      </div>
+    </nav>
+    <main class="pdoc">
+      <section class="module-info">
+        <h1 class="modulename">
+          <a href="./../securecookies.html">securecookies</a><wbr />.extras
+        </h1>
+
+        <div class="docstring">
+          <h1 id="securecookiesextras"><a href="">securecookies.extras</a></h1>
+
+          <p>
+            starlette-securecookies also ships with some common middleware and
+            tools modified and extended to work with secure cookies.
+          </p>
+
+          <ul>
+            <li>
+              <strong><code>csrf.SecureCSRFMiddleware</code></strong
+              >: Adds compatibility to the CSRF middleware provided by
+              <a href="https://github.com/frankie567/starlette-csrf"
+                >starlette_csrf</a
+              >. To use it, simply add it to your list of middleware (keep in
+              mind the ordering). If you don't want to specify
+              <code>starlette_csrf</code> as a direct dependency, you can also
+              install it through the <code>[csrf]</code> package extra.
+            </li>
+          </ul>
+        </div>
+
+        <input
+          id="mod-extras-view-source"
+          class="view-source-toggle-state"
+          type="checkbox"
+          aria-hidden="true"
+          tabindex="-1"
+        />
+
+        <label class="view-source-button" for="mod-extras-view-source"
+          ><span>View Source</span></label
+        >
+
+        <div class="pdoc-code codehilite">
+          <pre><span></span><span id="L-1"><a href="#L-1"><span class="linenos"> 1</span></a><span class="sd">&quot;&quot;&quot;</span>
+</span><span id="L-2"><a href="#L-2"><span class="linenos"> 2</span></a><span class="sd"># securecookies.extras</span>
+</span><span id="L-3"><a href="#L-3"><span class="linenos"> 3</span></a>
+</span><span id="L-4"><a href="#L-4"><span class="linenos"> 4</span></a><span class="sd">starlette-securecookies also ships with some common middleware and tools modified and</span>
+</span><span id="L-5"><a href="#L-5"><span class="linenos"> 5</span></a><span class="sd">extended to work with secure cookies.</span>
+</span><span id="L-6"><a href="#L-6"><span class="linenos"> 6</span></a>
+</span><span id="L-7"><a href="#L-7"><span class="linenos"> 7</span></a><span class="sd">- **`csrf.SecureCSRFMiddleware`**: Adds compatibility to the CSRF middleware provided</span>
+</span><span id="L-8"><a href="#L-8"><span class="linenos"> 8</span></a><span class="sd">by [starlette_csrf](https://github.com/frankie567/starlette-csrf). To use it, simply</span>
+</span><span id="L-9"><a href="#L-9"><span class="linenos"> 9</span></a><span class="sd">add it to your list of middleware (keep in mind the ordering). If you don&#39;t want to</span>
+</span><span id="L-10"><a href="#L-10"><span class="linenos">10</span></a><span class="sd">specify `starlette_csrf` as a direct dependency, you can also install it through the</span>
+</span><span id="L-11"><a href="#L-11"><span class="linenos">11</span></a><span class="sd">`[csrf]` package extra.</span>
+</span><span id="L-12"><a href="#L-12"><span class="linenos">12</span></a><span class="sd">&quot;&quot;&quot;</span>
+</span><span id="L-13"><a href="#L-13"><span class="linenos">13</span></a>
+</span><span id="L-14"><a href="#L-14"><span class="linenos">14</span></a><span class="n">__all__</span> <span class="o">=</span> <span class="p">[]</span>
+</span></pre>
+        </div>
+      </section>
+    </main>
+  </body>
+</html>
diff --git a/docs_templates/custom.css b/docs_templates/custom.css
deleted file mode 100644
index 891ae0a..0000000
--- a/docs_templates/custom.css
+++ /dev/null
@@ -1,10 +0,0 @@
-.docstring > pre {
-  all: unset;
-}
-.docstring > pre > code {
-  all: unset;
-  visibility: hidden;
-}
-.docstring > pre > code[data-processed="true"] {
-  visibility: visible;
-}
diff --git a/docs_templates/module.html.jinja2 b/docs_templates/module.html.jinja2
deleted file mode 100644
index c8a6bc7..0000000
--- a/docs_templates/module.html.jinja2
+++ /dev/null
@@ -1,12 +0,0 @@
-{% extends "default/module.html.jinja2" %}
-{% block module_info %}
-  <section class="module-info">
-    {{ docstring(module) }}
-    <script type="module">
-      import mermaid from "https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs";
-      const diagram = document.getElementsByTagName("code")[0];
-      mermaid.initialize({ startOnLoad: false, theme: "forest" });
-      await mermaid.run({ nodes: [diagram] });
-    </script>
-  </section>
-{% endblock %}
diff --git a/pdm.lock b/pdm.lock
index 2a6b65d..d4e3e07 100644
--- a/pdm.lock
+++ b/pdm.lock
@@ -23,9 +23,12 @@ dependencies = [
 
 [[package]]
 name = "attrs"
-version = "22.2.0"
-requires_python = ">=3.6"
+version = "23.1.0"
+requires_python = ">=3.7"
 summary = "Classes Without Boilerplate"
+dependencies = [
+    "importlib-metadata; python_version < \"3.8\"",
+]
 
 [[package]]
 name = "certifi"
@@ -41,12 +44,6 @@ dependencies = [
     "pycparser",
 ]
 
-[[package]]
-name = "charset-normalizer"
-version = "3.1.0"
-requires_python = ">=3.7.0"
-summary = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
-
 [[package]]
 name = "colorama"
 version = "0.4.6"
@@ -55,7 +52,7 @@ summary = "Cross-platform colored terminal text."
 
 [[package]]
 name = "cryptography"
-version = "39.0.2"
+version = "40.0.2"
 requires_python = ">=3.6"
 summary = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
 dependencies = [
@@ -109,7 +106,7 @@ summary = "Internationalized Domain Names in Applications (IDNA)"
 
 [[package]]
 name = "importlib-metadata"
-version = "6.1.0"
+version = "6.6.0"
 requires_python = ">=3.7"
 summary = "Read metadata from Python packages"
 dependencies = [
@@ -146,13 +143,13 @@ summary = "Safely add untrusted strings to HTML/XML markup."
 
 [[package]]
 name = "packaging"
-version = "23.0"
+version = "23.1"
 requires_python = ">=3.7"
 summary = "Core utilities for Python packages"
 
 [[package]]
 name = "pdoc"
-version = "13.0.1"
+version = "13.1.1"
 requires_python = ">=3.7"
 summary = "API Documentation for Python Projects"
 dependencies = [
@@ -179,8 +176,8 @@ summary = "C parser in Python"
 
 [[package]]
 name = "pygments"
-version = "2.14.0"
-requires_python = ">=3.6"
+version = "2.15.1"
+requires_python = ">=3.7"
 summary = "Pygments is a syntax highlighting package written in Python."
 
 [[package]]
@@ -199,18 +196,6 @@ dependencies = [
     "tomli>=1.0.0; python_version < \"3.11\"",
 ]
 
-[[package]]
-name = "requests"
-version = "2.28.2"
-requires_python = ">=3.7, <4"
-summary = "Python HTTP for Humans."
-dependencies = [
-    "certifi>=2017.4.17",
-    "charset-normalizer<4,>=2",
-    "idna<4,>=2.5",
-    "urllib3<1.27,>=1.21.1",
-]
-
 [[package]]
 name = "rfc3986"
 version = "1.5.0"
@@ -248,6 +233,16 @@ dependencies = [
     "typing-extensions>=3.10.0; python_version < \"3.10\"",
 ]
 
+[[package]]
+name = "starlette-csrf"
+version = "2.0.0"
+requires_python = ">=3.7"
+summary = "Starlette middleware implementing Double Submit Cookie technique to mitigate CSRF"
+dependencies = [
+    "itsdangerous<3.0.0,>=2.0.1",
+    "starlette>=0.14.2",
+]
+
 [[package]]
 name = "tomli"
 version = "2.0.1"
@@ -260,12 +255,6 @@ version = "4.5.0"
 requires_python = ">=3.7"
 summary = "Backported and Experimental Type Hints for Python 3.7+"
 
-[[package]]
-name = "urllib3"
-version = "1.26.15"
-requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
-summary = "HTTP library with thread-safe connection pooling, file post, and more."
-
 [[package]]
 name = "wheel"
 version = "0.40.0"
@@ -280,8 +269,8 @@ summary = "Backport of pathlib-compatible object wrapper for zip files"
 
 [metadata]
 lock_version = "4.2"
-groups = ["default", "dev"]
-content_hash = "sha256:b6a6a8c5dddf243e42c8ce93a5307a0a1b2f856dbcfdaf8b9d8fb762c1f85296"
+groups = ["default", "csrf", "dev"]
+content_hash = "sha256:3a1d6a3051257994cb8dbca563e7869477cccdf549c26d031566600882d6f8d1"
 
 [metadata.files]
 "anyio 3.6.2" = [
@@ -292,9 +281,9 @@ content_hash = "sha256:b6a6a8c5dddf243e42c8ce93a5307a0a1b2f856dbcfdaf8b9d8fb762c
     {url = "https://files.pythonhosted.org/packages/2b/03/13dde6512ad7b4557eb792fbcf0c653af6076b81e5941d36ec61f7ce6028/astunparse-1.6.3-py2.py3-none-any.whl", hash = "sha256:c2652417f2c8b5bb325c885ae329bdf3f86424075c4fd1a128674bc6fba4b8e8"},
     {url = "https://files.pythonhosted.org/packages/f3/af/4182184d3c338792894f34a62672919db7ca008c89abee9b564dd34d8029/astunparse-1.6.3.tar.gz", hash = "sha256:5ad93a8456f0d084c3456d059fd9a92cce667963232cbf763eac3bc5b7940872"},
 ]
-"attrs 22.2.0" = [
-    {url = "https://files.pythonhosted.org/packages/21/31/3f468da74c7de4fcf9b25591e682856389b3400b4b62f201e65f15ea3e07/attrs-22.2.0.tar.gz", hash = "sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99"},
-    {url = "https://files.pythonhosted.org/packages/fb/6e/6f83bf616d2becdf333a1640f1d463fef3150e2e926b7010cb0f81c95e88/attrs-22.2.0-py3-none-any.whl", hash = "sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836"},
+"attrs 23.1.0" = [
+    {url = "https://files.pythonhosted.org/packages/97/90/81f95d5f705be17872843536b1868f351805acf6971251ff07c1b8334dbb/attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"},
+    {url = "https://files.pythonhosted.org/packages/f0/eb/fcb708c7bf5056045e9e98f62b93bd7467eb718b0202e7698eb11d66416c/attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"},
 ]
 "certifi 2022.12.7" = [
     {url = "https://files.pythonhosted.org/packages/37/f7/2b1b0ec44fdc30a3d31dfebe52226be9ddc40cd6c0f34ffc8923ba423b69/certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"},
@@ -366,111 +355,30 @@ content_hash = "sha256:b6a6a8c5dddf243e42c8ce93a5307a0a1b2f856dbcfdaf8b9d8fb762c
     {url = "https://files.pythonhosted.org/packages/f9/96/fc9e118c47b7adc45a0676f413b4a47554e5f3b6c99b8607ec9726466ef1/cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"},
     {url = "https://files.pythonhosted.org/packages/ff/fe/ac46ca7b00e9e4f9c62e7928a11bc9227c86e2ff43526beee00cdfb4f0e8/cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"},
 ]
-"charset-normalizer 3.1.0" = [
-    {url = "https://files.pythonhosted.org/packages/00/47/f14533da238134f5067fb1d951eb03d5c4be895d6afb11c7ebd07d111acb/charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a5fc78f9e3f501a1614a98f7c54d3969f3ad9bba8ba3d9b438c3bc5d047dd28"},
-    {url = "https://files.pythonhosted.org/packages/01/c7/0407de35b70525dba2a58a2724a525cf882ee76c3d2171d834463c5d2881/charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3573d376454d956553c356df45bb824262c397c6e26ce43e8203c4c540ee0acb"},
-    {url = "https://files.pythonhosted.org/packages/05/f3/86b5fcb5c8fe8b4231362918a7c4d8f549c56561c5fdb495a3c5b41c6862/charset_normalizer-3.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:65ed923f84a6844de5fd29726b888e58c62820e0769b76565480e1fdc3d062f8"},
-    {url = "https://files.pythonhosted.org/packages/07/6b/98d41a0221991a806e88c95bfeecf8935fbf465b02eb4b469770d572183a/charset_normalizer-3.1.0-cp37-cp37m-win32.whl", hash = "sha256:4155b51ae05ed47199dc5b2a4e62abccb274cee6b01da5b895099b61b1982974"},
-    {url = "https://files.pythonhosted.org/packages/0a/67/8d3d162ec6641911879651cdef670c3c6136782b711d7f8e82e2fffe06e0/charset_normalizer-3.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6734e606355834f13445b6adc38b53c0fd45f1a56a9ba06c2058f86893ae8017"},
-    {url = "https://files.pythonhosted.org/packages/12/12/c5c39f5a149cd6788d2e40cea5618bae37380e2754fcdf53dc9e01bdd33a/charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3dc5b6a8ecfdc5748a7e429782598e4f17ef378e3e272eeb1340ea57c9109f41"},
-    {url = "https://files.pythonhosted.org/packages/12/68/4812f9b05ac0a2b7619ac3dd7d7e3fc52c12006b84617021c615fc2fcf42/charset_normalizer-3.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:38e812a197bf8e71a59fe55b757a84c1f946d0ac114acafaafaf21667a7e169e"},
-    {url = "https://files.pythonhosted.org/packages/13/b7/21729a6d512246aa0bb872b90aea0d9fcd1b293762cdb1d1d33c01140074/charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f645caaf0008bacf349875a974220f1f1da349c5dbe7c4ec93048cdc785a3326"},
-    {url = "https://files.pythonhosted.org/packages/16/58/19fd2f62e6ff44ba0db0cd44b584790555e2cde09293149f4409d654811b/charset_normalizer-3.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b82fab78e0b1329e183a65260581de4375f619167478dddab510c6c6fb04d9b6"},
-    {url = "https://files.pythonhosted.org/packages/18/36/7ae10a3dd7f9117b61180671f8d1e4802080cca88ad40aaabd3dad8bab0e/charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ca564606d2caafb0abe6d1b5311c2649e8071eb241b2d64e75a0d0065107e62"},
-    {url = "https://files.pythonhosted.org/packages/1c/9b/de2adc43345623da8e7c958719528a42b6d87d2601017ce1187d43b8a2d7/charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:10c93628d7497c81686e8e5e557aafa78f230cd9e77dd0c40032ef90c18f2230"},
-    {url = "https://files.pythonhosted.org/packages/1f/be/c6c76cf8fcf6918922223203c83ba8192eff1c6a709e8cfec7f5ca3e7d2d/charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d16fd5252f883eb074ca55cb622bc0bee49b979ae4e8639fff6ca3ff44f9f854"},
-    {url = "https://files.pythonhosted.org/packages/21/16/1b0d8fdcb81bbf180976af4f867ce0f2244d303ab10d452fde361dec3b5c/charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:11d117e6c63e8f495412d37e7dc2e2fff09c34b2d09dbe2bee3c6229577818be"},
-    {url = "https://files.pythonhosted.org/packages/23/13/cf5d7bb5bc95f120df64d6c470581189df51d7f011560b2a06a395b7a120/charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:b06f0d3bf045158d2fb8837c5785fe9ff9b8c93358be64461a1089f5da983137"},
-    {url = "https://files.pythonhosted.org/packages/26/20/83e1804a62b25891c4e770c94d9fd80233bbb3f2a51c4fadee7a196e5a5b/charset_normalizer-3.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:3160a0fd9754aab7d47f95a6b63ab355388d890163eb03b2d2b87ab0a30cfa59"},
-    {url = "https://files.pythonhosted.org/packages/2c/2f/ec805104098085728b7cb610deede7195c6fa59f51942422f02cc427b6f6/charset_normalizer-3.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c60b9c202d00052183c9be85e5eaf18a4ada0a47d188a83c8f5c5b23252f649"},
-    {url = "https://files.pythonhosted.org/packages/2e/25/3eab2b38fef9ae59f7b4e9c1e62eb50609d911867e5acabace95fe25c0b1/charset_normalizer-3.1.0-cp310-cp310-win32.whl", hash = "sha256:12d1a39aa6b8c6f6248bb54550efcc1c38ce0d8096a146638fd4738e42284448"},
-    {url = "https://files.pythonhosted.org/packages/31/8b/81c3515a69d06b501fcce69506af57a7a19bd9f42cabd1a667b1b40f2c55/charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:80d1543d58bd3d6c271b66abf454d437a438dff01c3e62fdbcd68f2a11310d4b"},
-    {url = "https://files.pythonhosted.org/packages/33/10/c87ba15f779f8251ae55fa147631339cd91e7af51c3c133d2687c6e41800/charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ea9f9c6034ea2d93d9147818f17c2a0860d41b71c38b9ce4d55f21b6f9165a11"},
-    {url = "https://files.pythonhosted.org/packages/33/97/9967fb2d364a9da38557e4af323abcd58cc05bdd8f77e9fd5ae4882772cc/charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fa558996782fc226b529fdd2ed7866c2c6ec91cee82735c98a197fae39f706"},
-    {url = "https://files.pythonhosted.org/packages/45/3d/fa2683f5604f99fba5098a7313e5d4846baaecbee754faf115907f21a85f/charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b116502087ce8a6b7a5f1814568ccbd0e9f6cfd99948aa59b0e241dc57cf739f"},
-    {url = "https://files.pythonhosted.org/packages/4e/11/f7077d78b18aca8ea3186a706c0221aa2bc34c442a3d3bdf3ad401a29052/charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ac3775e3311661d4adace3697a52ac0bab17edd166087d493b52d4f4f553f9f0"},
-    {url = "https://files.pythonhosted.org/packages/4f/18/92866f050f7114ba38aba4f4a69f83cc2a25dc2e5a8af4b44fd1bfd6d528/charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:74db0052d985cf37fa111828d0dd230776ac99c740e1a758ad99094be4f1803d"},
-    {url = "https://files.pythonhosted.org/packages/4f/7c/af43743567a7da2a069b4f9fa31874c3c02b963cd1fb84fe1e7568a567e6/charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:6f4f4668e1831850ebcc2fd0b1cd11721947b6dc7c00bf1c6bd3c929ae14f2c7"},
-    {url = "https://files.pythonhosted.org/packages/4f/a2/9031ba4a008e11a21d7b7aa41751290d2f2035a2f14ecb6e589771a17c47/charset_normalizer-3.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e0ac8959c929593fee38da1c2b64ee9778733cdf03c482c9ff1d508b6b593b2b"},
-    {url = "https://files.pythonhosted.org/packages/56/24/5f2dedcf3d0673931b6200c410832ae44b376848bc899dbf1fa6c91c4ebe/charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cb7b2ab0188829593b9de646545175547a70d9a6e2b63bf2cd87a0a391599324"},
-    {url = "https://files.pythonhosted.org/packages/5d/2b/4d8c80400c04ae3c8dbc847de092e282b5c7b17f8f9505d68bb3e5815c71/charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:cf6511efa4801b9b38dc5546d7547d5b5c6ef4b081c60b23e4d941d0eba9cbeb"},
-    {url = "https://files.pythonhosted.org/packages/61/e3/ad9ae58b28482d1069eba1edec2be87701f5dd6fd6024a665020d66677a0/charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:628c985afb2c7d27a4800bfb609e03985aaecb42f955049957814e0491d4006d"},
-    {url = "https://files.pythonhosted.org/packages/67/30/dbab1fe5ab2ce5d3d517ad9936170d896e9687f3860a092519f1fe359812/charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e89df2958e5159b811af9ff0f92614dabf4ff617c03a4c1c6ff53bf1c399e0e1"},
-    {url = "https://files.pythonhosted.org/packages/67/df/660e9665ace7ad711e275194a86cb757fb4d4e513fae5ff3d39573db4984/charset_normalizer-3.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d7fc3fca01da18fbabe4625d64bb612b533533ed10045a2ac3dd194bfa656b60"},
-    {url = "https://files.pythonhosted.org/packages/68/77/af702eba147ba963b27eb00832cef6b8c4cb9fcf7404a476993876434b93/charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:73dc03a6a7e30b7edc5b01b601e53e7fc924b04e1835e8e407c12c037e81adbd"},
-    {url = "https://files.pythonhosted.org/packages/69/22/66351781e668158feef71c5e3b059a79ecc9efc3ef84a45888b0f3a933d5/charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1435ae15108b1cb6fffbcea2af3d468683b7afed0169ad718451f8db5d1aff6f"},
-    {url = "https://files.pythonhosted.org/packages/6d/59/59a3f4d8a59ee270da77f9e954a0e284c9d6884d39ec69d696d9aa5ff2f2/charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20064ead0717cf9a73a6d1e779b23d149b53daf971169289ed2ed43a71e8d3b0"},
-    {url = "https://files.pythonhosted.org/packages/72/90/667a6bc6abe42fc10adf4cd2c1e1c399d78e653dbac4c8018350843d4ab7/charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c84132a54c750fda57729d1e2599bb598f5fa0344085dbde5003ba429a4798c0"},
-    {url = "https://files.pythonhosted.org/packages/74/5f/361202de730532028458b729781b8435f320e31a622c27f30e25eec80513/charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de5695a6f1d8340b12a5d6d4484290ee74d61e467c39ff03b39e30df62cf83a0"},
-    {url = "https://files.pythonhosted.org/packages/74/f1/d0b8385b574f7e086fb6709e104b696707bd3742d54a6caf0cebbb7e975b/charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:49919f8400b5e49e961f320c735388ee686a62327e773fa5b3ce6721f7e785ce"},
-    {url = "https://files.pythonhosted.org/packages/76/ad/516fed8ffaf02e7a01cd6f6e9d101a6dec64d4db53bec89d30802bf30a96/charset_normalizer-3.1.0-cp38-cp38-win32.whl", hash = "sha256:12a2b561af122e3d94cdb97fe6fb2bb2b82cef0cdca131646fdb940a1eda04f0"},
-    {url = "https://files.pythonhosted.org/packages/82/b9/51b66a647be8685dee75b7807e0f750edf5c1e4f29bc562ad285c501e3c7/charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d2686f91611f9e17f4548dbf050e75b079bbc2a82be565832bc8ea9047b61c8c"},
-    {url = "https://files.pythonhosted.org/packages/84/23/f60cda6c70ae922ad78368982f06e7fef258fba833212f26275fe4727dc4/charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:dd5653e67b149503c68c4018bf07e42eeed6b4e956b24c00ccdf93ac79cdff84"},
-    {url = "https://files.pythonhosted.org/packages/85/e8/18d408d8fe29a56012c10d6b15960940b83f06620e9d7481581cdc6d9901/charset_normalizer-3.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f8303414c7b03f794347ad062c0516cee0e15f7a612abd0ce1e25caf6ceb47df"},
-    {url = "https://files.pythonhosted.org/packages/94/70/23981e7bf098efbc4037e7c66d28a10e950d9296c08c6dea8ef290f9c79e/charset_normalizer-3.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f6c7a8a57e9405cad7485f4c9d3172ae486cfef1344b5ddd8e5239582d7355e"},
-    {url = "https://files.pythonhosted.org/packages/9a/f1/ff81439aa09070fee64173e6ca6ce1342f2b1cca997bcaae89e443812684/charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3af8e0f07399d3176b179f2e2634c3ce9c1301379a6b8c9c9aeecd481da494f"},
-    {url = "https://files.pythonhosted.org/packages/9e/62/a1e0a8f8830c92014602c8a88a1a20b8a68d636378077381f671e6e1cec9/charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaf53a6cebad0eae578f062c7d462155eada9c172bd8c4d250b8c1d8eb7f916a"},
-    {url = "https://files.pythonhosted.org/packages/a2/6c/5167f08da5298f383036c33cb749ab5b3405fd07853edc8314c6882c01b8/charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:0be65ccf618c1e7ac9b849c315cc2e8a8751d9cfdaa43027d4f6624bd587ab7e"},
-    {url = "https://files.pythonhosted.org/packages/a4/03/355281b62c26712a50c6a9dd75339d8cdd58488fd7bf2556ba1320ebd315/charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1e8fcdd8f672a1c4fc8d0bd3a2b576b152d2a349782d1eb0f6b8e52e9954731d"},
-    {url = "https://files.pythonhosted.org/packages/a9/83/138d2624fdbcb62b7e14715eb721d44347e41a1b4c16544661e940793f49/charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:53d0a3fa5f8af98a1e261de6a3943ca631c526635eb5817a87a59d9a57ebf48f"},
-    {url = "https://files.pythonhosted.org/packages/ac/7f/62d5dff4e9cb993e4b0d4ea78a74cc84d7d92120879529e0ce0965765936/charset_normalizer-3.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8f25e17ab3039b05f762b0a55ae0b3632b2e073d9c8fc88e89aca31a6198e88f"},
-    {url = "https://files.pythonhosted.org/packages/ac/c5/990bc41a98b7fa2677c665737fdf278bb74ad4b199c56b6b564b3d4cbfc5/charset_normalizer-3.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3a06f32c9634a8705f4ca9946d667609f52cf130d5548881401f1eb2c39b1e2c"},
-    {url = "https://files.pythonhosted.org/packages/ad/83/994bfca99e29f1bab66b9248e739360ee70b5aae0a5ee488cd776501edbc/charset_normalizer-3.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:cca4def576f47a09a943666b8f829606bcb17e2bc2d5911a46c8f8da45f56755"},
-    {url = "https://files.pythonhosted.org/packages/b0/55/d8ef4c8c7d2a8b3a16e7d9b03c59475c2ee96a0e0c90b14c99faaac0ee3b/charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6f5c2e7bc8a4bf7c426599765b1bd33217ec84023033672c1e9a8b35eaeaaaf8"},
-    {url = "https://files.pythonhosted.org/packages/bb/dc/58fdef3ab85e8e7953a8b89ef1d2c06938b8ad88d9617f22967e1a90e6b8/charset_normalizer-3.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11d3bcb7be35e7b1bba2c23beedac81ee893ac9871d0ba79effc7fc01167db6c"},
-    {url = "https://files.pythonhosted.org/packages/bc/08/7e7c97399806366ca515a049c3a1e4b644a6a2048bed16e5e67bfaafd0aa/charset_normalizer-3.1.0-cp311-cp311-win32.whl", hash = "sha256:c36bcbc0d5174a80d6cccf43a0ecaca44e81d25be4b7f90f0ed7bcfbb5a00909"},
-    {url = "https://files.pythonhosted.org/packages/bc/92/ac692a303e53cdc8852ce72b1ac364b493ca5c9206a5c8db5b30a7f3019c/charset_normalizer-3.1.0-cp39-cp39-win32.whl", hash = "sha256:a04f86f41a8916fe45ac5024ec477f41f886b3c435da2d4e3d2709b22ab02af1"},
-    {url = "https://files.pythonhosted.org/packages/c2/35/dfb4032f5712747d3dcfdd19d0768f6d8f60910ae24ed066ecbf442be013/charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:891cf9b48776b5c61c700b55a598621fdb7b1e301a550365571e9624f270c203"},
-    {url = "https://files.pythonhosted.org/packages/c6/ab/43ea052756b2f2dcb6a131897811c0e2704b0288f090336217d3346cd682/charset_normalizer-3.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:04eefcee095f58eaabe6dc3cc2262f3bcd776d2c67005880894f447b3f2cb9c1"},
-    {url = "https://files.pythonhosted.org/packages/c9/8c/a76dd9f2c8803eb147e1e715727f5c3ba0ef39adaadf66a7b3698c113180/charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bd7163182133c0c7701b25e604cf1611c0d87712e56e88e7ee5d72deab3e76b5"},
-    {url = "https://files.pythonhosted.org/packages/cc/f6/21a66e524658bd1dd7b89ac9d1ee8f7823f2d9701a2fbc458ab9ede53c63/charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75f2568b4189dda1c567339b48cba4ac7384accb9c2a7ed655cd86b04055c795"},
-    {url = "https://files.pythonhosted.org/packages/d1/ff/51fe7e6446415f143b159740c727850172bc35622b2a06dde3354bdebaf3/charset_normalizer-3.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:830d2948a5ec37c386d3170c483063798d7879037492540f10a475e3fd6f244b"},
-    {url = "https://files.pythonhosted.org/packages/d5/92/86c0f0e66e897f6818c46dadef328a5b345d061688f9960fc6ca1fd03dbe/charset_normalizer-3.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6baf0baf0d5d265fa7944feb9f7451cc316bfe30e8df1a61b1bb08577c554f31"},
-    {url = "https://files.pythonhosted.org/packages/d7/4c/37ad75674e8c6bc22ab01bef673d2d6e46ee44203498c9a26aa23959afe5/charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e1b25e3ad6c909f398df8921780d6a3d120d8c09466720226fc621605b6f92b1"},
-    {url = "https://files.pythonhosted.org/packages/d8/ca/a7ff600781bf1e5f702ba26bb82f2ba1d3a873a3f8ad73cc44c79dfaefa9/charset_normalizer-3.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7381c66e0561c5757ffe616af869b916c8b4e42b367ab29fedc98481d1e74e14"},
-    {url = "https://files.pythonhosted.org/packages/dd/39/6276cf5a395ffd39b77dadf0e2fcbfca8dbfe48c56ada250c40086055143/charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac0aa6cd53ab9a31d397f8303f92c42f534693528fafbdb997c82bae6e477ad9"},
-    {url = "https://files.pythonhosted.org/packages/e1/7c/398600268fc98b7e007f5a716bd60903fff1ecff75e45f5700212df5cd76/charset_normalizer-3.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9a3267620866c9d17b959a84dd0bd2d45719b817245e49371ead79ed4f710d19"},
-    {url = "https://files.pythonhosted.org/packages/e1/b4/53678b2a14e0496fc167fe9b9e726ad33d670cfd2011031aa5caeee6b784/charset_normalizer-3.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0c95f12b74681e9ae127728f7e5409cbbef9cd914d5896ef238cc779b8152373"},
-    {url = "https://files.pythonhosted.org/packages/e5/aa/9d2d60d6a566423da96c15cd11cbb88a70f9aff9a4db096094ee19179cab/charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:abc1185d79f47c0a7aaf7e2412a0eb2c03b724581139193d2d82b3ad8cbb00ac"},
-    {url = "https://files.pythonhosted.org/packages/e6/98/a3f65f57651da1cecaed91d6f75291995d56c97442fa2a43d2a421139adf/charset_normalizer-3.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:322102cdf1ab682ecc7d9b1c5eed4ec59657a65e1c146a0da342b78f4112db23"},
-    {url = "https://files.pythonhosted.org/packages/ea/38/d31c7906c4be13060c1a5034087966774ef33ab57ff2eee76d71265173c3/charset_normalizer-3.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e633940f28c1e913615fd624fcdd72fdba807bf53ea6925d6a588e84e1151531"},
-    {url = "https://files.pythonhosted.org/packages/ef/81/14b3b8f01ddaddad6cdec97f2f599aa2fa466bd5ee9af99b08b7713ccd29/charset_normalizer-3.1.0-py3-none-any.whl", hash = "sha256:3d9098b479e78c85080c98e1e35ff40b4a31d8953102bb0fd7d1b6f8a2111a3d"},
-    {url = "https://files.pythonhosted.org/packages/f2/b7/e21e16c98575616f4ce09dc766dbccdac0ca119c176b184d46105e971a84/charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fca62a8301b605b954ad2e9c3666f9d97f63872aa4efcae5492baca2056b74ab"},
-    {url = "https://files.pythonhosted.org/packages/f2/d7/6ee92c11eda3f3c9cac1e059901092bfdf07388be7d2e60ac627527eee62/charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:5f008525e02908b20e04707a4f704cd286d94718f48bb33edddc7d7b584dddc1"},
-    {url = "https://files.pythonhosted.org/packages/f4/0a/8c03913ed1eca9d831db0c28759edb6ce87af22bb55dbc005a52525a75b6/charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:22908891a380d50738e1f978667536f6c6b526a2064156203d418f4856d6e86a"},
-    {url = "https://files.pythonhosted.org/packages/f6/0f/de1c4030fd669e6719277043e3b0f152a83c118dd1020cf85b51d443d04a/charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3747443b6a904001473370d7810aa19c3a180ccd52a7157aacc264a5ac79265e"},
-    {url = "https://files.pythonhosted.org/packages/f8/ed/500609cb2457b002242b090c814549997424d72690ef3058cfdfca91f68b/charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:78cacd03e79d009d95635e7d6ff12c21eb89b894c354bd2b2ed0b4763373693b"},
-    {url = "https://files.pythonhosted.org/packages/fa/8e/2e5c742c3082bce3eea2ddd5b331d08050cda458bc362d71c48e07a44719/charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:04afa6387e2b282cf78ff3dbce20f0cc071c12dc8f685bd40960cc68644cfea6"},
-    {url = "https://files.pythonhosted.org/packages/ff/d7/8d757f8bd45be079d76309248845a04f09619a7b17d6dfc8c9ff6433cac2/charset-normalizer-3.1.0.tar.gz", hash = "sha256:34e0a2f9c370eb95597aae63bf85eb5e96826d81e3dcf88b8886012906f509b5"},
-]
 "colorama 0.4.6" = [
     {url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
     {url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
 ]
-"cryptography 39.0.2" = [
-    {url = "https://files.pythonhosted.org/packages/06/ea/d998c35ac871396749f14a4b4e82f080422182e1830f02959e893abd3016/cryptography-39.0.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e944fe07b6f229f4c1a06a7ef906a19652bdd9fd54c761b0ff87e83ae7a30354"},
-    {url = "https://files.pythonhosted.org/packages/0b/20/f406c0d2edb7b3974c39099816795d629bbd8716cd41cda8c3c4703de095/cryptography-39.0.2-cp36-abi3-win32.whl", hash = "sha256:c43ac224aabcbf83a947eeb8b17eaf1547bce3767ee2d70093b461f31729a480"},
-    {url = "https://files.pythonhosted.org/packages/13/40/acfea5abe60f483bfba44a24419fa89d584e1e93dca750b800805ef272b9/cryptography-39.0.2-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:30b1d1bfd00f6fc80d11300a29f1d8ab2b8d9febb6ed4a38a76880ec564fae84"},
-    {url = "https://files.pythonhosted.org/packages/1e/85/d5b768b45e564a66fc5ba6344145334208f01d64939adcb8c4032545d164/cryptography-39.0.2-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:103e8f7155f3ce2ffa0049fe60169878d47a4364b277906386f8de21c9234aa1"},
-    {url = "https://files.pythonhosted.org/packages/26/d2/85480f4e754375c6d8e4a18cc8d2f28ef1984cf2843395c4d1ea396331d3/cryptography-39.0.2-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffd394c7896ed7821a6d13b24657c6a34b6e2650bd84ae063cf11ccffa4f1a97"},
-    {url = "https://files.pythonhosted.org/packages/3c/0c/ac188ca210fbc02102d34ad8dba6956fe16fc566e5c5110a7f7bdbd30138/cryptography-39.0.2-cp36-abi3-macosx_10_12_x86_64.whl", hash = "sha256:23df8ca3f24699167daf3e23e51f7ba7334d504af63a94af468f468b975b7dd7"},
-    {url = "https://files.pythonhosted.org/packages/3c/5a/6c180b745336f989e9b298e1790af0ef5b37640edb861fc536b5663726e3/cryptography-39.0.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:eb40fe69cfc6f5cdab9a5ebd022131ba21453cf7b8a7fd3631f45bbf52bed612"},
-    {url = "https://files.pythonhosted.org/packages/4f/0e/55b8cff87b572da828e9c6b7e7c5ecb9dc955b551ab863c28464a15f6451/cryptography-39.0.2-cp36-abi3-win_amd64.whl", hash = "sha256:788b3921d763ee35dfdb04248d0e3de11e3ca8eb22e2e48fef880c42e1f3c8f9"},
-    {url = "https://files.pythonhosted.org/packages/6d/5b/516dc11fa0a638cb707293ad44cc1cb93924bb4b5ba03881dfdb819e23b0/cryptography-39.0.2-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:d15809e0dbdad486f4ad0979753518f47980020b7a34e9fc56e8be4f60702fac"},
-    {url = "https://files.pythonhosted.org/packages/77/19/47d55b3f609fc03b6f80c63820996671dfccb28e1d07427dd81319d514d5/cryptography-39.0.2-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:50cadb9b2f961757e712a9737ef33d89b8190c3ea34d0fb6675e00edbe35d074"},
-    {url = "https://files.pythonhosted.org/packages/7b/49/05debd3f2dfc43987063575cffb58116daf80b3db278555ecb1af765a2bd/cryptography-39.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:8bc0008ef798231fac03fe7d26e82d601d15bd16f3afaad1c6113771566570f3"},
-    {url = "https://files.pythonhosted.org/packages/9c/30/e787edf59f35192799d340a0a36976870ce487ba32948f086c29dc5d54ab/cryptography-39.0.2-cp36-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:8f35c17bd4faed2bc7797d2a66cbb4f986242ce2e30340ab832e5d99ae60e011"},
-    {url = "https://files.pythonhosted.org/packages/9e/a0/4c0c8b827f430246b48a0f2415a432427d365c77b04a911c5139ae9c79b1/cryptography-39.0.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:6236a9610c912b129610eb1a274bdc1350b5df834d124fa84729ebeaf7da42c3"},
-    {url = "https://files.pythonhosted.org/packages/b2/54/2b2a610b6eced5a7be96c0d2e214be9cee6824b9494756e6043470ca594f/cryptography-39.0.2-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fa507318e427169ade4e9eccef39e9011cdc19534f55ca2f36ec3f388c1f70f3"},
-    {url = "https://files.pythonhosted.org/packages/c5/8a/6dcd53c995506d4ff0de3a7da2202715654493fd12d7875f2a43b3a44150/cryptography-39.0.2-cp36-abi3-macosx_10_12_universal2.whl", hash = "sha256:2725672bb53bb92dc7b4150d233cd4b8c59615cd8288d495eaa86db00d4e5c06"},
-    {url = "https://files.pythonhosted.org/packages/c6/c4/354c78bade0270f951a14db9f8248ab975ca7df050476dc3759831e52a7f/cryptography-39.0.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:35d658536b0a4117c885728d1a7032bdc9a5974722ae298d6c533755a6ee3915"},
-    {url = "https://files.pythonhosted.org/packages/cb/76/c9fa9cda16ac5b47b5bb29b3e3b8536ca3584458e889a6df82bbee18e693/cryptography-39.0.2-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:e029b844c21116564b8b61216befabca4b500e6816fa9f0ba49527653cae2108"},
-    {url = "https://files.pythonhosted.org/packages/d3/26/da69282ae3b350ee869536994e6816ac77057a7b5970068fabe56c644624/cryptography-39.0.2-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:5f8c682e736513db7d04349b4f6693690170f95aac449c56f97415c6980edef5"},
-    {url = "https://files.pythonhosted.org/packages/d6/99/12d3b9c8df83b52799f9994da17bb67bb4565c418b3a8284ed1f79b692e1/cryptography-39.0.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc0521cce2c1d541634b19f3ac661d7a64f9555135e9d8af3980965be717fd4a"},
-    {url = "https://files.pythonhosted.org/packages/e8/5c/9e47aac90fb5923d09c413909af6bf6ad4af2bfeeff707a2485c3f2af8be/cryptography-39.0.2-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:d7d84a512a59f4412ca8549b01f94be4161c94efc598bf09d027d67826beddc0"},
-    {url = "https://files.pythonhosted.org/packages/f4/6d/1afb19efbe093f0b1af7a788bb8a693e495dc6c1d2139316b05b40f5e1dd/cryptography-39.0.2-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:b49a88ff802e1993b7f749b1eeb31134f03c8d5c956e3c125c75558955cda536"},
-    {url = "https://files.pythonhosted.org/packages/f7/c0/daaeedc40e3385f01bb1af8c001ac214dcea6716b61efebabf9066b6f619/cryptography-39.0.2-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:e8a0772016feeb106efd28d4a328e77dc2edae84dfbac06061319fdb669ff828"},
-    {url = "https://files.pythonhosted.org/packages/fa/f3/f4b8c175ea9a1de650b0085858059050b7953a93d66c97ed89b93b232996/cryptography-39.0.2.tar.gz", hash = "sha256:bc5b871e977c8ee5a1bbc42fa8d19bcc08baf0c51cbf1586b0e87a2694dde42f"},
+"cryptography 40.0.2" = [
+    {url = "https://files.pythonhosted.org/packages/0d/91/b2efda2ffb30b1623016d8e8ea6f59dde22b9bc86c0883bc12d965c53dca/cryptography-40.0.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4df2af28d7bedc84fe45bd49bc35d710aede676e2a4cb7fc6d103a2adc8afe4d"},
+    {url = "https://files.pythonhosted.org/packages/41/96/e4c439905077508e78ae15577fdd302c1e582d0bc5f96fcc761da1681dd2/cryptography-40.0.2-cp36-abi3-win32.whl", hash = "sha256:aecbb1592b0188e030cb01f82d12556cf72e218280f621deed7d806afd2113f9"},
+    {url = "https://files.pythonhosted.org/packages/55/9f/53e0df7b81f86967d8997c77b71c5255d3bcabfac0c346b1cff061b80e03/cryptography-40.0.2-cp36-abi3-win_amd64.whl", hash = "sha256:b12794f01d4cacfbd3177b9042198f3af1c856eedd0a98f10f141385c809a14b"},
+    {url = "https://files.pythonhosted.org/packages/5c/26/a5bcec07b84ce9064659e15a526976efeb1971cc7fcc61fc71f6a6b659ce/cryptography-40.0.2-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4f01c9863da784558165f5d4d916093737a75203a5c5286fde60e503e4276c7a"},
+    {url = "https://files.pythonhosted.org/packages/5e/12/e3eb644d2c040a083f3b3ee12553fe2ac273ef7525722438d2ad141d984f/cryptography-40.0.2-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:956ba8701b4ffe91ba59665ed170a2ebbdc6fc0e40de5f6059195d9f2b33ca0e"},
+    {url = "https://files.pythonhosted.org/packages/66/f1/dbf368e3565c4b9b7784b4f595e45ff3b3cde57a9d54aeee9681d2c1a7e6/cryptography-40.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7a38250f433cd41df7fcb763caa3ee9362777fdb4dc642b9a349721d2bf47404"},
+    {url = "https://files.pythonhosted.org/packages/72/68/6e942224400261a3f947df8abad1ffe95e338e2466f7a0b5b87f33d8a196/cryptography-40.0.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:48f388d0d153350f378c7f7b41497a54ff1513c816bcbbcafe5b829e59b9ce5b"},
+    {url = "https://files.pythonhosted.org/packages/75/9c/446d0209840eaa639abc564ccac3a8b4c716629bb3424d2f4bdb618cbf34/cryptography-40.0.2-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:cbaba590180cba88cb99a5f76f90808a624f18b169b90a4abb40c1fd8c19420e"},
+    {url = "https://files.pythonhosted.org/packages/85/86/a17a4baf08e0ae6496b44f75136f8e14b843fd3d8a3f4105c0fd79d4786b/cryptography-40.0.2-cp36-abi3-macosx_10_12_x86_64.whl", hash = "sha256:05dc219433b14046c476f6f09d7636b92a1c3e5808b9a6536adf4932b3b2c440"},
+    {url = "https://files.pythonhosted.org/packages/88/87/c720c0b56f6363eaa32c582b6240523010691ad973204649526c4ce28e95/cryptography-40.0.2-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:d5a1bd0e9e2031465761dfa920c16b0065ad77321d8a8c1f5ee331021fda65e9"},
+    {url = "https://files.pythonhosted.org/packages/8e/34/f54dbfc6d12fa34a50f03bf01319d585e7e9bddd68ad28299b4998e3098b/cryptography-40.0.2-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:adc0d980fd2760c9e5de537c28935cc32b9353baaf28e0814df417619c6c8c3b"},
+    {url = "https://files.pythonhosted.org/packages/91/89/13174c6167f452598baa8584133993e3d624b6a19e93748e5f2885a442f2/cryptography-40.0.2-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:a95f4802d49faa6a674242e25bfeea6fc2acd915b5e5e29ac90a32b1139cae1c"},
+    {url = "https://files.pythonhosted.org/packages/9c/1b/30faebcef9be2df5728a8086b8fc15fff92364fe114fb207b70cd7c81329/cryptography-40.0.2-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dcca15d3a19a66e63662dc8d30f8036b07be851a8680eda92d079868f106288"},
+    {url = "https://files.pythonhosted.org/packages/ad/d4/a9c46f0fedfad9198740e77b99cb69d4596dfb0ef0e70440f2780373fb24/cryptography-40.0.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:3daf9b114213f8ba460b829a02896789751626a2a4e7a43a28ee77c04b5e4958"},
+    {url = "https://files.pythonhosted.org/packages/c6/e9/a004c5ff4a01e38da38c0d20257f4af41f0858719fb25c5a034ee46d40cd/cryptography-40.0.2-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:142bae539ef28a1c76794cca7f49729e7c54423f615cfd9b0b1fa90ebe53244b"},
+    {url = "https://files.pythonhosted.org/packages/cc/aa/285f288e36d398db873d4cc20984c9a132ef5eace539d91babe4c4e94aaa/cryptography-40.0.2-cp36-abi3-macosx_10_12_universal2.whl", hash = "sha256:8f79b5ff5ad9d3218afb1e7e20ea74da5f76943ee5edb7f76e56ec5161ec782b"},
+    {url = "https://files.pythonhosted.org/packages/eb/a0/496b34c04a971dafef68fa5f58222b5688f63f956f3b3f92664165a0921f/cryptography-40.0.2-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c0764e72b36a3dc065c155e5b22f93df465da9c39af65516fe04ed3c68c92636"},
+    {url = "https://files.pythonhosted.org/packages/f7/80/04cc7637238b78f8e7354900817135c5a23cf66dfb3f3a216c6d630d6833/cryptography-40.0.2.tar.gz", hash = "sha256:c33c0d32b8594fa647d2e01dbccc303478e16fdd7cf98652d5b3ed11aa5e5c99"},
+    {url = "https://files.pythonhosted.org/packages/ff/87/cffd495cc78503fb49aa3e19babc126b610174d08aa32c0d1d75c6499afc/cryptography-40.0.2-cp36-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:a04386fb7bc85fab9cd51b6308633a3c271e3d0d3eae917eebab2fac6219b6d2"},
 ]
 "exceptiongroup 1.1.1" = [
     {url = "https://files.pythonhosted.org/packages/61/97/17ed81b7a8d24d8f69b62c0db37abbd8c0042d4b3fc429c73dab986e7483/exceptiongroup-1.1.1-py3-none-any.whl", hash = "sha256:232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e"},
@@ -492,9 +400,9 @@ content_hash = "sha256:b6a6a8c5dddf243e42c8ce93a5307a0a1b2f856dbcfdaf8b9d8fb762c
     {url = "https://files.pythonhosted.org/packages/8b/e1/43beb3d38dba6cb420cefa297822eac205a277ab43e5ba5d5c46faf96438/idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"},
     {url = "https://files.pythonhosted.org/packages/fc/34/3030de6f1370931b9dbb4dad48f6ab1015ab1d32447850b9fc94e60097be/idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"},
 ]
-"importlib-metadata 6.1.0" = [
-    {url = "https://files.pythonhosted.org/packages/e2/d8/3d431bade4598ad9e33be9da41d15e6607b878008e922d122659ab01b077/importlib_metadata-6.1.0.tar.gz", hash = "sha256:43ce9281e097583d758c2c708c4376371261a02c34682491a8e98352365aad20"},
-    {url = "https://files.pythonhosted.org/packages/f8/7d/e3adad613703c86d62aa991b45d6f090cf59975078a8c8100b50a0c86948/importlib_metadata-6.1.0-py3-none-any.whl", hash = "sha256:ff80f3b5394912eb1b108fcfd444dc78b7f1f3e16b16188054bd01cb9cb86f09"},
+"importlib-metadata 6.6.0" = [
+    {url = "https://files.pythonhosted.org/packages/0b/1f/9de392c2b939384e08812ef93adf37684ec170b5b6e7ea302d9f163c2ea0/importlib_metadata-6.6.0.tar.gz", hash = "sha256:92501cdf9cc66ebd3e612f1b4f0c0765dfa42f0fa38ffb319b6bd84dd675d705"},
+    {url = "https://files.pythonhosted.org/packages/30/bb/bf2944b8b88c65b797acc2c6a2cb0fb817f7364debf0675792e034013858/importlib_metadata-6.6.0-py3-none-any.whl", hash = "sha256:43dd286a2cd8995d5eaef7fee2066340423b818ed3fd70adf0bad5f1fac53fed"},
 ]
 "iniconfig 2.0.0" = [
     {url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
@@ -560,13 +468,13 @@ content_hash = "sha256:b6a6a8c5dddf243e42c8ce93a5307a0a1b2f856dbcfdaf8b9d8fb762c
     {url = "https://files.pythonhosted.org/packages/ea/60/2400ba59cf2465fa136487ee7299f52121a9d04b2cf8539ad43ad10e70e8/MarkupSafe-2.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:e55e40ff0cc8cc5c07996915ad367fa47da6b3fc091fdadca7f5403239c5fec3"},
     {url = "https://files.pythonhosted.org/packages/f9/aa/ebcd114deab08f892b1d70badda4436dbad1747f9e5b72cffb3de4c7129d/MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7313ce6a199651c4ed9d7e4cfb4aa56fe923b1adf9af3b420ee14e6d9a73df65"},
 ]
-"packaging 23.0" = [
-    {url = "https://files.pythonhosted.org/packages/47/d5/aca8ff6f49aa5565df1c826e7bf5e85a6df852ee063600c1efa5b932968c/packaging-23.0.tar.gz", hash = "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"},
-    {url = "https://files.pythonhosted.org/packages/ed/35/a31aed2993e398f6b09a790a181a7927eb14610ee8bbf02dc14d31677f1c/packaging-23.0-py3-none-any.whl", hash = "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2"},
+"packaging 23.1" = [
+    {url = "https://files.pythonhosted.org/packages/ab/c3/57f0601a2d4fe15de7a553c00adbc901425661bf048f2a22dfc500caf121/packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"},
+    {url = "https://files.pythonhosted.org/packages/b9/6c/7c6658d258d7971c5eb0d9b69fa9265879ec9a9158031206d47800ae2213/packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"},
 ]
-"pdoc 13.0.1" = [
-    {url = "https://files.pythonhosted.org/packages/64/8f/2b44c405ab75bd8a0c21950361b2638f5122b7eb337cff0605f485469912/pdoc-13.0.1-py3-none-any.whl", hash = "sha256:16a24914280ed318896ad798674e2b0d11832297fdea95632fa472e3d171e247"},
-    {url = "https://files.pythonhosted.org/packages/7f/08/224f5a19fc820999306e8c7839fa260c3d0278595b4ebc113a5bc3399144/pdoc-13.0.1.tar.gz", hash = "sha256:4d84056847728203b8789ca8a8d0c8003f25002b3caef3365f6f21a1e4228a1b"},
+"pdoc 13.1.1" = [
+    {url = "https://files.pythonhosted.org/packages/b5/6c/264d7d4148d30e8676d86ff09bca86df80c4179e3b128a02822de07b3c82/pdoc-13.1.1-py3-none-any.whl", hash = "sha256:9025c6cd2448b18662e88eacf84c6eb050dcbdc8ee5259aee5e40a1c2b417840"},
+    {url = "https://files.pythonhosted.org/packages/b8/87/21dd506901c7987e36e3e59d001901ff92086f133d0533cba8e9dfb37c00/pdoc-13.1.1.tar.gz", hash = "sha256:2b8e341b1882ed8217e95c1f3f1f11d34f9ef93a5796287590162e2035296815"},
 ]
 "pluggy 1.0.0" = [
     {url = "https://files.pythonhosted.org/packages/9e/01/f38e2ff29715251cf25532b9082a1589ab7e4f571ced434f98d0139336dc/pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"},
@@ -576,18 +484,14 @@ content_hash = "sha256:b6a6a8c5dddf243e42c8ce93a5307a0a1b2f856dbcfdaf8b9d8fb762c
     {url = "https://files.pythonhosted.org/packages/5e/0b/95d387f5f4433cb0f53ff7ad859bd2c6051051cebbb564f139a999ab46de/pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"},
     {url = "https://files.pythonhosted.org/packages/62/d5/5f610ebe421e85889f2e55e33b7f9a6795bd982198517d912eb1c76e1a53/pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"},
 ]
-"pygments 2.14.0" = [
-    {url = "https://files.pythonhosted.org/packages/0b/42/d9d95cc461f098f204cd20c85642ae40fbff81f74c300341b8d0e0df14e0/Pygments-2.14.0-py3-none-any.whl", hash = "sha256:fa7bd7bd2771287c0de303af8bfdfc731f51bd2c6a47ab69d117138893b82717"},
-    {url = "https://files.pythonhosted.org/packages/da/6a/c427c06913204e24de28de5300d3f0e809933f376e0b7df95194b2bb3f71/Pygments-2.14.0.tar.gz", hash = "sha256:b3ed06a9e8ac9a9aae5a6f5dbe78a8a58655d17b43b93c078f094ddc476ae297"},
+"pygments 2.15.1" = [
+    {url = "https://files.pythonhosted.org/packages/34/a7/37c8d68532ba71549db4212cb036dbd6161b40e463aba336770e80c72f84/Pygments-2.15.1-py3-none-any.whl", hash = "sha256:db2db3deb4b4179f399a09054b023b6a586b76499d36965813c71aa8ed7b5fd1"},
+    {url = "https://files.pythonhosted.org/packages/89/6b/2114e54b290824197006e41be3f9bbe1a26e9c39d1f5fa20a6d62945a0b3/Pygments-2.15.1.tar.gz", hash = "sha256:8ace4d3c1dd481894b2005f560ead0f9f19ee64fe983366be1a21e171d12775c"},
 ]
 "pytest 7.2.2" = [
     {url = "https://files.pythonhosted.org/packages/b2/68/5321b5793bd506961bd40bdbdd0674e7de4fb873ee7cab33dd27283ad513/pytest-7.2.2-py3-none-any.whl", hash = "sha256:130328f552dcfac0b1cec75c12e3f005619dc5f874f0a06e8ff7263f0ee6225e"},
     {url = "https://files.pythonhosted.org/packages/b9/29/311895d9cd3f003dd58e8fdea36dd895ba2da5c0c90601836f7de79f76fe/pytest-7.2.2.tar.gz", hash = "sha256:c99ab0c73aceb050f68929bc93af19ab6db0558791c6a0715723abe9d0ade9d4"},
 ]
-"requests 2.28.2" = [
-    {url = "https://files.pythonhosted.org/packages/9d/ee/391076f5937f0a8cdf5e53b701ffc91753e87b07d66bae4a09aa671897bf/requests-2.28.2.tar.gz", hash = "sha256:98b1b2782e3c6c4904938b84c0eb932721069dfdb9134313beff7c83c2df24bf"},
-    {url = "https://files.pythonhosted.org/packages/d2/f4/274d1dbe96b41cf4e0efb70cbced278ffd61b5c7bb70338b62af94ccb25b/requests-2.28.2-py3-none-any.whl", hash = "sha256:64299f4909223da747622c030b781c0d7811e359c37124b4bd368fb8c6518baa"},
-]
 "rfc3986 1.5.0" = [
     {url = "https://files.pythonhosted.org/packages/79/30/5b1b6c28c105629cc12b33bdcbb0b11b5bb1880c6cfbd955f9e792921aa8/rfc3986-1.5.0.tar.gz", hash = "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835"},
     {url = "https://files.pythonhosted.org/packages/c4/e5/63ca2c4edf4e00657584608bee1001302bbf8c5f569340b78304f2f446cb/rfc3986-1.5.0-py2.py3-none-any.whl", hash = "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97"},
@@ -604,6 +508,10 @@ content_hash = "sha256:b6a6a8c5dddf243e42c8ce93a5307a0a1b2f856dbcfdaf8b9d8fb762c
     {url = "https://files.pythonhosted.org/packages/12/48/f9c1ec6bee313aba264fbc2483d9070f4e4526f2538e2b55b1e4a391d938/starlette-0.26.1-py3-none-any.whl", hash = "sha256:e87fce5d7cbdde34b76f0ac69013fd9d190d581d80681493016666e6f96c6d5e"},
     {url = "https://files.pythonhosted.org/packages/52/55/98746af96f57a0ff4f108c5ac84c130af3c4e291272acf446afc67d5d5d8/starlette-0.26.1.tar.gz", hash = "sha256:41da799057ea8620e4667a3e69a5b1923ebd32b1819c8fa75634bbe8d8bea9bd"},
 ]
+"starlette-csrf 2.0.0" = [
+    {url = "https://files.pythonhosted.org/packages/6f/f7/86ef6d5823d098980ac093778ed0c44dda44ddcf841254a5b41c58e10562/starlette_csrf-2.0.0-py3-none-any.whl", hash = "sha256:638d55a8f98e8e432b81fea56606b4afe9377d567a60e3c43a566bdd117660a0"},
+    {url = "https://files.pythonhosted.org/packages/ae/78/1057d69a1d6cd39593013641d5b2170915bd3665a461f2edb2a9a2e59b2e/starlette_csrf-2.0.0.tar.gz", hash = "sha256:5f03b8c496840d612f1f7065aac7a209da084972f6e7844bcc5752c32ac54747"},
+]
 "tomli 2.0.1" = [
     {url = "https://files.pythonhosted.org/packages/97/75/10a9ebee3fd790d20926a90a2547f0bf78f371b2f13aa822c759680ca7b9/tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
     {url = "https://files.pythonhosted.org/packages/c0/3f/d7af728f075fb08564c5949a9c95e44352e23dee646869fa104a3b2060a3/tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
@@ -612,10 +520,6 @@ content_hash = "sha256:b6a6a8c5dddf243e42c8ce93a5307a0a1b2f856dbcfdaf8b9d8fb762c
     {url = "https://files.pythonhosted.org/packages/31/25/5abcd82372d3d4a3932e1fa8c3dbf9efac10cc7c0d16e78467460571b404/typing_extensions-4.5.0-py3-none-any.whl", hash = "sha256:fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4"},
     {url = "https://files.pythonhosted.org/packages/d3/20/06270dac7316220643c32ae61694e451c98f8caf4c8eab3aa80a2bedf0df/typing_extensions-4.5.0.tar.gz", hash = "sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb"},
 ]
-"urllib3 1.26.15" = [
-    {url = "https://files.pythonhosted.org/packages/21/79/6372d8c0d0641b4072889f3ff84f279b738cd8595b64c8e0496d4e848122/urllib3-1.26.15.tar.gz", hash = "sha256:8a388717b9476f934a21484e8c8e61875ab60644d29b9b39e11e4b9dc1c6b305"},
-    {url = "https://files.pythonhosted.org/packages/7b/f5/890a0baca17a61c1f92f72b81d3c31523c99bec609e60c292ea55b387ae8/urllib3-1.26.15-py2.py3-none-any.whl", hash = "sha256:aa751d169e23c7479ce47a0cb0da579e3ede798f994f5816a74e4f4500dcea42"},
-]
 "wheel 0.40.0" = [
     {url = "https://files.pythonhosted.org/packages/61/86/cc8d1ff2ca31a312a25a708c891cf9facbad4eae493b3872638db6785eb5/wheel-0.40.0-py3-none-any.whl", hash = "sha256:d236b20e7cb522daf2390fa84c55eea81c5c30190f90f29ae2ca1ad8355bf247"},
     {url = "https://files.pythonhosted.org/packages/fc/ef/0335f7217dd1e8096a9e8383e1d472aa14717878ffe07c4772e68b6e8735/wheel-0.40.0.tar.gz", hash = "sha256:cd1196f3faee2b31968d626e1731c94f99cbdb67cf5a46e4f5656cbee7738873"},
diff --git a/pyproject.toml b/pyproject.toml
index d126ba3..297cb24 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
 [project]
 name = "starlette-securecookies"
-version = "1.0.2"
+version = "1.1.0"
 description = "Secure cookie middleware for Starlette applications."
 authors = [
     {name = "Elias Gabriel", email = "me@eliasfgabriel.com"},
@@ -11,11 +11,17 @@ readme = "README.md"
 requires-python = "~=3.7"
 dependencies = [
     "starlette>=0.6.1",
-    "cryptography>=0",
+    "cryptography>=2.2",
+    "typing_extensions; python_version < '3.8'",
+]
+
+[project.optional-dependencies]
+csrf = [
+    "starlette-csrf>=1.4.2",
 ]
 
 [project.urls]
-homepage = "https://example.com"
+homepage = "https://securecookies.thearchitector.dev"
 documentation = "https://securecookies.thearchitector.dev"
 repository = "https://github.com/thearchitector/starlette-securecookies"
 changelog = "https://github.com/thearchitector/starlette-securecookies/blob/main/CHANGELOG.md"
@@ -27,14 +33,13 @@ includes = ["CHANGELOG.md", "securecookies/"]
 [tool.pdm.dev-dependencies]
 dev = [
     "pytest~=7.2.2",
-    "pdoc~=13.0.1",
-    "requests~=2.28.2",
-    "httpx>=0.23.3",
-    "itsdangerous>=2.1.2",
+    "pdoc~=13.1.0",
+    "httpx~=0.23.3",
+    "itsdangerous~=2.1.2",
 ]
 
 [tool.pdm.scripts]
-docs = "pdoc -t docs_templates -o docs --no-search securecookies"
+docs = "pdoc -o docs --no-search --mermaid securecookies"
 
 [tool.pytest.ini_options]
 addopts = "-svv"
diff --git a/securecookies/__init__.py b/securecookies/__init__.py
index 1a1b8b8..b23c696 100644
--- a/securecookies/__init__.py
+++ b/securecookies/__init__.py
@@ -1,5 +1,7 @@
-""".. include:: ../../README.md"""
+""".. include:: ../README.md"""
+
+from securecookies import extras
 
 from .middleware import BadArgumentError, SecureCookiesMiddleware
 
-__all__ = ["SecureCookiesMiddleware", "BadArgumentError"]
+__all__ = ["SecureCookiesMiddleware", "BadArgumentError", "extras"]
diff --git a/securecookies/extras/__init__.py b/securecookies/extras/__init__.py
new file mode 100644
index 0000000..2c92038
--- /dev/null
+++ b/securecookies/extras/__init__.py
@@ -0,0 +1,14 @@
+"""
+# securecookies.extras
+
+starlette-securecookies also ships with some common middleware and tools modified and
+extended to work with secure cookies.
+
+- **`csrf.SecureCSRFMiddleware`**: Adds compatibility to the CSRF middleware provided
+by [starlette_csrf](https://github.com/frankie567/starlette-csrf). To use it, simply
+add it to your list of middleware (keep in mind the ordering). If you don't want to
+specify `starlette_csrf` as a direct dependency, you can also install it through the
+`[csrf]` package extra.
+"""
+
+__all__ = []  # type: ignore
diff --git a/securecookies/extras/csrf.py b/securecookies/extras/csrf.py
new file mode 100644
index 0000000..18c89f8
--- /dev/null
+++ b/securecookies/extras/csrf.py
@@ -0,0 +1,38 @@
+try:
+    from starlette_csrf.middleware import CSRFMiddleware
+except ImportError:
+    raise AssertionError("starlette_csrf must be installed to use the CSRF extra.")
+
+from typing import Optional
+
+from starlette.requests import Request
+
+from ..middleware import SecureCookiesMiddleware
+
+
+class SecureCSRFMiddleware(CSRFMiddleware):
+    async def _get_submitted_csrf_token(self, request: Request) -> Optional[str]:
+        """
+        We're using encrypted cookies, so the contents of the header coming from the
+        client will also be encrypted. The incoming cookie is decrypted automatically
+        but the header is not, so we need to decrypt it manually so CSRF middleware
+        can compare them correctly.
+        """
+        # middleware is built and instantiated once during application creation.
+        # since we don't want to recreate the middleware (seems not nice), we need to
+        # loop through the entire ASGI stack to find our SecureCookieMiddleware.
+        # this might be excessive but ¯\_(ツ)_/¯
+        if not hasattr(self, "_secure_middleware"):
+            app = request.scope["app"].middleware_stack
+            while not isinstance(app, SecureCookiesMiddleware):
+                try:
+                    app = app.app
+                except AttributeError:
+                    raise Exception(
+                        "You must use SecureCSRFMiddleware in conjunction with"
+                        " SecureCookiesMiddleware."
+                    )
+
+            self._secure_middleware = app
+
+        return self._secure_middleware.decrypt(request.headers[self.header_name])
diff --git a/securecookies/middleware.py b/securecookies/middleware.py
index 6bf98b4..2f83795 100644
--- a/securecookies/middleware.py
+++ b/securecookies/middleware.py
@@ -1,3 +1,4 @@
+import sys
 from http.cookies import SimpleCookie
 from typing import Any, List, Optional
 
@@ -7,6 +8,11 @@
 from starlette.responses import Response
 from starlette.types import ASGIApp
 
+if sys.version_info >= (3, 8):  # pragma: no cover
+    from typing import Literal
+else:  # pragma: no cover
+    from typing_extensions import Literal
+
 
 class BadArgumentError(Exception):
     """
@@ -20,7 +26,7 @@ class SecureCookiesMiddleware(BaseHTTPMiddleware):
     Provides automatic secure cookie support through symmetric Fernet encryption. As per
     the `cryptography` docs, security is achieved through:
 
-    - 128-bit key AES in CBC mode using PKCS7 padding for encryption
+    - 128-bit key AES in CBC mode using PKCS7 padding for encryption.
     - HMAC using SHA256 for authentication.
     """
 
@@ -41,7 +47,7 @@ def __init__(
         cookie_domain: Optional[str] = None,
         cookie_secure: Optional[bool] = None,
         cookie_httponly: Optional[bool] = None,
-        cookie_samesite: Optional[str] = None,
+        cookie_samesite: Optional[Literal["strict", "lax", "none"]] = None,
         excluded_cookies: Optional[List[str]] = None,
         included_cookies: Optional[List[str]] = None,
     ) -> None:
@@ -74,7 +80,7 @@ def __init__(
         if excluded_cookies and included_cookies:
             raise BadArgumentError(
                 "It doesn't make sense to specify both excluded and included cookies."
-                " Supply with `excluded_cookies` or `included_cookies` to restrict"
+                " Supply either `excluded_cookies` or `included_cookies` to restrict"
                 " which cookies should be secure."
             )
 
@@ -83,18 +89,31 @@ def __init__(
                 "SameSite attribute must be either 'strict', 'lax' or 'none'"
             )
 
+    def set_header(self, request: Request, header: str, value: str) -> None:
+        """
+        Adds the given Header to the available Request headers. If the Header already
+        exists, its value is overwritten.
+        """
+        hkey = header.encode("latin-1")
+        request.scope["headers"] = [
+            *(h for h in request.scope["headers"] if h[0] != hkey),
+            (hkey, value.encode("latin-1")),
+        ]
+
+    def decrypt(self, value: str) -> str:
+        """Decrypt the given value using any of the configured secrets."""
+        return self.mfernet.decrypt(value.encode()).decode()
+
+    def encrypt(self, value: str) -> str:
+        """Encrypt the given value using the first configured secret."""
+        return self.mfernet.encrypt(value.encode()).decode()
+
     async def dispatch(
         self, request: Request, call_next: RequestResponseEndpoint
     ) -> Response:
-        # request cookies are only passed along and mutable within the asgi scope
-        headers = request.scope["headers"]
-        raw_cookies = [h for h in headers if h[0] == b"cookie"]
-        if len(raw_cookies):
-            # if encrypted cookies are present, remove and parse them
-            headers.remove(raw_cookies[0])
-            cookies: SimpleCookie[Any] = SimpleCookie(raw_cookies[0][1].decode())
-
-            for cookie, morsel in list(cookies.items()):
+        if len(request.cookies):
+            cookies: SimpleCookie[Any] = SimpleCookie()
+            for cookie, value in request.cookies.items():
                 # if the cookie is included or not excluded
                 if (
                     (not self.included_cookies and not self.excluded_cookies)
@@ -102,30 +121,27 @@ async def dispatch(
                     or (self.excluded_cookies and cookie not in self.excluded_cookies)
                 ):
                     try:
-                        # try to decrypt the token. if you can, then it's already
-                        # encrypted and can be passed along
-                        cookies[cookie] = self.mfernet.decrypt(
-                            morsel.value.encode()
-                        ).decode()
+                        # try to decrypt the cookie and pass it along
+                        cookies[cookie] = self.decrypt(value)
                     except InvalidToken:
-                        # delete invalid or unencrypted cookies if enabled
-                        if self.discard_invalid:
-                            del cookies[cookie]
-
-            # serialize and append the decrypted cookies to the asgi scope headers
-            new_cookie = (
-                b"cookie",
-                cookies.output(header="", sep=";").strip().encode(),
+                        # delete invalid or unencrypted cookies unless disabled
+                        if not self.discard_invalid:
+                            cookies[cookie] = value
+
+            # serialize and set the decrypted cookies to the asgi scope headers
+            # we have to modify the scope directly because request objects are not
+            # passed between ASGI applications / middleware.
+            self.set_header(
+                request, "cookie", cookies.output(header="", sep=";").strip()
             )
-            headers.append(new_cookie)
 
         # propagate the modified request
         response: Response = await call_next(request)
 
         # for every cookie in the response
-        for raw_cookie in response.headers.getlist("set-cookie"):
+        for cookie in response.headers.getlist("set-cookie"):
             # decode it
-            ncookie: SimpleCookie[Any] = SimpleCookie(raw_cookie)
+            ncookie: SimpleCookie[Any] = SimpleCookie(cookie)
             key = [*ncookie.keys()][0]
 
             # if the cookie is included or not excluded
@@ -137,13 +153,12 @@ async def dispatch(
                 # create a new encrypted cookie with the desired attributes
                 response.set_cookie(
                     key,
-                    value=self.mfernet.encrypt(ncookie[key].value.encode()).decode(),
+                    value=self.encrypt(ncookie[key].value),
                     path=self.cookie_path or ncookie[key]["path"],
                     domain=self.cookie_domain or ncookie[key]["domain"],
                     secure=self.cookie_secure or ncookie[key]["secure"],
                     httponly=self.cookie_httponly or ncookie[key]["httponly"],
-                    samesite=self.cookie_samesite
-                    or ncookie[key]["samesite"],  # type:ignore [arg-type]
+                    samesite=self.cookie_samesite or ncookie[key]["samesite"],
                 )
 
         return response


Test patch:
diff --git a/tests/conftest.py b/tests/conftest.py
index bdb69c0..4538a26 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -1,7 +1,7 @@
 import pytest
 from cryptography.fernet import Fernet
 from starlette.applications import Starlette
-from starlette.middleware import Middleware, sessions
+from starlette.middleware import Middleware
 from starlette.responses import PlainTextResponse
 from starlette.routing import Route
 from starlette.testclient import TestClient
@@ -51,6 +51,11 @@ async def _validate_session(request):
     return PlainTextResponse("Session get")
 
 
+async def _post(request):
+    await request.json()
+    return PlainTextResponse("JSON post")
+
+
 @pytest.fixture(scope="session")
 def secret():
     yield Fernet.generate_key()
@@ -71,7 +76,7 @@ def mock_cookies(fernet):
 
 @pytest.fixture(scope="session")
 def client_factory(secret):
-    def _func(cookies=None, **kwargs):
+    def _func(cookies=None, middleware=None, **kwargs):
         return TestClient(
             Starlette(
                 debug=True,
@@ -82,14 +87,14 @@ def _func(cookies=None, **kwargs):
                     # third party
                     Route("/session", _session, methods=["GET"]),
                     Route("/session_val", _validate_session, methods=["GET"]),
+                    # csrf
+                    Route("/post", _post, methods=["POST"]),
                 ],
                 middleware=[
                     # secure cookies must be first in the list so it can decrypt first
                     # and encrypt last
                     Middleware(SecureCookiesMiddleware, secrets=[secret], **kwargs),
-                    Middleware(
-                        sessions.SessionMiddleware, secret_key="verysecretsecret"
-                    ),
+                    *(middleware or []),
                 ],
             ),
             cookies=cookies,
diff --git a/tests/extras/test_csrf.py b/tests/extras/test_csrf.py
new file mode 100644
index 0000000..369a017
--- /dev/null
+++ b/tests/extras/test_csrf.py
@@ -0,0 +1,32 @@
+from starlette.middleware import Middleware
+from starlette_csrf import CSRFMiddleware
+
+from securecookies.extras.csrf import SecureCSRFMiddleware
+
+
+def test_csrf_bad_vanilla(client_factory):
+    # check if normal CSRF fails. it should since the token header is not decrypted
+    # by default
+    client = client_factory(
+        middleware=[Middleware(CSRFMiddleware, secret="verysecretsecret")]
+    )
+    response = client.post(
+        "/post",
+        headers={"x-csrftoken": client.get("/get").cookies["csrftoken"]},
+        json={"hello": "world"},
+    )
+    assert response.status_code == 403
+
+
+def test_csrf_secure(client_factory):
+    # check if the secure CSRF works. it should automatically find the secure cookie
+    # middleware and decrypt the header.
+    client = client_factory(
+        middleware=[Middleware(SecureCSRFMiddleware, secret="verysecretsecret")]
+    )
+    response = client.post(
+        "/post",
+        headers={"x-csrftoken": client.get("/get").cookies["csrftoken"]},
+        json={"hello": "world"},
+    )
+    assert response.status_code == 200
diff --git a/tests/test_other-party.py b/tests/test_other-party.py
index c358185..c5e551f 100644
--- a/tests/test_other-party.py
+++ b/tests/test_other-party.py
@@ -1,11 +1,14 @@
 import pytest
 from itsdangerous import BadSignature, TimestampSigner
+from starlette.middleware import Middleware, sessions
 
 
 def test_third_party(client_factory, fernet):
-    # cookies added by other middlewares should get (de/en)crypted correctly
+    # cookies added by other middleware should get (de/en)crypted correctly
+    middleware = [Middleware(sessions.SessionMiddleware, secret_key="verysecretsecret")]
+
     ## set a session cookie
-    response = client_factory().get("/session")
+    response = client_factory(middleware=middleware).get("/session")
     assert response.status_code == 200
 
     ### it should be encrypted / will have an invalid sig
@@ -15,4 +18,6 @@ def test_third_party(client_factory, fernet):
     TimestampSigner("verysecretsecret").unsign(fernet.decrypt(scookie.encode()))
 
     ## read a session cookie, should be decrypted / will have a valid sig
-    client_factory(cookies={"session": scookie}).get("/session_val")
+    client_factory(middleware=middleware, cookies={"session": scookie}).get(
+        "/session_val"
+    )