Subject: Re: Formalizing the HTTP State Tokens proposal.

From: Kari Hurtta <[email-masked]>
Date: Mon, 1 Apr 2019 21:08:56 +0300 (EEST)

3.2.  Requests and Responses
https://tools.ietf.org/html/draft-west-http-state-tokens-00#section-3.2

|   This document relies upon the definitions of "request" and "response"
|   found in [Fetch].
|
|   A request's delivery scope can be obtained as follows:
|
|   1.  Let "request-origin" be the request's "origin", and "target-
|       origin" be the request's "URL"'s "origin".
|
|   2.  If the request was generated by the user agent as a response to
|       direct user interaction with the user agent (e.g. the user typed
|       an address into the agent's address bar, clicked a bookmark, or
|       etc.), return "same-origin".
|
|   3.  If "request-origin" is same-origin with "target-origin", return
|       "same-origin".
|
|   4.  If "request-origin"'s registrable domain is the same as "target-
|       origin"'s registrable domain, return "same-site".
|
|   5.  Return "cross-site".

Is delivery=same-site intended to cause Sec-Http-State request field
to be send about same requests than Cookies with SameSite attribute?

SameSite seems use definition "site for cookies" for that. How that
compare to "request-origin" ?

5.2.  "Same-site" and "cross-site" Requests
https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-02#section-5.2

|   2.  Let "site" be "request"'s client's "site for cookies" (as defined
|       in the following sections).
|
|   3.  Let "target" be the registered domain of "request"'s current url.
|
|   4.  If "site" is an exact match for "target", return "same-site".

5.2.1.  Document-based requests
https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-02#section-5.2.1

|   For a document displayed in a top-level browsing context, we can stop
|   here: the document's "site for cookies" is the top-level site.

 (and so on)

I failed interpret how Fetch defines request's "origin"

https://fetch.spec.whatwg.org/#concept-request-origin

https://html.spec.whatwg.org/multipage/origin.html#concept-origin

Specially nested browsing contexts (iframes and so on).

/ Kari Hurtta

---

From: Ilari Liusvaara <[email-masked]>
Date: Thu, 28 Mar 2019 21:40:46 +0200

On Thu, Mar 28, 2019 at 11:14:22AM +0100, Mike West wrote:
> Way back in August, 2018, I started a thread [1] on a proposal to introduce
> a client-controlled, origin-bound, HTTPS-only session identifier for
> network-level state management [2].
> 
> I wasn't able to make it to IETF104, but I will be attending the HTTP
> workshop next week. In the hopes of sparking some conversations there, I've
> formalized the proposal as
> https://tools.ietf.org/html/draft-west-http-state-tokens-00, clarifying
> some pieces based on y'all's earlier feedback. I'm looking forward to your
> feedback on, either here on the list, or at the workshop next week.

I see some issues:

- This mechanism looks to lack server opt-in, which runs into issues
  with EU "cookie law". Specifically, it does not seem to be possible
  to use this for any purpose without triggering disclaimer
  requirements. Whereas there are still usecases cookies that do not
  necressarily do so (for example, login).

- The request signing mechansims looks like one that would break if
  there is some CDN or reverse proxy in the path that adds a header
  or a few (sometimes with some non-standard one in the mix). Or is it
  expected that all CDNs or reverse proxies on path for application
  using this mechanism can rewrite the MAC?

-Ilari

---

From: Kari Hurtta <[email-masked]>
Date: Wed, 3 Apr 2019 21:28:57 +0300 (EEST)

>   necressarily do so (for example, login).

https://tools.ietf.org/html/draft-west-http-state-tokens-00

My suggestion #2 for server opt-in (*)

( This also includes my delivery=none suggestion
  <[email-masked]>
  https://lists.w3.org/Archives/Public/ietf-http-wg/2019JanMar/0251.html
)

3.1.  HTTP State Tokens
https://tools.ietf.org/html/draft-west-http-state-tokens-00#section-3.1

"delivery" metadata is enum  of either

	  "query", "void", "none",
	  same-origin", "same-site", or "cross-site"

Initial value for "delivery" is "query".

4.1.  The 'Sec-Http-State' HTTP Header Field
https://tools.ietf.org/html/draft-west-http-state-tokens-00#section-4.1

I assume that site / server uses Sec-Http-State: request field for
indication that HTTP State Tokens are supported by browser
(and Cookie need not be generated).

Therefore  "Sec-Http-State:"  dictionary member, whose key is "token",
have value which is ether binary content (sh-binary) or token (sh-token). 

Allowed token (sh-token) values for "token" are
"query" and "void".

4.2.  The 'Sec-Http-State-Options' HTTP Header Field

https://tools.ietf.org/html/draft-west-http-state-tokens-00#section-4.2

"Sec-Http-State-Options:"  dictionary member's,  whose key is
"delivery",  allowed token (sh-token) values 
are  "void", "none", "same-origin", "same-site", or "cross-site"

( Note that "query" is missed. It is just initial value "delivery" metadata
  and can not be set by site / server .)

1) If HTTP State Token's "delivery" property have value "query",
generated request header field is
    
  Sec-HTTP-State: token=query

This indicates that browser supports HTTP State Tokens but
opt-in is needed.

2) If HTTP State Token's "delivery" property have value "void",
generated request header field is

  Sec-HTTP-State: token=void

This indicates that browser supports HTTP State Tokens but
site/server or user is opt-out for  HTTP State Tokens

Site should not longer prompt consent frum user either
(also should not set Cookies either for same reason).

3) If HTTP State Token's "delivery" property have value "none",
 Sec-HTTP-State: request header field is NOT generated.

This is for sites/origins which want minimize request size (these
sites/origins naturally also do NOT set Cooies.) These origins
proviedes static content (images, styles, javascript and so on which
do not need state).

4) If HTTP State Token's "delivery" property have value
 same-origin", "same-site", or "cross-site" then
 "value" property for HTTP State Token is generated
 (256 cryptographically random bits) and
generated request header field is

  Sec-HTTP-State: token=*(base64 encoding of "value" property)*

The 'Sec-Http-State' HTTP Header Field may also include
other dictionat memebers than "token".

If  HTTP State Token's "delivery" property have value "query",
there neeed also method for Javascript to set that
to other value. This allows site/server use Javascript based consent
from user.

( Server / Site can set this with Sec-Http-State-Options:
  response header feld. )

