Subject: [GNAP] generic HTTP resource type

From: Jamey Sharp <[email-masked]>
Date: Mon, 26 Jul 2021 18:04:04 -0700

In today's meeting, I asked about applying GNAP as the HTTP 
authentication method for arbitrary HTTP resources, such as static 
files, in the same way that Basic and Digest auth can be used today. 
Justin asked me to share the question here.

Because the current draft includes RS-first AS discovery using the 
standard WWW-Authenticate response header, it might work for this use 
case as-is, but I think it can be improved.

First: Am I correct in thinking that two access tokens retrieved from 
the same AS, by the same end user, with the same "access" list, should 
be indistinguishable to the client? Specifically, if a client receives 
two `WWW-Authenticate: GNAP` headers with the same "as_url" and "access" 
parameters, can it reuse the access token it got for the first request 
on the second request, without consulting the AS again?

If so, I think the WWW-Authenticate "access" parameter is equivalent to 
the "realm" parameter defined in RFC7235 and used in RFC7617 Basic auth. 
(Perhaps for consistency with HTTP auth, it should in fact be called 
"realm" when used in that header? RFC7235 even uses "scope" terminilogy 
to describe it.)

Without additional provisions, which I'm pretty sure are not currently 
in GNAP, checking for matching realm/access parameters still requires an 
extra unauthenticated request any time the client needs to access a URL 
it hasn't visited before, even if the response turns out to indicate 
that an earlier access token can be reused.

RFC7617 defines somewhat magic rules for when a client can proactively 
provide Basic-scheme credentials to a URL where it hasn't previously 
seen a WWW-Authenticate header, in order to avoid a round-trip in the 
common case where the same credentials are accepted at similar URLs. In 
theory, GNAP could specify something similar to make RS-first AS 
discovery more efficient, but that level of magic seems dangerous to me.

The Digest auth scheme in RFC7616 instead allows the server (in this 
context, the RS) to give an explicit list of URL prefixes which accept 
the same credentials, in the WWW-Authenticate "domain" parameter. I 
think that's a closer fit for GNAP, but rather than making it a header 
parameter, I think it's best to fold it into the token's access rights.

I propose standardizing a definition of a "type" value for the rights 
request that describes HTTP access rights generically, rather than 
describing actions appropriate to a specific API. I think that would 
make GNAP usable anywhere that Basic or Digest auth are currently used. 
It might also enable a wide variety of RESTful APIs and HTTP-based 
standards to use GNAP without needing to define custom rights types.

Here is a concrete suggestion as a starting point for discussion:

"access": [{
   "type": "http",
   "locations": ["https://example.com/protected/"],
   "datatypes": ["text/html", "image/*"],
   "actions": ["GET", "PUT", "DELETE"]
}]

A resource request must match all fields to be allowed. If "datatypes" 
or "actions" are empty or absent, then all are permitted. (Permitting 
nothing is the same as not granting any rights at all.) The "locations" 
field is required to be present and non-empty though, and might work 
like the "domain" parameter in Digest: "The client can use this list to 
determine the set of URIs for which the same authentication information 
may be sent: any URI that has a URI in this list as a prefix [...] MAY 
be assumed to be in the same protection space."

This allows a client to request a limited set of methods or access to a 
limited portion of the protection space. It also allows the AS to inform 
the client of exactly which requests it may use the access token on, 
which may be different than what the client requested.

If I'm reading the current draft correctly, if a client sends an opaque 
resource reference like `"access": "WallyWorld"`, then the AS may choose 
to send back a non-opaque description of the rights granted by the 
returned access token, such as the above example for the hypothetical 
"http" rights type. Is that right?

I suppose the downside of the AS transforming an opaque reference into a 
full rights description is that the client can't indicate which rights 
types it understands. If a CMS supports a proprietary API for editing 
blog posts, but also supports WebDAV for file attachments, it might not 
be clear which rights type to use, yeah?