/ Kari Hurtta

(*) My previous suggestion was:

<[email-masked]>
https://lists.w3.org/Archives/Public/ietf-http-wg/2018JulSep/0222.html

( or perhaps not )

---

From: Kari Hurtta <[email-masked]>
Date: Sun, 7 Apr 2019 20:10:00 +0300 (EEST)

Follow-up:

Delivery scope "same-site" should be same definition
on "same-siteness" than 

gives. But now it is not.  It is confusing when two releted technology
uses different definition.

( SameSite is already implemented by browsers )

( continuing inline )

> |       origin"'s registrable domain, return "same-site".

      I think that should be named "same-domain" so that it does not
      confuse "same-site" request definition for SameSite cookies
      (it uses "site for cookies").

      Use "same-site" term for request's delivery scope only
      if client's "site for cookies" (as defined for SameSite)
      is the same as "target-origin"'s registrable domain.

> compare to "request-origin" ?

"site for cookies" is different than "request-origin"

That is effectively

https://html.spec.whatwg.org/multipage/origin.html#origin

| If the Document's URL's scheme is a network scheme
|
|    A copy of the Document's URL's origin assigned when the Document is created.
|
|    The document.open() method can change the Document's URL to "about:blank". Therefore the origin is assigned when the Document is created.

specially:

| 5.2.1.  Document-based requests
| 
|   The URI displayed in a user agent's address bar is the only security
|   context directly exposed to users, and therefore the only signal
|   users can reasonably rely upon to determine whether or not they trust
|   a particular website.  The registered domain of that URI's origin
|   represents the context in which a user most likely believes
|   themselves to be interacting.  We'll label this domain the "top-level
|   site".
|
|   For a document displayed in a top-level browsing context, we can stop
|   here: the document's "site for cookies" is the top-level site.
|
|   For documents which are displayed in nested browsing contexts, we
|   need to audit the origins of each of a document's ancestor browsing
|   contexts' active documents in order to account for the "multiple-
|   nested scenarios" described in Section 4 of [RFC7034].  These
|   document's "site for cookies" is the top-level site if and only if
|   the document and each of its ancestor documents' origins have the
|   same registered domain as the top-level site.  Otherwise its "site
|   for cookies" is the empty string.

/ Kari Hurtta

---

From: Kari Hurtta <[email-masked]>
Date: Wed, 10 Apr 2019 19:59:39 +0300 (EEST)

HTTP State Tokens

|   o  Exactly one member whose key is "delivery", and whose value is one
|      of the following tokens ([I-D.ietf-httpbis-header-structure],
|      Section 3.9): "same-origin", "same-site", or "cross-site".
|
|      If the "delivery" member contains an unknown identifier, the
|      member MUST be ignored.

This does not work for delivery=same-origin because 

Sec-Http-State: header field is generated on first reguest
and default is delivery=same-site.

That is before http client have seen Sec-Http-State-Options
reponse header field.

This solution is subset from my "Server/Site opt-in" suggestion
( <[email-masked]>
   https://lists.w3.org/Archives/Public/ietf-http-wg/2019AprJun/0007.html

  That my "Server/Site opt-in" suggestion also needs
  some changes yet. It does not work well on subresources
  which need user opt in / opt out.
)

This solution includes also delivery=none for origins
which want mimize request size (delivery=none is not
state for user opt out).
( <[email-masked]>
  https://lists.w3.org/Archives/Public/ietf-http-wg/2019JanMar/0251.html
)

On another mail I suggested to replace "same-site" with "same-domain".
I mark this now as "same-site" [or "same-domain"].
( <[email-masked]> 
  https://lists.w3.org/Archives/Public/ietf-http-wg/2019AprJun/0013.html
)

This soulution  inserts

is request header when origin's delivery mode is not known.  This
is syntaxtically different from token which gives gives binary value
/ byte sequence because that uses * to indicate base64 encoded value.

( My some other suggestions use also

as request heaedr).

3.1.  HTTP State Tokens

|   o  "delivery" specifies the initiating contexts from which the token
|      can be delivered.  It is an enum of either "same-origin", "same-
|      site", or "cross-site".  Unless otherwise specified, its value is
|      "same-site".

⇒

----
    o  "delivery" specifies the initiating contexts from which the token
       can be delivered.  It is an enum of either "query", "none", 
       "same-origin", "same-site" [or "same-domain"], or "cross-site".  
       Unless otherwise specified, its value is "query".
----

3.3.1.  Generate an HTTP State Token for an origin
https://tools.ietf.org/html/draft-west-http-state-tokens-00#section-3.3.1

|   2.  Let "token" be a newly created HTTP State Token with its
|       properties set as follows:
|
|       *  "creation": The current time.
|
|       *  "delivery": "same-site"

⇒

----

       *  "delivery": "query"

----

|       *  "key": null
|
|       *  "max-age": 3600
|
|
|       *  "value": 256 cryptographically random bits.

|   o  Exactly one member whose key is "token", and whose value is binary
|      content ([I-D.ietf-httpbis-header-structure], Section 3.9) that
|      encodes the HTTP state token's value for the origin to which the
|      header is delivered.
|
|      If the "token" member contains more than 256 bits of binary
|      content, the member MUST be ignored.

⇒

----

   o  Exactly one member whose key is "token". Value of this key
      is either a byte sequence (sh-binary, 
      [draft-ietf-httpbis-header-structure-09], Section 3.10) or a 
      token (sh-token, [draft-ietf-httpbis-header-structure-09], Section 3.9).

      The byte sequence encodes the HTTP state token's value for the origin to which the
      header is delivered. This is a binary content.

      If the "token" member contains more than 256 bits of binary
      content, the member MUST be ignored.
   
      The token value (as sh-token) is "query". This indicates that
      http client supports HTTP state tokens, but needs value
      for "deliver".

---- 

      ( On my other suggestions include token value (as sh-token) 
        which is "void". It also indicates that
        http client supports HTTP state tokens, but a binary content
        could not deliver. )

|   o  Exactly one member whose key is "delivery", and whose value is one
|      of the following tokens ([I-D.ietf-httpbis-header-structure],
|      Section 3.9): "same-origin", "same-site", or "cross-site".

⇒

----

   o  Exactly one member whose key is "delivery", and whose value is one
      of the following tokens ([draft-ietf-httpbis-header-structure-09],
      Section 3.9): "none", "same-origin", "same-site" [or "same-domain"], 
      or "cross-site".

      Note: "delivery"'s value "query" is initial value for metadata
            and not allowed on "Sec-Http-State" response header.

----

5.1.  Attach HTTP State Tokens to a request
https://tools.ietf.org/html/draft-west-http-state-tokens-00#section-5.1

   5a.  If "request-token"'s "delivery" is "null", then skip the remaining steps in
        this algorithm, and return without modifying the request.

   5b.  If "request-token"'s "delivery" is "query", then:

        1. The user agent MAY omit generating Sec-Http-State: request
           header if it determines that origin does not support
           HTTP State Tokens.

           It is not required that all URL's for the origin
           responds with Sec-Http-State: response header
           for query.

        Note: Sec-Http-State: response header for query 
              may be genrated only for certain URLs
              (for example login and/or front page's
               URLs).

        2.  Insert a member into "header-value" whose key is "token" and
            value is "query" (using sh-token syntax).

        3. Skip the remaining steps in this algorithm.

|      8.   Insert a member into "header-value" whose key is "token" and
|        whose value is "serialized-value".

⇒

----
       
   8.   Insert a member into "header-value" whose key is "token" and
        whose value is "serialized-value" (using sh-binary syntax).

-----

6.  Configuring HTTP State Tokens
https://tools.ietf.org/html/draft-west-http-state-tokens-00#section-6

|           +  "header" has a member named "delivery" whose value is not
|              one of the following tokens (Section 3.9 of
|              [I-D.ietf-httpbis-header-structure]): "same-origin",
|              "same-site", and "cross-site".

⇒

----

           +  "header" has a member named "delivery" whose value is not
              one of the following tokens (Section 3.9 of
              [I-D.ietf-httpbis-header-structure]): "none", "same-origin",
              "same-site" [or "same-domain"], and "cross-site".
----

/ Kari Hurtta

---

From: Kari Hurtta <[email-masked]>
Date: Sun, 14 Apr 2019 13:15:29 +0300 (EEST)

HTTP State Tokens

Servers assume that client does not support HTTP State Tokens
when request does not include Sec-Http-State: header field, I
assume.

Then server generate session state itself and includes
Set-Cookie: response header. In that situation it does
not make sense to add Sec-Http-State-Options: response
header, because Cookie is already requested (with associated
session state).

Therefore there is also two problems with cross-site 
requests (and not only with delivery=same-origin).

1) "delivery=cross-site" case:

This does not work for delivery=cross-site 

Default is delivery=same-site and therefore initial request
does not include Sec-Http-State: header field. Server
can not just return Sec-Http-State-Options: response
header field, because server does not know that is this 
initial request or was server already returned 
Sec-Http-State-Options: response header field.

Therefore server needs return Set-Cookie: response header field
(and allocate state for client). 

Because state for client is allocated and Set-Cookie: response 
header field is added to response, it does not make sense
also add Sec-Http-State-Options: response
header field.

Therefore initial request needs 

also on cross-site requests.

2)  cross-site requests when state is not wanted:

Server (probably) does not know that request is cross site
and because request does not include Sec-Http-State: header field
server assumes that  HTTP State Tokens are not supported.

Therefore server adds Set-Cookie: response 
header field (with SameSite flag) to response and
allocate state for client. That state is wasted.

Therefore cross-site requests needs

when "delivery" is know (and "delivery" is not "none" (1)) and 
token value is not allowed to be returned.

Note:  Of course that same problem for server is also
       when client does not support HTTP State Tokens.

       But using of HTTP State Tokens need to provide
       some advantage for server, otherwise server
       make sense use only cookies. Code for cookies
       is needed anyway, because all clients does not
       support HTTP State Tokens.

3) also same-domain  requests when state is not wanted:

Server have returned 
  Sec-Http-State-Options: delivery=same-origin
on first request.

Second request does not include Sec-Http-State: header field.
Also here server (probably) does not know that request
is not same-origin request and because request does not 
include Sec-Http-State: header field server assumes that  
HTTP State Tokens are not supported.

Therefore server adds Set-Cookie: response 
header field (with host cookie) to response and
allocate state for client. That state is wasted.

Therefore same domain (but not same origin) requests needs

when "delivery" is know (and "delivery" is not "none" (1)) and 
token value is not allowed to be returned.

(*) delivery=none, where server want mimize request size, is exception. 
This delivery=none is not state for user opt out. Suggested on
<[email-masked]>
https://lists.w3.org/Archives/Public/ietf-http-wg/2019JanMar/0251.html

Giving

may also deflect some attacks, where otherwise server is tricked
to use data from less secure Cookie: -request header field.

If server uses HTTP State Tokens and Cookie for similar purpose,
server should ignore correspond Cookie: -request header field
when Sec-HTTP-State: -request header field is present (even when token
does not include base64 encoded byte sequence).

Sec-HTTP-State:  -request header field's token values are 
syntactically different, when it is a byte sequence (sh-binary, 
[draft-ietf-httpbis-header-structure-09], Section 3.10) and 
when it is a token (sh-token, [draft-ietf-httpbis-header-structure-09], 
Section 3.9).

This solution extens my "delivery=same-origin" suggestion
( <[email-masked]> 
  https://lists.w3.org/Archives/Public/ietf-http-wg/2019AprJun/0026.html
)
Changes mentioned on my "delivery=same-origin" suggestion should
also be assumed.