So here's an additional proposal: a client wishing to use this generic 
HTTP rights type should (must?) explicitly request it in the "access" 
rights request (and may also include the resource reference given in the 
"access" parameter of the WWW-Authenticate header, if any). It must 
specify the exact request URL in the "locations" field, and may also 
specify the method it tried to use in "actions". As usual, the AS may 
return a token granting rights to a wider range of locations or methods 
and is recommended to return the actual granted rights.

I hope that's reasonably clear and would love to discuss this further.

Jamey

---

From: Adrian Gropper <[email-masked]>
Date: Mon, 26 Jul 2021 22:31:37 -0400

Hi Jamey,

I don't understand what's being proposed. Mostly this is due to my
inexperience with HTTP APIs, but I'm trying to learn.

In cases of RS-first AS discovery, the end-user might or might not be the
RO. If the end-user is not the RO, then, from a data minimization
perspective, I do not want the client sharing any request information with
the RS. In other words, I do not assume that trusting the RS is the same as
trusting the AS. Therefore, an RS-first request should not require any
authentication. It should just return a link to the AS associated with that
resource.

A request to the RS by the RO should obviously require authentication.

A request to the RS that includes an authorization token is not subject to
authentication of the end-user.

What am I missing?

Adrian

On Mon, Jul 26, 2021 at 9:04 PM Jamey Sharp <[email-masked]> wrote:

> --
> TXAuth mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/txauth
>

---

From: Jamey Sharp <[email-masked]>
Date: Tue, 27 Jul 2021 11:25:23 -0700

Hi Adrian!

I agree with the general principles you're suggesting, but I don't 
believe my proposal reveals anything new to the RS. A resource server 
has to know what resource the end-user is requesting in order to serve 
that resource.

(The cryptography notions of "private information retrieval" and 
"oblivious RAM" would be an interesting challenge to apply to the web, 
but I'm sure they're well out of scope for this WG. You might enjoy 
reading the research literature on them though.)

My proposal does potentially reveal new information to the AS, and 
that's worth thinking about. There are two cases:

If it's desirable for the AS to reveal to the end-user the set of 
resources to which they've been granted rights—and I think it is—then 
that means the RS must have previously informed the AS about what the 
resource references which the RS uses actually refer to. Otherwise, a 
reference is an opaque string like "WallyWorld" that means nothing to 
either the end-user or the AS. (It certainly doesn't mean anything to 
me: I'm taking that from the original examples in the HTTP Basic auth 
spec, going back to at least 1996.)

Second, I've proposed that the client inform the AS of the specific 
resource and method which the end-user was trying to request. I'm not 
sure whether that's either necessary or desirable; I'm hoping other 
folks will chime in on my questions about whether the client needs to be 
able to indicate that it understands this generic "http" rights type.

I think it's worth noting that the choice of AS is made by the RO/RS, 
not by the end-user. So the safest assumption you can make when 
analyzing the privacy properties of GNAP is that the RS and AS may 
reveal any information they have to each other without the end-user's 
knowledge or consent. That doesn't change the above analysis though, 
since the only things the AS may learn are things the RS already knows.

Finally, here's context I think will help you on HTTP authentication:

An HTTP server can indicate that its response to a resource request 
might change if the client were authenticated. It does so by sending a 
"WWW-Authenticate" response header, containing a list of authentication 
schemes that the server will accept. In the context of GNAP, you can see 
that in "RS-first Method of AS Discovery", currently section 9.1.

If the client chooses to use one of those schemes, then it sends a new 
request containing an "Authorization" header. The contents of that 
header are mostly specified by the selected authentication scheme; for 
GNAP, that's covered in "Securing Requests from the Client Instance", 
"Presenting Access Tokens", which is currently section 7.2.

GNAP departs from older HTTP authentication schemes because in between 
the above two steps, the client goes off and talks to somebody else (the 
AS) for a while. But that side conversation is invisible to the RS, 
which just sees the client send one unauthenticated request and then a 
second request that contains an access token.

If the client already knows that the RS uses a specific GNAP AS, then 
the RS doesn't even get that first unauthenticated request; the first 
time it hears anything from the client is after the conversation with 
the AS is finished. But I'm interested in the case where the client has 
no prior knowledge about the RS, which means it works as I've described 
above, just like any other HTTP auth scheme.

The problem I'm trying to address is that after the first request, the 
HTTP auth spec doesn't say whether the client should use the same 
credentials when requesting resources at other URLs.

If the client does not send credentials on the next request, then it may 
get another "WWW-Authenticate" header back without getting the resource 
it actually wanted, which wastes time as it has to issue the request 
again even if it has a valid access token available.

But proactively authenticating to a different URL can leak information 
to a malicious party, since there may be many unaffiliated ROs at a 
single RS. For the Basic and Bearer schemes, the leaked information is 
full credentials and a complete security compromise. In other schemes, 
revealing that the end-user has credentials for some other resources is 
still a privacy violation, and in addition the leaked information may 
include identity details such as a username.

I briefly discussed in my previous mail how the Basic and Digest schemes 
approach this. Bearer seems to assume the client has prior knowledge 
about which resources a token gives it access to—which is reasonable 
given how OAuth 2.0 has been used, but GNAP's RS-first discovery opens 
up new use cases with new challenges. So I believe this needs to be 
addressed somehow, and I've proposed one possible way to do it.

I hope this clarified my proposal for you!
Jamey

---

From: Adrian Gropper <[email-masked]>
Date: Tue, 27 Jul 2021 18:54:31 -0400

Hi Jamey,

tldr: My perspective in the GNAP discussion is to maximize the power of the
RO and minimize the power of the RS by assuming that the RO can delegate to
_any_ AS they choose.

I'm grateful for your conversation because you are helping me tease out
which aspects of GNAP are essential for my (fairly common) use-case. My
use-case is securing a very complex (HL7-FHIR [1]) and regulated (US Gov
API Task Force [2]) API to health records. This work has been evolving for
a decade or more in the Kantara UMA WG [3] and the OpenID HEART WG [4] with
almost zero commercial uptake.

My goal is to use GNAP to replace as much of the OAuth, UMA, and OIDC
example implementation of delegated health records access. Links to our
repos are on the last slide of yesterday's presentation [5].

continuing inline....

> has to know what resource the end-user is requesting in order to serve
Yes.

> reading the research literature on them though.)
Sure. My concern is RO power and control, not security.

> that's worth thinking about. There are two cases:
No problem. I want to maximize the ROs agency by giving their delegated AS
as much power (privilege or capability) as the RO wants.

> spec, going back to at least 1996.)
Yes. Seems obvious.

> able to indicate that it understands this generic "http" rights type.
Yes. I have no problem with AS, as the RO's agent, being informed to the
extent the end-user is willing to share their attributes and their intent.

> since the only things the AS may learn are things the RS already knows.
Careful. "Separation of Concerns", avoiding censorship, and data
minimization dictate that the choice of AS should be made by the RO.  If an
RS is unwilling or unable to allow the RO their free choice of agent then I
would suggest that the RO should copy the resource to an RS that does allow
them to choose the AS.

As to the information transfer between AS and RS, it makes a big difference
if the end-ser is the RO or not.

> that in "RS-first Method of AS Discovery", currently section 9.1.
 OK.

> "Presenting Access Tokens", which is currently section 7.2.
OK.

> second request that contains an access token.
An unauthenticated request to the RS may return a pointer to the AS
controlling that resource if the RO wants to allow RS-first flows.
Otherwise, discovery of the AS and resources associated with the RO should
be out of scope for GNAP.

> above, just like any other HTTP auth scheme.
I think we agree, as above.

> credentials when requesting resources at other URLs.
This is above my pay grade.

> again even if it has a valid access token available.
In general, "wasting time" is not my concern. I'm on the lookout for giving
the RO maximum agency over the RS and if that's seen as a cost, so be it.

> include identity details such as a username.
I'm not sure of this. In general, end-user credentials should not be the
concern of the RS. For the RS as (GDPR) "processor", there are two
possibilities:
(a) The RS has some prior understanding of the RO's identity and can
associate authentication credentials with that identity.
(b) The RS has no prior understanding of the RO identity and simply takes a
key or certificate on a Trust on First Use basis.