This solution is also variant of  my "Server/Site opt-in" suggestion
( <[email-masked]>
   https://lists.w3.org/Archives/Public/ietf-http-wg/2019AprJun/0007.html

To avoid initial

wanted "delivery" value for origin need to be cached separatetely
from Token Storage and with longer cache time than 1 hour (for
example 50 hours). That may be then used when HTTP State Token is 
generated for origin. However I do NOT now include changes
for separate "delivery" value for origin cache.

Changes are:

3.1.  HTTP State Tokens

( as on "delivery=same-origin" suggestion <[email-masked]> )

( as on "delivery=same-origin" suggestion <[email-masked]> )

⇒

----

   
      The token value (as sh-token) is "query" or "void".

      Value "query" indicates that http client supports HTTP state tokens, but 
      needs value for "deliver".
     
      Value "void" indicates  that http client supports HTTP state tokens, but
      "deliver" does not allow returning of a byte sequence.

( as on "delivery=same-origin" suggestion <[email-masked]> )

|   5.   If "request-token" is "null", then:
|
|        1.  If "request"'s delivery scope is "cross-site", return
|            without modifying the request.
|
|            Note: As the default "delivery" for HTTP State Tokens is
|            "same-site", we return early rather than generating a token
|            for a cross-site request.
|
|        2.  Set "request-token" to the result of generating an HTTP
|            State Token for "target-origin", as defined in
|            Section 3.3.1.

⇒

----

   5.   If "request-token" is "null", then:

        1.  If "request"'s delivery scope is "cross-site", then
            execute "attach query" and skip the remaining steps in this 
            algorithm.

        2.  Set "request-token" to the result of generating an HTTP
            State Token for "target-origin", as defined in
            Section 3.3.1.

-----

After step 5 add following steps:

⇒

----

   5b.  If "request-token"'s "delivery" is "query", then
        execute "attach query" and skip the remaining steps in this 
        algorithm.

----

|   6.   Return without modifying the request if either of the following
|        statements are true:
|
|        *  "request-token"'s "delivery" is "same-origin", and
|           "request"'s delivery scope is not "same-origin".
|
|        *  "request-token"'s "delivery" is "same-site", and "request"'s
|           delivery scope is neither "same-origin" nor "same-site".

⇒   

----

    6. Execute "attach void" and skip the remaining steps in this 
       algorithm  if either of the following statements are true:

        *  "request-token"'s "delivery" is "same-origin", and
           "request"'s delivery scope is not "same-origin".

        *  "request-token"'s "delivery" is "same-site" [or "same-domain"] , 
           and "request"'s delivery scope is neither "same-origin" nor 
           "same-site" [or "same-domain"].

----

 ( Step 8. as on "delivery=same-origin" suggestion <[email-masked]> )

Addition:

⇒

----

  "attach query" algoritm is following:

        2.  Insert a member into "header-value" whose key is "token" and
            value is "query" (using sh-token syntax). Note that sh-syntax
            does not use quotes.

  "attach void" algoritm is following:
  
        1.  Insert a member into "header-value" whose key is "token" and
            value is "void" (using sh-token syntax). Note that sh-syntax
            does not use quotes.

----

( Original step 5. does not make sense, there is no request to modify !!! 
  This is response processing !!!
)

|   5.  If "token" is "null", then:
|
|       1.  If "request"'s delivery scope is "cross-site", return without
|           modifying the request.
|
|           Note: As the default "delivery" for HTTP State Tokens is
|           "same-site", we return early rather than generating a token
|           for a cross-site request.
|
|       2.  Set "token" to the result of generating an HTTP State Token
|           for "target-origin", as defined in Section 3.3.1.

⇒

-----

   5.  If "token" is "null", then:

       1.  If "request"'s delivery scope is "cross-site" and
           response's header list does not contain "Sec-Http-State-Options",
           return without altering "response-origin"'s HTTP
           State Token.

       2.  Set "token" to the result of generating an HTTP State Token
           for "response-origin", as defined in Section 3.3.1.

-----

( Step 6. substep 2. "delivery" check as as on "delivery=same-origin" 
  suggestion <[email-masked]> )

/ Kari Hurtta

---

From: Kari Hurtta <[email-masked]>
Date: Fri, 19 Apr 2019 20:48:45 +0300 (EEST)

HTTP State Tokens

In some cases server do not trust that these bytes are random.
That case server need defend agaist that two cliets issue
same token byte sequence (binary content) to token value on
Sec-HTTP-State: -request field.

| 4.2.  The 'Sec-Http-State-Options' HTTP Header Field
https://tools.ietf.org/html/draft-west-http-state-tokens-00#section-4.2

|  o  Exactly one member whose key is "key", and whose value is binary
|      content ([I-D.ietf-httpbis-header-structure], Section 3.10) that
|      encodes an key which can be used to generate a signature over
|      outgoing requests.

Key comes to play here.

Difficulty comes here that different client must got different key
but server  can not trust that token is unique token value (because 
purpose was defend agaist non-unique byte sequence (binary content).

Answer is not that "of course client generates unique tokens". But
that is how server can verify that. Not just trust.

Let's look options:

 • Server gives same "key" for different http requests which
   use same token=*xxxxx* value.

  ⇒  Two http clients which generate same token=t same *xxxxx* value
    key.

     ⇒ FAILURE to defend agaist non-unique byte sequences.

 • Server gives "key" once for same token=*xxxxx* value.

  ⇒  If that http esponse is interrupted (connection broken),
    client does not got "key" at all

    ⇒  Generated token=*xxxxx* value is non-functional, and
     site fails.

     User CAN'T fix that by pressing reload.

     Only fix is wait that Token Storage for that origin
     is expired (after 1 hour with default "max-age"
     value) or that user clears Token Storage.

 • Server gives different "key" for same token=*xxxxx* value
   on different requests.

     ⇒  Server needs allocate state for (token,key) pair

      AND match "sig" again every key for given token
  
       ⇒  Browser may have lauched many concurrent
      request for same origin, therefore same token
      (and without sig, because key os not yet given).

        ⇒  This leads many (token,key) pairs and many states
       on server.

        ⇒  This is make processing of request including 
       "sig" expensive and causes that different
       request have used different state on server
       (because different (token,key) pair) until
       last key is received by browser.

My solution:

‣ Browser needs some URL which it uses only
  to get key. 
‣ Server gives different "key" for same token=*xxxxx* value
  on different requests but only for that special URL.

On <[email-masked]> 
https://lists.w3.org/Archives/Public/ietf-http-wg/2018JulSep/0222.html

I suggested /.well-known/ path for that.

But now I suggest another URL.
 
I have not determined what should be request method
for that URL and what to do with response (except that 
Sec-Http-State-Options: response header is processed)
and response body (if request method is GET).

----
   o  Exactly one member whose key is "register" and whose value is an
      string ([draft-ietf-httpbis-header-structure-10], Section 3.8)
      representing a path which http request response will
      give "key" for this Http State. 

      User Agent will use that path only when Http State does not
      include value for "key". Value of "register" is NOT saved
      HTTP State Token.
-----

( Assume changes for my suggestion "cross-site"
  <[email-masked]> 
  https://lists.w3.org/Archives/Public/ietf-http-wg/2019AprJun/0037.html
)

|       2.  Return without altering "response-origin"'s HTTP State Token
|           if any of the following conditions hold:

new substep

⇒

-----
           +  "header" has a member named "register" whose value is not a
              string ([draft-ietf-httpbis-header-structure-10], Section 3.8).
-----

|   6.  If the response's header list contains "Sec-Http-State-Options",
|       then:

new substep

⇒

-----
 
       6.   If "header" has a member named "register":

            1. If value of "register" member does
               not match syntax of origin-form
               ([RFC 7230], Section 5.3.1),
               skip next steps.

            2. Let "register URL" to be catenation
               "response-origin" and value of "register" member.
               
            3. If "token"'s "key" is set, skip next steps.

            4. if "fetch register" is scheduled (but not completed) 
               for "response-origin", skip next steps.

            5. If this "HTTP-network-or-cache fetch" is called
               from "fetch register" algorithm, skip next steps.

               Note: This prevents loop where every "fetch register"
                     causes new "fetch register" to be scheduled.
                     That happens if response still have "register"
                     on "Sec-Http-State-Options".

               ( TBD: Is this working? Should HTTP-network-or-cache fetch
                      have optional "register-fetch flag" ? ) 

            6. Schedule "fetch register" for "response-origin"
               with following parameters
                + "origin" is given "response-origin"
               
                + "URL" is given "register URL"
                + "client" is request's "client"
                   from this execution of HTTP-network-or-cache fetch
                   (  ? TBD ? )
                + "credentials mode" is request's "credentials mode"     
                   from this execution of HTTP-network-or-cache fetch
                   (  ? TBD ? )
                + "destination"  is request's "destination"
                   from this execution of HTTP-network-or-cache fetch
                   ( ? TBD ? )
                + "window" is request's "window"
                   from this execution of HTTP-network-or-cache fetch
                + TBD

-----

Addition

⇒

-----

   "fetch register" algorithm is following:

       1. let "request" have following associated data:
 
          + "method"  is "GET"   if  parameter "destination"'s value is "document"
            "method"  is "HEAD"  otherwise
             ( TBD:  what is correct "method" ? -- depends what we want to do with response body? 
                     Or should methed be "OPTIONS" ?  This is also likely avoid caches.
             )
             
          + "origin"  is parameter "origin"'s value
          + "URL"     is parameter "URL"'s value
          + "client"  is parameter "client"'s value
          + "credentials mode" is parameter "credentials mode"'s value
          + "destination" is parameter "destination"'s value
          + "window"  is parameter "window"'s value
          + "referer" is "no-referrer"
          + "cache-mode" is "reload"
          + (TBD? should "redirect mode" be "error" ? )
          + (TBD? Maybe this)
             "header list" includes 
              "Cache-Control" / "no-cache, no-store"
          + TBD

          ( TBD: Actually just is is wanted that 
              "Sec-Http-State" request header field is reached 
              server maintaining state, and
              that "Sec-Http-State-Options" response header
              field is one shot and comes from server maintaining state
              and not cached. 

              Response may include
                  Cache-Control: no-cache=Sec-Http-State-Options
              but is this implemented?

              Cache on TLS terminator probably ignores requests 
              Cache-Control anyway.

              In theory

              Cache-Control: no-store

              should be enough, because no-store forbid using cache                
              at all.
          )

       2. Assert: "credentials mode" of "request" is either
                  "include" or  "same-origin"

       3. Execute "HTTP-network-or-cache fetch" for "request"

          Note: This causes that this Configuring HTTP State Tokens
                 -algorithm is executed also for that fetch register
                 -algorithm and therefore possible "key" is set if
                 returned on "Sec-Http-State-Options".

                Because this uses "HTTP-network-or-cache fetch" and
                not "HTTP fetch" algorithm, this is not exposed
                to a service worker (but also redirects from
                from the network are not exposed either).

        3. TBD: handling of response body 

           Do we want this work as some kind redirection where response
           replaces current document if there is response body ?
           (and updates URL of that also)
           Probably does not make sense.

           Thish makes sense only when "destination" is "document"
           on original fetch which caused "fetch register" scheduled. 

           Or is response body some kind special xml or json
           type, which is parsed hdere.

           Or shouild here show error message when that fetch fail
           (probably just show that response body) ?

---

From: Kari Hurtta <[email-masked]>
Date: Sat, 27 Apr 2019 19:14:52 +0300 (EEST)

HTTP State Tokens

For Server opt-in (or opt-out) on
( <[email-masked]>
  https://lists.w3.org/Archives/Public/ietf-http-wg/2019AprJun/0007.html
)

I used delivery=void  and same value on "delivery" metadata
on HTTP State Token.

This not work well on subresources which need user opt in / opt out.
User opt in / out questions are practical to query from origin
of top browser content. Origins which serve for example images
are bad position to ask from user.

http://ec.europa.eu/ipg/basics/legal/cookies/index_en.htm

If HTTP State Token is

"used for the sole purpose of carrying out the transmission of a
 communication, and strictly necessary in order for the provider of
 an information society service explicitly required by the user to
 provide that service"

then user opt in is not needed. So authentication, session-id,
load-balancing for example does not need user consent.
In that case origin can (and should) confirm  HTTP State Token
without prompt from user.

When origin is used for resources and not top level document,
it need delegate opt-in / opt-out to top level origin
if user consent is needed.

The "delivery" metadata of HTTP State Token can not used
for mark that "delegate to top" because origin needs
store real "delivery" option to it.

This solution uses "confirm" metadata of HTTP State Token
for origin opt-in / opt-out / delegate to top.

I call that top level origin for that purpose as
"confirm-top-origin". SameSite cookies (
https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-02#section-5.2.1
5.2.1.  Document-based requests )
use more complex definition for top level
origin. This needs more consideration.
Also now Worker-driven requests probably
gets "confirm-top-origin" as null. This is
probably OK for this purpose.

Also SameSite's "site for cookies" algorithm quits
when some ancestor browsing contexts have different
registered domain. That is not usable when determining
top level origin for confirm=top.

There is no "delivery=void" as there was
on my mail "Server/Site opt-in" (
<[email-masked]>
https://lists.w3.org/Archives/Public/ietf-http-wg/2019AprJun/0007.html )
instead "confirm=block" is used for that purpose.

There is "Sec-Http-State:"  dictionary member, whose key is "token",
have value which is either byte sequence (sh-binary) or token (sh-token).

That "token" with value type sh-token is also used on delivery
related solutions
"delivery=same-origin" (
<[email-masked]>
https://lists.w3.org/Archives/Public/ietf-http-wg/2019AprJun/0026.html
) and "cross-site" (
<[email-masked]>
https://lists.w3.org/Archives/Public/ietf-http-wg/2019AprJun/0037.html )

Another  HTTP State Token metadata is used on
top level origin to track opt-in for origins, which
use confirm=top. Metadata "deliver-origins" is list
of origins for which are allowed to use request

Sec-Http-State: token=*value*

when confirm=top for that origin and delivery -value allows
giving of token value.

Sec-Http-State: token=query

indicates either that value for "confirm" is needed
or that value for "delivery" is needed per
"delivery=same-origin" (
<[email-masked]>
https://lists.w3.org/Archives/Public/ietf-http-wg/2019AprJun/0026.html
) and "cross-site" (
<[email-masked]>
https://lists.w3.org/Archives/Public/ietf-http-wg/2019AprJun/0037.html ).

Sec-Http-State: token=void

indicates either that value of "confirm" or
that value of "delivery" blocks producing

Sec-Http-State: token=*value*

To resolve that, dictionary of Sec-Http-State
may contain member whose key is "reason".

This have values

     reason=delivery	Value for "delivery" is required
     			or "delivery" blocks token.

     reason=confirm     Value for "confirm" is required
     			or "confirm" blocks token.

     reason=top		There is confirm=top but 
     			HTTP State Token for top level
			origin does not list current
			origin on "deliver-origins"
			metadata.

     reason=no-top      There is confirm=top but
                        top level origin is not available.
     			
     reason=delivery/confirm  Values for "delivery" and
     			     "confirm" are required.

Dictionary of Sec-Http-State-Options may contain
member whose key is "confirm" and whose value is
one of "block", "deliver", or "top".

Value "block" for "confirm" indicates that

Sec-Http-State: token=void; reason=confirm

is sent instead of

Sec-Http-State: token=*value*

( assuming that "delivery" allows producing token=*value* ).

Value "deliver" for "confirm" causes that

Sec-Http-State: token=*value*

is sent ( assuming that "delivery" allows producing
token=*value* ).

Value "top" for "confirm" indicates that

either

Sec-Http-State: token=void; reason=top

or

Sec-Http-State: token=*value*

is produced ( assuming that "delivery" allows producing
token=*value* ).

If "delivery" indicates that token=query
or token=void should be produced, that
is used even when "confirm" indicates another
value. On that case reason=delivery is
used if "confirm" disagrees.

However

Sec-Http-State: token=void; reason=delivery/top

is not used.

When "delivery" causes token=void  generated,
value of "confirm" is not consulted. That causes

Sec-Http-State: token=void; reason=delivery

to be generated.

This solution extends my "delivery=same-origin" suggestion
( <[email-masked]> 
  https://lists.w3.org/Archives/Public/ietf-http-wg/2019AprJun/0026.html
) and my "cross-site"  suggestion
( <[email-masked]>
  https://lists.w3.org/Archives/Public/ietf-http-wg/2019AprJun/0037.html
  ).

Changes mentioned on my "delivery=same-origin" and "cross-site"
suggestions should also be assumed.

This solution does not be practical when HTTP State Token
is used several places:

    o On load balancer on TLS terminator. That usage
      does not require user consent,

    o And same time on back end servers on way, which requires
      user's consent.

Specially that breaks when user does not consent usage
on back end servers. I guess that on that situation
load balancer needs use Cookie instead. That then breaks
when user is configured browser to ignore cookies and allow
HTTP State Tokens only. ( But if backend server do not
have state, it does not matter lot which server is
selected on load balancing. So that breakage probably
does not matter.)

This solution includes also delivery=none for origins
which want minimize request size (delivery=none is not
state for user opt out).
( <[email-masked]>
  https://lists.w3.org/Archives/Public/ietf-http-wg/2019JanMar/0251.html
)

SameSite's "site for cookies" algorithm looks all ancestor
browsing contexts and quits when some ancestor browsing contexts
have different registered domain. It just not look "request-origin"
and "target-origin".

So I think that delivery should use delivery=same-domain
instead. And Sec-Http-State-Options have also
same-site=?0 or same-site=?1

And that "same-site" looks ancestor browser contents
and sandboxed origin browsing context flag as SameSite
looks. That makes difference also on delivery=same-origin
situations.

But that is not part of this Server/Site opt-in solution.

On my previous "Server/Site opt-in" suggestion
( <[email-masked]>
   https://lists.w3.org/Archives/Public/ietf-http-wg/2019AprJun/0007.html
) I wrote

> there need also method for Javascript to set that

On this suggestion Javascript does not have access
to HTTP State Token's "delivery" property, but Javascipt
have read/write access to "confirm" and "deliver-origins"
properties of HTTP State Token. Third new HTTP State Token
metadata is "query-origins", which  Javascipt have read access.
Metadata "query-origins" is list.

When confirm=top is seen on Sec-Http-State-Options, response
origin is added to  "query-origins" metadata on
top level origin's HTTP State Token.

There was algorithm NotifyHostHTTPStateReset()
which is called for origin when origin's  HTTP State Token
is generated. Similarly there also can be algorithm NotifyHostHTTPStateQuery()
which is called with top level origin and response origin.
This NotifyHostHTTPStateQuery() is called when new origin is
added to  "query-origins" metadata on top level origin's HTTP State
Token.

This may execute Javascript on content of top level origin
(on content of top level document) with added response
origin's name as argument.

This allows producing implementing user opt in / out from
Javascript.

To avoid initial

   Sec-HTTP-State: token=query; reason=delivery/top

request header filled, "delivery", "confirm" and
"deliver-origins" values for origin need to be cached separately
from Token Storage and with longer cache time than 1 hour (for
example 50 hours). That may be then used when HTTP State Token is 
generated for origin. However I do NOT now include these changes.

Changes are:

3.1.  HTTP State Tokens

⇒

----

Addition:

⇒
----

    o "confirm" specifies server or user opt-in/opt-out.  It is an enum of
       either "query", "block", "deliver", or "top".  Unless otherwise specified,
       its value is "query".     

       User agent MAY allow to configure default value of "confirm"
       to either "query", "block" or "deliver". For example command
       line HTTP client may provide command option for specify
       default value of "confirm".

    o "deliver-origins" is list of origins in which token for that origin
       can be delivered if "confirm" metadata for that origin specifies
       "top".

    o "query-origins" is list of origins , whose "confirm" metadata specifies
       "top".

    Note: Both  "delivery" and "confirm" needs initial value "query" because
          it is unlikely that origin can set them same time when user consent
	  is required.

    [TBD: "query-origins" is lost when token is expired. ]

    [TBD: If user agent implements Javascript, that should be
          have read/write access to "confirm" and "deliver-origins"
	  properties of HTTP State Token on correspond origin. ]

    [TBD: Some HTTP clients (for example data mining tools)
          may not instantiate browsing contexts. On these
	  default value for "confirm" may need to be configured
	  to other value than "query". ]

----

⇒

----

   2.  Let "token" be a newly created HTTP State Token with its
       properties set as follows:

       *  "creation": The current time.

       *  "delivery": "query"

----

Addition:

⇒

----

       * "confirm": "query"

       * "deliver-origins": empty list

       * "query-origins": empty list

----

      [ TBD: Should "query-origins" to be recalculated on reset?
             This means walking all browsing context
	     which origin is same than HTTP State Token's
	     origin and then look all child browsing
	     content and  HTTP State Tokens for them
	     for "confirm"'s value "top". ]

⇒

----

   o  Exactly one member whose key is "token", and whose value is
      either a byte sequence (sh-binary, [draft-ietf-httpbis-header-structure-10],
      Section 3.10) or a token (sh-token, [draft-ietf-httpbis-header-structure-10],
      Section 3.9).

      If the "token" member (as sh-binary) contains more than 256 bits of binary
      content, the member MUST be ignored.

      Value "query" indicates that HTTP client supports HTTP state tokens, but 
      needs value for "delivery" or "confirm".

      Value "void" indicates  that HTTP client supports HTTP state tokens, but
      "delivery" or "confirm" does not allow returning of a byte sequence.

----

|   The dictionary MAY contain:

Addition:

⇒

----

   o  Exactly one member whose key is "reason", and whose value
      is one of the following tokens (sh-token,
      [draft-ietf-httpbis-header-structure-10], Section 3.9):
      "delivery", "confirm", "top", "no-top", or "delivery/confirm".

------

|   The dictionary MAY contain:

and there

⇒

----

   o  Exactly one member whose key is "delivery", and whose value is one
      of the following tokens ([draft-ietf-httpbis-header-structure-10],
      Section 3.9): "none", "same-origin", "same-site" [or "same-domain"], 
      or "cross-site".

      Note: "delivery"'s value "query" is initial value for metadata
            and not allowed on "Sec-Http-State-Options" response header.

----

Addition:

⇒

----

   o  Exactly one member whose key is "confirm" and whose value is one
      of the following tokens ([draft-ietf-httpbis-header-structure-10],
      Section 3.9): "deliver", "top",  and "block".

      Note:  "confirm"'s value "query" is initial value for metadata
             and not allowed on "Sec-Http-State-Options" response header.

   o  Exactly one member whose key is "deliver-origins" whose value is
      string ([draft-ietf-httpbis-header-structure-10], Section 3.8).

      Value includes comma separated list of origins.
-----

|   3.   Let "request-token" be the result of retrieving origin's token
|        from the user agent's token store, or "null" if no such token
|        exists.

I suppose
⇒

----
   3.   Let "request-token" be the result of retrieving target-origin's token
        from the user agent's token store, or "null" if no such token
        exists.
----

After step 3 add following step:

⇒

----
   3a. Execute  "get confirm-top-origin" for this request.
       Result of that algorithm is "confirm-top-origin".
       
       Note: This can be null.
                    
----

⇒

----

       1.  If "request"'s delivery scope is "cross-site", then
            execute "attach query" with "reason" value "delivery/confirm"
	    and skip the remaining steps in this 
            algorithm.

⇒

----
   5a.  If "request-token"'s "delivery" is "none", then skip the remaining steps in
        this algorithm, and return without modifying the request.

        1. If "request-token"'s "confirm" is "query",
	   execute "attach query" with "reason" value "delivery/confirm"
	   and skip the remaining steps in this 
           algorithm.

        2. Execute "attach query" with "reason" value "delivery"
	   and skip the remaining steps in this 
           algorithm.
	   
----

⇒

----
    6. Execute "attach void" with "reason" value "delivery"
       and skip the remaining steps in this algorithm  if
       either of the following statements are true:

           "same-site".

----

After step 6 add following steps:

⇒

----
   6a.  If "request-token"'s "confirm" is "query",
        execute "attach query" with "reason" value "confirm"
	and skip the remaining steps in this algorithm.

   6b.  If "request-token"'s "confirm" is "top", then:

        1. If "confirm-top-origin" is null,
	   execute "attach void"  with "reason" value "no-top"
	   and skip the remaining steps in this algorithm.

        2. Let "top-token" be the result of retrieving
	   "confirm-top-origin"'s token from the user agent's token
	   store, or "null" if no such token exists.

        3. If "top-token" is expired, clear the user agent's token
           store for  "confirm-top-origin", and set "top-token"
	   to "null".

        4. If "top-token" is "null", execute "attach void"
	   with "reason" value "top" and skip the remaining steps
	   in this algorithm.

        5. If "top-token"'s "deliver-origins" list does not
	   include "target-origin", execute "attach void"
	   with "reason" value "top" and skip the remaining steps
	   in this algorithm.

   6c.  If "request-token"'s "confirm" is "block",
        execute "attach void" with "reason" value "confirm" and
	skip the remaining steps in this algorithm.
----

⇒

----
       
   8.   Insert a member into "header-value" whose key is "token" and
        whose value is "serialized-value" (using byte sequence
	(sh-binary, [draft-ietf-httpbis-header-structure-10], Section 3.10)
	syntax).

-----

|   9.   If "request-token"'s "key" is not null, then insert a member
|        into "header-value" whose key is "sig", and whose value is the
|        result of executing Section 5.2 on request, "serialized-value",
|        and "request-token"'s "key".

⇒
Maybe also add note that value is added as a byte sequence:

----
   9.   If "request-token"'s "key" is not null, then insert a member
        into "header-value" whose key is "sig", and whose value as
	a byte sequence is the result of executing Section 5.2 on request,
	"serialized-value", and "request-token"'s "key". Base64 Encode a byte
	sequence and use byte sequence (sh-binary,
	[draft-ietf-httpbis-header-structure-10], Section 3.10) syntax.
----

Addition:

⇒

-----

"get confirm-top-origin" algorithm is following:

   1. Let "top-browsing-context" to be request's client's
      responsible browsing context or null if request's client is null.

      Note: Request's client's responsible browsing context may be null.
   
   2. while "top-browsing-context" is not null and "top-browsing-context"'s
      have a parent browsing context: 
         let "top-browsing-context" to be "top-browsing-context"'s parent browsing context.

   3. Let "top-document" to be "top-browsing-context"'s active document
       or null if "top-browsing-context" is null.

   4. Let "confirm-top-origin" to be "top-document"'s origin
        or null if "top-document" is null.

       Note: SameSite uses different definition for top-origin.

       [TBD: SameSite quits when some some ancestor browsing
             contexts have different registered domain. That
	     is not usable on here. ]

       [TBD: SameSite looks also sandboxed origin browsing
             context flag. Should that affect "confirm-top-origin" ? ]

       [TBD: Not looked what this does for worker-based requests.
             Perhaps this is OK for "confirm-top-origin". ]

       [TBD: Some HTTP clients (for example data mining tools)
             may not instantiate browsing contexts. In that case
	     "confirm-top-origin" is null. ]

"attach query" algorithm is following:

       It is not required that all URL's for the origin
       responds with Sec-Http-State-Options: response header
       for query.

       Note: Sec-Http-State-Options: response header for query 
             may be generated only for certain URLs
             (for example login and/or front page's
              URLs).

    2.  Insert a member into "header-value" whose key is "token" and
        value is "query" (using token (sh-token,
	[draft-ietf-httpbis-header-structure-10], Section 3.9) syntax).
	Note that sh-syntax does not use quotes.
	    
    3.  Insert a member into "header-value" whose key is "reason"
        and value is  "reason" value for that algorithm
	(using token (sh-token,
	[draft-ietf-httpbis-header-structure-10], Section 3.9) syntax).

    4.  Append a header to "request"'s header list whose name is "Sec-
        Http-State", and whose value is the result of serializing
        "header-value" ([draft-ietf-httpbis-header-structure-10],
        Section 4.1).

 "attach void" algorithm is following:
  
    1.  Insert a member into "header-value" whose key is "token" and
        value is "void" (using token (sh-token,
	[draft-ietf-httpbis-header-structure-10], Section 3.9) syntax).
	Note that sh-syntax does not use quotes. 

    2.  Insert a member into "header-value" whose key is "reason"
        and value is  "reason" value for that algorithm
	(using token (sh-token,
	[draft-ietf-httpbis-header-structure-10], Section 3.9) syntax).

    3. Append a header to "request"'s header list whose name is "Sec-
       Http-State", and whose value is the result of serializing
       "header-value" ([draft-ietf-httpbis-header-structure-10],
       Section 4.1).

-----

⇒

-----

-----

After step 5 add following step:

⇒

----

  5a.  Execute  "get confirm-top-origin" for this request.
       Result of that algorithm is "confirm-top-origin".
       
       Note: This can be null.

       [TBD: This executed as part of Section 5.2
             so "confirm-top-origin" may already be available. ]

-----

On step 6:

|       2.  Return without altering "response-origin"'s HTTP State Token
|           if any of the following conditions hold:
|
|          +  Parsing the header results in failure.
|
|           +  "header" has a member named "key" whose value is not a
|              byte sequence (Section 3.10 of
|              [I-D.ietf-httpbis-header-structure])
|
|           +  "header" has a member named "delivery" whose value is not
|              one of the following tokens (Section 3.9 of
|              [I-D.ietf-httpbis-header-structure]): "same-origin",
|              "same-site", and "cross-site".
|
|           +  "header" has a member named "max-age" whose value is not a
|              positive integer (Section 3.6 of
|              [I-D.ietf-httpbis-header-structure]).

⇒

----

      2.  Return without altering "response-origin"'s HTTP State Token
          if any of the following conditions hold:

           +  Parsing the header results in failure.

           +  "header" has a member named "key" whose value is not a
              byte sequence ([draft-ietf-httpbis-header-structure-10],
	      Section 3.10)

           +  "header" has a member named "delivery" whose value is not
              one of the following tokens
	      ([draft-ietf-httpbis-header-structure-10], Section 3.9):
	      "none", "same-origin", "same-site" [or "same-domain"], and
	      "cross-site".

           + "header" has a member named "max-age" whose value is not a
              positive integer ([draft-ietf-httpbis-header-structure-10],
	      Section 3.6).

           +  "header" has a member named "confirm"  whose value is not
              one of the following tokens
	      ([draft-ietf-httpbis-header-structure-10], Section 3.9):
	      "deliver", "top", and "block".

           + "header" has a member named "deliver-origins" whose value is
	      not a string ([draft-ietf-httpbis-header-structure-10],
	      Section 3.8).

----

Add on step 6 after substep 4 add following steps:

⇒

----

     4a. If "header" has a member named "confirm",
         set "token"'s "confirm" to the member's value.

     4b. If "header" has a member named  "deliver-origins", then:

     	 1. Let "string-value" to be  the member's value.

         2. Split "string-value" to list using comma as separator.

         3. Set "token"'s "deliver-origins" to the resulting
	    list.

     4c. If "header" has a member named "confirm", whose
         value is "top", then:

         1. If "confirm-top-origin" is null, skip next substeps.

         2. Let "top-token" be the result of retrieving
	    confirm-top-origin's token from the user agent's token
	    store, or "null" if no such token exists.

         3. If "top-token" is expired, clear the user agent's token
            store for  "confirm-top-origin", and set "top-token"
	    to "null".

         4. If "top-token" is "null", set "top-token" to the result
	    of generating an HTTP State Token for "confirm-top-origin",
	    as defined in Section 3.3.1.

         5. If  "top-token"'s "query-origins" list does not include
	    "response-origin" value, then:

            1.  Add "response-origin" to "top-token"'s "query-origins" list.

            2.  If the user agent has defined a "NotifyHostHTTPStateQuery()"
	        algorithm call it with "confirm-top-origin" and
		"response-origin" using "top-document"'s  environment
		settings object. 

/ Kari Hurtta