> addressed somehow, and I've proposed one possible way to do it.
I hope my answers above have helped. You may be raising a security issue
that does not imply any power shift between the RO and the RS. In cases
where the end-user is not the RO, the end-user has legitimate privacy
interests relative to both the RS and AS but I don't understand if your
proposal impacts this.

- Adrian

> I hope this clarified my proposal for you!

[1] https://www.hl7.org/fhir/
[2]
https://www.healthit.gov/sites/default/files/facas/SingleSourceofTruth-APITFRecommendations.pdf

[3] https://kantarainitiative.org/confluence/display/uma/Home
[4] https://openid.net/wg/heart/
[5]
https://datatracker.ietf.org/meeting/111/materials/slides-111-gnap-gnap-and-w3c-verifiable-credentials-api-01

- Adrian

---

From: Justin Richer <[email-masked]>
Date: Tue, 27 Jul 2021 19:24:44 -0400

Hi Jamey,

Thanks for this thorough writeup, this is a fascinating idea, and as an individual I think it has some merit and warrants discussion. Now the question is what to do with that idea, and I can think of a handful of immediate options, detailed below. There are probably others.

But first, a note: the “type” element serves an important namespace function. In particular, a general-purpose “type” value would want to be something that’s collision-resistant, like a URI. Which URI gets used here depends a lot on where this definition would go. The documentation that defines the “type” element also defines the structure and contents of the object that contains the “type” element, so the language about what goes in “locations”, “datatypes”, and “actions” would all be defined with the “type” value. Of course, it’s entirely up to an AS/RS to map a given “type” value to a given definition set, but that’s the nature of protecting general APIs with a common security protocol — we can’t dictate that people interpret things a particular way.

These are the options for this type definition I can think of right now:

1) Defined as an appendix in GNAP Core. We can also use it in some examples. It remains optional to interpret or support for a given AS/RS.
2) Defined in a separate GNAP document.
3) Defined by a different WG. Perhaps HTTP-API would want to look at this?
4) Defined on a webpage on the internet, without a standards body behind it. The URL would be the URL of the document.

All of these have equal functionality inside of GNAP because of the supremacy of the AS/RS in this decision. And even better, anything defined for this part of GNAP is immediately usable in OAuth 2 RAR as well.

I’d like to hear what people think about this proposal — is it a good one, is it worth writing down, and if so, where?

 — Justin

> On Jul 26, 2021, at 9:04 PM, Jamey Sharp <[email-masked]> wrote:
> 
> In today's meeting, I asked about applying GNAP as the HTTP authentication method for arbitrary HTTP resources, such as static files, in the same way that Basic and Digest auth can be used today. Justin asked me to share the question here.
> 
> Because the current draft includes RS-first AS discovery using the standard WWW-Authenticate response header, it might work for this use case as-is, but I think it can be improved.
> 
> First: Am I correct in thinking that two access tokens retrieved from the same AS, by the same end user, with the same "access" list, should be indistinguishable to the client? Specifically, if a client receives two `WWW-Authenticate: GNAP` headers with the same "as_url" and "access" parameters, can it reuse the access token it got for the first request on the second request, without consulting the AS again?
> 
> If so, I think the WWW-Authenticate "access" parameter is equivalent to the "realm" parameter defined in RFC7235 and used in RFC7617 Basic auth. (Perhaps for consistency with HTTP auth, it should in fact be called "realm" when used in that header? RFC7235 even uses "scope" terminilogy to describe it.)
> 
> Without additional provisions, which I'm pretty sure are not currently in GNAP, checking for matching realm/access parameters still requires an extra unauthenticated request any time the client needs to access a URL it hasn't visited before, even if the response turns out to indicate that an earlier access token can be reused.
> 
> RFC7617 defines somewhat magic rules for when a client can proactively provide Basic-scheme credentials to a URL where it hasn't previously seen a WWW-Authenticate header, in order to avoid a round-trip in the common case where the same credentials are accepted at similar URLs. In theory, GNAP could specify something similar to make RS-first AS discovery more efficient, but that level of magic seems dangerous to me.
> 
> The Digest auth scheme in RFC7616 instead allows the server (in this context, the RS) to give an explicit list of URL prefixes which accept the same credentials, in the WWW-Authenticate "domain" parameter. I think that's a closer fit for GNAP, but rather than making it a header parameter, I think it's best to fold it into the token's access rights.
> 
> I propose standardizing a definition of a "type" value for the rights request that describes HTTP access rights generically, rather than describing actions appropriate to a specific API. I think that would make GNAP usable anywhere that Basic or Digest auth are currently used. It might also enable a wide variety of RESTful APIs and HTTP-based standards to use GNAP without needing to define custom rights types.
> 
> A resource request must match all fields to be allowed. If "datatypes" or "actions" are empty or absent, then all are permitted. (Permitting nothing is the same as not granting any rights at all.) The "locations" field is required to be present and non-empty though, and might work like the "domain" parameter in Digest: "The client can use this list to determine the set of URIs for which the same authentication information may be sent: any URI that has a URI in this list as a prefix [...] MAY be assumed to be in the same protection space."
> 
> This allows a client to request a limited set of methods or access to a limited portion of the protection space. It also allows the AS to inform the client of exactly which requests it may use the access token on, which may be different than what the client requested.
> 
> If I'm reading the current draft correctly, if a client sends an opaque resource reference like `"access": "WallyWorld"`, then the AS may choose to send back a non-opaque description of the rights granted by the returned access token, such as the above example for the hypothetical "http" rights type. Is that right?
> 
> I suppose the downside of the AS transforming an opaque reference into a full rights description is that the client can't indicate which rights types it understands. If a CMS supports a proprietary API for editing blog posts, but also supports WebDAV for file attachments, it might not be clear which rights type to use, yeah?
> 
> So here's an additional proposal: a client wishing to use this generic HTTP rights type should (must?) explicitly request it in the "access" rights request (and may also include the resource reference given in the "access" parameter of the WWW-Authenticate header, if any). It must specify the exact request URL in the "locations" field, and may also specify the method it tried to use in "actions". As usual, the AS may return a token granting rights to a wider range of locations or methods and is recommended to return the actual granted rights.
>

---

From: Jamey Sharp <[email-masked]>
Date: Tue, 27 Jul 2021 18:06:15 -0700

On Tue, Jul 27, 2021 at 06:54:31PM -0400, Adrian Gropper wrote:
> Hi Jamey,
> I'm grateful for your conversation because you are helping me tease 
> out which aspects of GNAP are essential for my (fairly common) 
> use-case.

I'm glad it's helping! Just keep in mind that I read the GNAP draft for 
the first time yesterday. 🤣

I think I have a better understanding of your concern now. I was 
somewhat confused because if the resources in question are electronic 
health records, then the RO is the party that needs protection the most, 
while in the cases I usually think about, it's the end-user's privacy 
that is most at risk.

I don't believe anything I'm proposing affects your use case, because 
I'm only proposing a resource rights type and possibly some end-user 
behavior. As far as I can tell,

- GNAP's privacy and security promises should not depend on the 
   specifics of any rights type;

- your application wouldn't use this rights type and so would not be 
   affected regardless;

- and any protections which GNAP offers an RO should apply regardless of 
   the behavior of any end-user.

Jamey

---

From: Fabien Imbault <[email-masked]>
Date: Wed, 28 Jul 2021 06:29:15 +0200

Hi,

The proposal answers a real problem. As a consequence, I'd tend to think it
makes a good candidate in core, as chairs where looking for an appendix
related to use cases anyways.

For the details of what implementing that use case requires, any of the
possibilities mentioned by Justin seem fine to me, although it kind of
illustrates why I wasn't so fond of "type" in the first place (not in
principle, but what it should represent, i.e. a unique namespace).

Cheers
Fabien

Le mer. 28 juil. 2021 à 01:26, Justin Richer <[email-masked]> a écrit :

> Hi Jamey,
>
> Thanks for this thorough writeup, this is a fascinating idea, and as an
> individual I think it has some merit and warrants discussion. Now the
> question is what to do with that idea, and I can think of a handful of
> immediate options, detailed below. There are probably others.
>
> But first, a note: the “type” element serves an important namespace
> function. In particular, a general-purpose “type” value would want to be
> something that’s collision-resistant, like a URI. Which URI gets used here
> depends a lot on where this definition would go. The documentation that
> defines the “type” element also defines the structure and contents of the
> object that contains the “type” element, so the language about what goes in
> “locations”, “datatypes”, and “actions” would all be defined with the
> “type” value. Of course, it’s entirely up to an AS/RS to map a given “type”
> value to a given definition set, but that’s the nature of protecting
> general APIs with a common security protocol — we can’t dictate that people
> interpret things a particular way.
>
> 1) Defined as an appendix in GNAP Core. We can also use it in some
> examples. It remains optional to interpret or support for a given AS/RS.
> 4) Defined on a webpage on the internet, without a standards body behind
> it. The URL would be the URL of the document.
>
> All of these have equal functionality inside of GNAP because of the
> supremacy of the AS/RS in this decision. And even better, anything defined
> for this part of GNAP is immediately usable in OAuth 2 RAR as well.
>
> I’d like to hear what people think about this proposal — is it a good one,
> is it worth writing down, and if so, where?
>
>  — Justin
>
> authentication method for arbitrary HTTP resources, such as static files,
> in the same way that Basic and Digest auth can be used today. Justin asked
> me to share the question here.
> >
> standard WWW-Authenticate response header, it might work for this use case
> as-is, but I think it can be improved.
> >
> the same AS, by the same end user, with the same "access" list, should be
> indistinguishable to the client? Specifically, if a client receives two
> `WWW-Authenticate: GNAP` headers with the same "as_url" and "access"
> parameters, can it reuse the access token it got for the first request on
> the second request, without consulting the AS again?
> >
> "realm" when used in that header? RFC7235 even uses "scope" terminilogy to
> describe it.)
> >
> extra unauthenticated request any time the client needs to access a URL it
> hasn't visited before, even if the response turns out to indicate that an
> earlier access token can be reused.
> >
> provide Basic-scheme credentials to a URL where it hasn't previously seen a
> WWW-Authenticate header, in order to avoid a round-trip in the common case
> where the same credentials are accepted at similar URLs. In theory, GNAP
> could specify something similar to make RS-first AS discovery more
> efficient, but that level of magic seems dangerous to me.
> >
> context, the RS) to give an explicit list of URL prefixes which accept the
> same credentials, in the WWW-Authenticate "domain" parameter. I think
> that's a closer fit for GNAP, but rather than making it a header parameter,
> I think it's best to fold it into the token's access rights.
> >
> describing actions appropriate to a specific API. I think that would make
> GNAP usable anywhere that Basic or Digest auth are currently used. It might
> also enable a wide variety of RESTful APIs and HTTP-based standards to use
> GNAP without needing to define custom rights types.
> >
> field is required to be present and non-empty though, and might work like
> the "domain" parameter in Digest: "The client can use this list to
> determine the set of URIs for which the same authentication information may
> be sent: any URI that has a URI in this list as a prefix [...] MAY be
> assumed to be in the same protection space."
> >
> the client of exactly which requests it may use the access token on, which
> may be different than what the client requested.
> >
> resource reference like `"access": "WallyWorld"`, then the AS may choose to
> send back a non-opaque description of the rights granted by the returned
> access token, such as the above example for the hypothetical "http" rights
> type. Is that right?
> >
> types it understands. If a CMS supports a proprietary API for editing blog
> posts, but also supports WebDAV for file attachments, it might not be clear
> which rights type to use, yeah?
> >
> "access" parameter of the WWW-Authenticate header, if any). It must specify
> the exact request URL in the "locations" field, and may also specify the
> method it tried to use in "actions". As usual, the AS may return a token
> granting rights to a wider range of locations or methods and is recommended
> to return the actual granted rights.
> >