Subject: [OAUTH-WG] Comments on draft-richer-oauth-introspection-04

From: Thomas Broyer <[email-masked]>
Date: Tue, 22 Oct 2013 16:50:21 +0200

Hi all,

In a platform we're building, we have AS, clients and PRs all as distinct
parties managed/provided by distinct companies. There's a single AS though,
doing SSO through OpenID Connect (i.e. the AS in an OP).

I thus need a way for a PR to ask the AS whether the token presented by the
client is valid and grants access to the PR. I've thus briefly
evaluated draft-richer-oauth-introspection-04 which seemed to fulfill my
needs. Here are my comments:

First, I'm a bit disturbed about privacy and potential security issues
about the way this is done (disclaimer: I'm in no way a security expert).
This draft is really about "introspection", and not "validation" of a
token, and that might be the problem: it returns the information about a
token to whoever asks for it (provided it authenticates, and possibly only
if the token grants it access, but that would mean there's an association
in the AS between scopes and registered PRs, themselves identified by a
client_id); this is IMO disclosing too much information.
In case the PR is compromised, this information could be used to then reuse
the token with other PRs inferred by the token's granted scopes and gain
access to private information in a way that the End User didn't explicitly
approved (he authorized the Client to access several PRs, he didn't
authorize exchanges between PRs directly). This could be mitigated by *not*
using Bearer tokens (using some sort of 'proof token' instead, e.g. either
MAC or JWT), but there's no reason we couldn't have such a feature/endpoint
that could work securely with Bearer tokens (I don't want to put too much
burden on client and PR implementers).
Before I saw this draft, my idea was to have an endpoint at the AS where
the PR would send the token received by the Client *and* the scopes
corresponding to the request being done (and the "sub" of the End-User if
it was part of the request; in our case, we use it as a global identifier
shared by all parties involved; we might change to per-party IDs and then
use that endpoint to "translate" the ID as known by the Client to the ID as
known by the PR, but this is another story), and the AS would answer with
just a "yes" (HTTP/1.1 204 No Content) or "no" (400 Bad Request with a JSON
payload similar to the Error Response from Section 5.2 or RFC 6749, with
the same error codes as defined by RFC 6750; that way the PR can just
"translate" the error response to a WWW-Authenticate: Bearer response
header). That way, the PR does not know where else the token is "valid",
i.e. what it could do with it.

Second thing, the draft talks about a "resource_id" but doesn't say how it
could be used, and whether it'll be used at all by the server, what impact
it could have on the response, etc. Could that resource_id replace the
"list of scopes" from my implementation idea? The PR would need to know the
list of scopes to return the correct WWW-Authenticate header anyway
(assuming a Bearer token is used here), so I'm not sure it's really better.
And the resource_id is optional, so what would happen if it's not provided?
you'd have *more* information returned? I understand that this is just a
framework and each server would have its own rules, but you're then either
saying too much or too few.

Thanks in advance for any guidance about how to achieve my goal. Should I
go with introspection? (maybe I misunderstood something, or saw a threats
where there isn't) or should I use something else? Does my initial idea
make sense? Should I go with it?

-- 
Thomas Broyer
/tɔ.ma.bʁwa.je/ <http://xn--nna.ma.xn--bwa-xxb.je/>

---

From: Eve Maler <[email-masked]>
Date: Wed, 23 Oct 2013 11:37:01 -0700

Hi Thomas-- You may want to take a look at UMA, which leverages both OAuth and Justin's token introspection draft. Token introspection on its own is a "shallow" kind of loose coupling between authorization servers and resource servers. If these are operated by different organizations, as appears to be the case for you, then "deep" loose coupling may be need to answer questions about how the AS and RS onboard and establish trust with each other. UMA provides one set of answers for how to do this. You can find more info at http://tinyurl.com/umawg.

	Eve

On 22 Oct 2013, at 7:50 AM, Thomas Broyer <[email-masked]> wrote:

> Hi all,
> 
> In a platform we're building, we have AS, clients and PRs all as distinct parties managed/provided by distinct companies. There's a single AS though, doing SSO through OpenID Connect (i.e. the AS in an OP).
> 
> I thus need a way for a PR to ask the AS whether the token presented by the client is valid and grants access to the PR. I've thus briefly evaluated draft-richer-oauth-introspection-04 which seemed to fulfill my needs. Here are my comments:
> 
> First, I'm a bit disturbed about privacy and potential security issues about the way this is done (disclaimer: I'm in no way a security expert). This draft is really about "introspection", and not "validation" of a token, and that might be the problem: it returns the information about a token to whoever asks for it (provided it authenticates, and possibly only if the token grants it access, but that would mean there's an association in the AS between scopes and registered PRs, themselves identified by a client_id); this is IMO disclosing too much information.
> In case the PR is compromised, this information could be used to then reuse the token with other PRs inferred by the token's granted scopes and gain access to private information in a way that the End User didn't explicitly approved (he authorized the Client to access several PRs, he didn't authorize exchanges between PRs directly). This could be mitigated by *not* using Bearer tokens (using some sort of 'proof token' instead, e.g. either MAC or JWT), but there's no reason we couldn't have such a feature/endpoint that could work securely with Bearer tokens (I don't want to put too much burden on client and PR implementers).
> Before I saw this draft, my idea was to have an endpoint at the AS where the PR would send the token received by the Client *and* the scopes corresponding to the request being done (and the "sub" of the End-User if it was part of the request; in our case, we use it as a global identifier shared by all parties involved; we might change to per-party IDs and then use that endpoint to "translate" the ID as known by the Client to the ID as known by the PR, but this is another story), and the AS would answer with just a "yes" (HTTP/1.1 204 No Content) or "no" (400 Bad Request with a JSON payload similar to the Error Response from Section 5.2 or RFC 6749, with the same error codes as defined by RFC 6750; that way the PR can just "translate" the error response to a WWW-Authenticate: Bearer response header). That way, the PR does not know where else the token is "valid", i.e. what it could do with it.
> 
> Second thing, the draft talks about a "resource_id" but doesn't say how it could be used, and whether it'll be used at all by the server, what impact it could have on the response, etc. Could that resource_id replace the "list of scopes" from my implementation idea? The PR would need to know the list of scopes to return the correct WWW-Authenticate header anyway (assuming a Bearer token is used here), so I'm not sure it's really better. And the resource_id is optional, so what would happen if it's not provided? you'd have *more* information returned? I understand that this is just a framework and each server would have its own rules, but you're then either saying too much or too few.
> 
> Thanks in advance for any guidance about how to achieve my goal. Should I go with introspection? (maybe I misunderstood something, or saw a threats where there isn't) or should I use something else? Does my initial idea make sense? Should I go with it?
> 
> -- 
> Thomas Broyer
> /tɔ.ma.bʁwa.je/
> _______________________________________________
> OAuth mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/oauth

Eve Maler                                  http://www.xmlgrrl.com/blog
+1 425 345 6756                         http://www.twitter.com/xmlgrrl

---

From: "Richer, Justin P." <[email-masked]>
Date: Wed, 23 Oct 2013 19:22:37 +0000

Hi Thomas,

You're right in that the introspection process is about getting meta data about a particular token by making an authenticated call. It does reveal a lot of information about the token -- because that's exactly the point of the protocol. :)

If the PR is compromised, then the attacker would be able to do anything the PR can do, including reusing any tokens handed to the PR (assuming they're bearer tokens). This is true without doing introspection at all, since you can just steal and start broadcasting the token. Also, if the PR is compromised, all the data protected at that PR is also compromised, so you've got other problems too.

The "resource_id" parameter is meant to be a service-specific hint that the PR can hand to the AS to give context to the transaction. You could easily use this field to pass along the list of scopes that you mention below. You can have your AS return no information other than the "valid" field in the response and leave out the scopes, subject, client id, and everything else. All those fields are optional. However, in practice we've found it very helpful to reveal to the PR which scopes and audiences that a token was issued for so that the PR can use that information to make authorization decisions. But if all you're after is answering the question "is this token valid" and you don't want any other information, your AS is fully allowed to do answer just that question.

As Eve pointed out in the other email, the introspection draft allows for a light "loose" binding between the AS and PR, but there's an assumption that the relationship was set up somewhere. UMA adds the possibilities of a deeper and more dynamic binding between PR and AS before introspection takes place. (In fact, the introspection draft was pretty much lifted out of UMA originally.) UMA also has a concept of permission sets that are more flexible and descriptive than scopes alone are, but those are added to the top of the base introspection response.

 -- Justin

On Oct 22, 2013, at 7:50 AM, Thomas Broyer <[email-masked]<mailto:[email-masked]>> wrote:

Hi all,

--
Thomas Broyer
/tɔ.ma.bʁwa.je/<http://xn--nna.ma.xn--bwa-xxb.je/>

---

From: Thomas Broyer <[email-masked]>
Date: Thu, 24 Oct 2013 02:27:33 +0200

On Wed, Oct 23, 2013 at 9:22 PM, Richer, Justin P. <[email-masked]>wrote:

>  Hi Thomas,
>
>  You're right in that the introspection process is about getting meta
> data about a particular token by making an authenticated call. It does
> reveal a lot of information about the token -- because that's exactly the
> point of the protocol. :)
>
>  If the PR is compromised, then the attacker would be able to do anything
> the PR can do, including reusing any tokens handed to the PR (assuming
> they're bearer tokens).
>

Yes, this is the problem with bearer tokens. Is there any spec for 'proof
tokens' besides http-mac?
As a mean of mitigating the issue, I was thinking about delivering a
refresh_token and asking Clients to generate (ask the AS) different access
tokens for each PR (or "resource set"). That would of course solve the
issue with introspection giving too much information (to my taste), but
puts burden on Client implementors, with no guarantee that they'll actually
do it. AFAICT, only a 'proof token' would really solve the issue; it's in
our backlog.

> This is true without doing introspection at all, since you can just steal
> and start broadcasting the token.
>

But then the AS could revoke the access token when it detects a high rate
of validation/introspection requests from many different PRs, particularly
many such requests in error!
Giving the compromised victim the list of scopes for the token would
severely limits the number of errors and it would be much harder to detect
such compromised entities.

Also, if the PR is compromised, all the data protected at that PR is also
> compromised, so you've got other problems too.
>

That's a problem between the PR and the ROs then, unrelated to the AS or
even Clients.
It becomes a problem with the whole system when compromising one entity
(other than the AS) gives access to personal data in others.

>  The "resource_id" parameter is meant to be a service-specific hint that
> the PR can hand to the AS to give context to the transaction. You could
> easily use this field to pass along the list of scopes that you mention
> below.
>

I had just skimmed through resource-reg and didn't remember the "resource
set" concept. Now that I re-read it, I better understand what that
resource_id can be.

> You can have your AS return no information other than the "valid" field in
> the response and leave out the scopes, subject, client id, and everything
> else. All those fields are optional. However, in practice we've found it
> very helpful to reveal to the PR which scopes and audiences that a token
> was issued for so that the PR can use that information to make
> authorization decisions.
>

But aren't authorization decisions the responsibility of the AS?
If the PR sent the scopes (or resource_id, but that would closely couple
the protocol with resource-reg, which I don't think is desirable) to the
AS, then the PR could authorize access based only on a yes/no response (and
the "no" response would give information about the "why", to be sent
directly to the Client)

> But if all you're after is answering the question "is this token valid"
> and you don't want any other information, your AS is fully allowed to do
> answer just that question.
>

As I said, I do need "more information", or rather, a more "contextual"
information.

I think I'll just go with my custom protocol for now. Thanks for your
answer.

---

From: Thomas Broyer <[email-masked]>
Date: Thu, 24 Oct 2013 02:35:49 +0200

On Wed, Oct 23, 2013 at 8:37 PM, Eve Maler <[email-masked]> wrote:

> Hi Thomas-- You may want to take a look at UMA, which leverages both OAuth
> and Justin's token introspection draft. Token introspection on its own is a
> "shallow" kind of loose coupling between authorization servers and resource
> servers. If these are operated by different organizations, as appears to be
> the case for you, then "deep" loose coupling may be need to answer
> questions about how the AS and RS onboard and establish trust with each
> other. UMA provides one set of answers for how to do this. You can find
> more info at http://tinyurl.com/umawg.
>

There are interesting concepts in UMA. In our case though, AS, PR and
Clients are all operated by different organizations, but we do have "strong
coupling" between them (a central registry of PRs and Clients). Thanks
anyway.

---

From: Torsten Lodderstedt <[email-masked]>
Date: Thu, 24 Oct 2013 07:50:07 +0200

Hi Thomas,

we generate access tokens per resource server in order to mitigate this and other risks. You must issue those tokens to different audiences (resource server id) and the resource servers must validate if the token is issued for its particular audience. Otherwise a compromised resource server can still abuse the tokens. 

Talking about burden: You need to compare the effort needed to obtain different access tokens to the effort needed to implement proof of possession.

I recommend you to take a look into the OAuth threat model for a discussion of this threat ( http://tools.ietf.org/html/rfc6819#section-4.6.4).

regards,
Torsten.

Thomas Broyer <[email-masked]> schrieb:
>------------------------------------------------------------------------
>

---

From: "Richer, Justin P." <[email-masked]>
Date: Thu, 24 Oct 2013 14:36:58 +0000

On Oct 23, 2013, at 5:27 PM, Thomas Broyer <[email-masked]<mailto:[email-masked]>>
 wrote:

On Wed, Oct 23, 2013 at 9:22 PM, Richer, Justin P. <[email-masked]<mailto:[email-masked]>> wrote:
Hi Thomas,

If the PR is compromised, then the attacker would be able to do anything the PR can do, including reusing any tokens handed to the PR (assuming they're bearer tokens).

Yes, this is the problem with bearer tokens. Is there any spec for 'proof tokens' besides http-mac?
As a mean of mitigating the issue, I was thinking about delivering a refresh_token and asking Clients to generate (ask the AS) different access tokens for each PR (or "resource set"). That would of course solve the issue with introspection giving too much information (to my taste), but puts burden on Client implementors, with no guarantee that they'll actually do it. AFAICT, only a 'proof token' would really solve the issue; it's in our backlog.

There are a couple of proposed holder-of-key type tokens proposed but none have been accepted by the working group yet. We'd be glad to have more input into it.

This is true without doing introspection at all, since you can just steal and start broadcasting the token.

But then the AS could revoke the access token when it detects a high rate of validation/introspection requests from many different PRs, particularly many such requests in error!
Giving the compromised victim the list of scopes for the token would severely limits the number of errors and it would be much harder to detect such compromised entities.

It depends on how closely the scopes map to specific resources and how much the attacker knows about that environment. It sounds like your usage of OAuth places a significant amount of information into the scope which would leak that information. In such an environment, having the PR supply the scope in the request somehow instead of the AS returning the scope in the response might help. However, what would prevent a compromised PR from fishing for the scopes of a given token, assuming they know the overall set of scopes the token could be good for?

In our own implementation, the PR's are tied to a specific scope set and the AS knows which scopes a particular PR is meant to use. With this information, by local policy we can actually limit which tokens the PR is allowed to introspect.

Also, if the PR is compromised, all the data protected at that PR is also compromised, so you've got other problems too.

That's a problem between the PR and the ROs then, unrelated to the AS or even Clients.
It becomes a problem with the whole system when compromising one entity (other than the AS) gives access to personal data in others.

Yes, and there are other means for mitigating these risks, as Torsten pointed out, and you'll really want to be doing these anyway in your system.

The "resource_id" parameter is meant to be a service-specific hint that the PR can hand to the AS to give context to the transaction. You could easily use this field to pass along the list of scopes that you mention below.

I had just skimmed through resource-reg and didn't remember the "resource set" concept. Now that I re-read it, I better understand what that resource_id can be.

The resource_id isn't necessarily a resource set identifier, though it can be. It was really meant as a way for the PR to say "here's the context of the token being used". The other piece of context is the client identifier that's used as part of the client authenticating the call to the introspection endpoint. These, coupled with the token itself, can give a very complete view of the request..

You can have your AS return no information other than the "valid" field in the response and leave out the scopes, subject, client id, and everything else. All those fields are optional. However, in practice we've found it very helpful to reveal to the PR which scopes and audiences that a token was issued for so that the PR can use that information to make authorization decisions.

Partially, but it's the PR that makes the ultimate decision of whether or not to let the request proceed. The AS can only help provide information for the PR to make that final decision.

If the PR sent the scopes (or resource_id, but that would closely couple the protocol with resource-reg, which I don't think is desirable) to the AS, then the PR could authorize access based only on a yes/no response (and the "no" response would give information about the "why", to be sent directly to the Client)

Again, I want to point out that resource_id isn't necessarily meant to be coupled with the resource registration protocol (though it can nicely overlap).

An interesting idea to send back the reason why from the AS, I'm assuming this would be one of the error codes defined by RFC6750? You'd want to be careful about exposing too much information in the error though.

But if all you're after is answering the question "is this token valid" and you don't want any other information, your AS is fully allowed to do answer just that question.

As I said, I do need "more information", or rather, a more "contextual" information.

And you can add that contextual information, like UMA does, as part of the JSON structure that's returned.

I think I'll just go with my custom protocol for now. Thanks for your answer.

I would encourage you to rethink that stance, especially if the introspection protocol can be changed to accommodate your use case without breaking the existing use case that people are using it for. As it's a draft standard I'm fine with us tweaking things. Additionally, starting with introspection as it is would leave the door open to you interoperating with other systems in the future and even moving to a more comprehensive protocol like UMA.

 -- Justin

---

From: Thomas Broyer <[email-masked]>
Date: Fri, 25 Oct 2013 11:19:50 +0200

On Thu, Oct 24, 2013 at 7:50 AM, Torsten Lodderstedt <
[email-masked]> wrote:

> Hi Thomas,
>
> we generate access tokens per resource server in order to mitigate this
> and other risks. You must issue those tokens to different audiences
> (resource server id) and the resource servers must validate if the token is
> issued for its particular audience. Otherwise a compromised resource server
> can still abuse the tokens.
>
> Talking about burden: You need to compare the effort needed to obtain
> different access tokens to the effort needed to implement proof of
> possession.
>

On our backlog is also support for "service accounts" (to use Google's
terminology), so clients will likely need to do some crypto-related work.
Asking them to do it for each and every request to sign the access token
might not be that much of a problem (if they have the right tools;
google-oauth-java-client for instance does a great job making all of this
easier, and google-api-java-client adds service accounts support with a
just-as-easy-to-use API:
https://code.google.com/p/google-api-java-client/wiki/OAuth2#Service_Accounts;
same for PHP, Python, etc.)
That said, I'm rather new to crypto too, so I might be oversimplifying
things…
I'll check with the project manager and project owner which approach we'd
use (we could also support both…)

I recommend you to take a look into the OAuth threat model for a discussion
> of this threat ( http://tools.ietf.org/html/rfc6819#section-4.6.4).
>

Thanks for the pointer. I had already read that RFC but somehow forgot
about some details, and failed to check it back for that particular problem.

---

From: Thomas Broyer <[email-masked]>
Date: Fri, 25 Oct 2013 11:59:44 +0200

On Thu, Oct 24, 2013 at 4:36 PM, Richer, Justin P. <[email-masked]>wrote:

>  On Oct 23, 2013, at 5:27 PM, Thomas Broyer <[email-masked]>
>  wrote:
>
>>  If the PR is compromised, then the attacker would be able to do
>> anything the PR can do, including reusing any tokens handed to the PR
>> (assuming they're bearer tokens).
>>
>
>  There are a couple of proposed holder-of-key type tokens proposed but
> none have been accepted by the working group yet. We'd be glad to have more
> input into it.
>

Any pointer?
I've only see http-mac, but I'm surprised to find nothing similar to
jwt-bearer (i.e. a signed JWT whose claim set includes the access token;
the resource server could then send the JWT to the AS which would verify
the signature and validity of the JWT wrt "exp", "iat", "nbf" and "jti"
fields, and embedded access token –could be the "sub"?–; the JWT couldn't
be used with other resource servers as its "aud" field wouldn't match)
http-mac looks much more complex, and probably with very good reasons, but
my gut feeling is that if something like jwt-bearer, which looks simpler,
is deemed secure enough as grant-type or client-assertion-type, why would
it be different for accessing protected resources?
(disclaimer: remember, I'm not a security guy)

>  But then the AS could revoke the access token when it detects a high
> rate of validation/introspection requests from many different PRs,
> particularly many such requests in error!
>  It depends on how closely the scopes map to specific resources and how
> much the attacker knows about that environment. It sounds like your usage
> of OAuth places a significant amount of information into the scope which
> would leak that information.
>

It's not yet really clear for us, but it'll probably be the case yes.

> In such an environment, having the PR supply the scope in the request
> somehow instead of the AS returning the scope in the response might help.
> However, what would prevent a compromised PR from fishing for the scopes of
> a given token, assuming they know the overall set of scopes the token could
> be good for?
>

Ah yes, fair enough…
A resource_id would be a good abstraction then, as it would be "private",
only known to the resource server and authorization server, making it
harder to fish for other possible uses of the token.

> In our own implementation, the PR's are tied to a specific scope set and
> the AS knows which scopes a particular PR is meant to use. With this
> information, by local policy we can actually limit which tokens the PR is
> allowed to introspect.
>

Are you also returning different values for the "scope" based on which PR
makes the request? (filtering them to only include scopes the PR is tied to)
(I'm a web guy, and "profiling" the response depending on who accesses it
goes against my REST background and is not natural to me, but that would
work I guess)

An interesting idea to send back the reason why from the AS, I'm assuming
> this would be one of the error codes defined by RFC6750?
>

Yes.

When using Token Introspection, that wouldn't be really needed though: a
400 response from the AS maps to an invalid_request, and {"active":false}
to an invalid_token, and the PR is in charge of determining whether to
return an insufficient_scope error.

> the JSON structure that's returned.

By "more contextual", I meant that the "yes/no" response is more "precise"
than just "active/inactive": it's a yes/no for a particular request.
The only difference with Token Introspection is about disclosing the scopes
to the PR or not.

> I would encourage you to rethink that stance, especially if the
> introspection protocol can be changed to accommodate your use case without
> breaking the existing use case that people are using it for. As it's a
> draft standard I'm fine with us tweaking things. Additionally, starting
> with introspection as it is would leave the door open to you interoperating
> with other systems in the future and even moving to a more comprehensive
> protocol like UMA.
>

I'll try out Token Introspection and see if it can match. I actually
already know it will IFF I trade "wide scoped" bearer tokens to either "one
bearer token per resource server" (like Torsten said) or "proof tokens".

---

From: Torsten Lodderstedt <[email-masked]>
Date: Fri, 25 Oct 2013 19:28:15 +0200

Am 25.10.2013 11:19, schrieb Thomas Broyer:
>
>
>
> On Thu, Oct 24, 2013 at 7:50 AM, Torsten Lodderstedt 
> <[email-masked] <mailto:[email-masked]>> wrote:
>
>     Hi Thomas,
>
>     we generate access tokens per resource server in order to mitigate
>     this and other risks. You must issue those tokens to different
>     audiences (resource server id) and the resource servers must
>     validate if the token is issued for its particular audience.
>     Otherwise a compromised resource server can still abuse the tokens.
>
>     Talking about burden: You need to compare the effort needed to
>     obtain different access tokens to the effort needed to implement
>     proof of possession.
>
>
> terminology), so clients will likely need to do some crypto-related 
> work. Asking them to do it for each and every request to sign the 
> access token might not be that

I assume you mean signing the request or at least some request data. 
Just signing the access token won't help.

> much of a problem (if they have the right tools; 
> google-oauth-java-client for instance does a great job making all of 
> this easier, and google-api-java-client adds service accounts support 
> with a just-as-easy-to-use API: 
> I'll check with the project manager and project owner which approach 
> we'd use (we could also support both…)
>
>     I recommend you to take a look into the OAuth threat model for a
>     discussion of this threat (
>     http://tools.ietf.org/html/rfc6819#section-4.6.4).
>
>

---

From: Thomas Broyer <[email-masked]>
Date: Fri, 25 Oct 2013 22:01:19 +0200

Le 25 oct. 2013 19:28, "Torsten Lodderstedt" <[email-masked]> a
might not be that
>
>
> I assume you mean signing the request or at least some request data. Just
signing the access token won't help.

I meant signing the access token + PR identifier/URI + some timestamp, at a
minimum.
I explained it better in my answer to Justin; something like jwt-bearer
applied to access tokens.

things…
>>> I recommend you to take a look into the OAuth threat model for a
discussion of this threat ( http://tools.ietf.org/html/rfc6819#section-4.6.4
).

---

From: "Richer, Justin P." <[email-masked]>
Date: Sat, 26 Oct 2013 16:03:28 +0000

>> On our backlog is also support for "service accounts" (to use Google's terminology), so clients will likely need to do some crypto-related work. Asking them to do it for each and every request to sign the access token might not be that
>
>
> I assume you mean signing the request or at least some request data. Just signing the access token won't help.

I meant signing the access token + PR identifier/URI + some timestamp, at a minimum.
I explained it better in my answer to Justin; something like jwt-bearer applied to access tokens.

I suggested to the group that we try something like this a while ago but it didn't get traction at the time. I never really wrote down the whole process I had in mind, so here's a quick overview:

First, the client gets a token from the auth server using any normal oauth mechanism (or any abnormal mechanism for that matter), and the response looks something like this:

{
  token_type: signed,
  access_token: <public token value>
  token_key: <private token secret used for signing, maybe as a JWK?>
  alg: <JWS algorithm to use for signing requests to the RS, I'll use HS256 for my example below but we could probably tweak this to use asymmetric keys too>
  expires_in: 3600
  …
}

Next, the client figures out the request it wants to make:

GET http://foo.bar/baz?quxx=bob&woz=whynot HTTP/1.1
Accept: application/json
X-Other-Header: SomeHeaderValue

Treating this request as a structure, we've got a verb, a url (with scheme, host, path, parameters), and some headers. We want the client to be able to sign some subset of this with the request, so let's say this client wants to sign the verb, scheme+host+port+path, the parameters, and one of the headers. So the way I see it we've got a couple options. First is to repeat all the items to be signed within a JSON structure and use JWS. This is messy and it ignores some of the best stuff about using HTTP/REST these days. Second, we can combine, normalize, and hash the signable items. With this approach and some sufficient handwavium (because I don't really want to get into specifics of serialization and normalization here), we get something like this for a base string:

GET
http://foo.bar/baz
quux=bob
woz=whynot
X-Other-Header=SomeHeaderValue

which we can hash using a defined algorithm of the same bit size as our signing algorithm. So say we're using HMAC 256, we get a base64url encoded hash blob like this fake one I just made up: HJ23dfjoa32fasd23lajkds

So great, we've got a hash and we've got a set of data that was hashed. So far we're in the same boat that got a lot of OAuth 1.0 implementations in trouble, due to oddities about normalization. So let's take this a step further and tell the server what we're hashing in our signed content, but by repeating just the *keys* to this content and not the content itself, since the keys will be shorter in many cases and less redundant:

signed: [ "verb", "scheme+host+path", {"query": ["quux", "woz"]}, {"header": ["X-Other-Header"]} ]

Note that this uses arrays, which is important because arrays preserve order in JSON. Now we have a pretty programmatic way of telling the server which bits we care about signing and what order we put them in, with normalizing those aspects. This makes us robust against stuff getting reordered and new headers or query parameters being inserted (which often happens with various web frameworks). Of course, after verifying a signature, an app would want to make sure that important parameters were covered by that signature, but that's up to the app. Any decent library would make the list available to the app easily enough for a quick check.

OK, so now we've got our hash and our note on what we hashed. Let's put those into a JSON object:

{
hash: HJ23dfjoa32fasd23lajkds,
signed: [ "verb", "scheme+host+path", {"query": ["quux", "woz"]}, {"header": ["X-Other-Header"]} ],
token_id: <public token value>
}

And we'll make our normal JWS header, use the above JSON object as the bode, and sign it with JWS using the secret/key that we got up in the token response:

eyheaderstufffooo.eybodystuffbaaar.signatureblob

[Side note: Maybe if you really wanted to you could also sign it using the client secret and include the client id in the signed data, like OAuth 1.0 does.]

And *now* we can send this over using any method comparable to those defined in RFC6750, since it's all a single, self-contained value.

GET http://foo.bar/baz?quxx=bob&woz=whynot HTTP/1.1
Accept: application/json
X-Other-Header: SomeHeaderValue
Authorization: SignedOAuth eyheaderstufffooo.eybodystuffbaaar.signatureblob

or:

GET http://foo.bar/baz?quxx=bob&woz=whynot&signed_access_token=eyheaderstufffooo.eybodystuffbaaar.signatureblob HTTP/1.1
Accept: application/json
X-Other-Header: SomeHeaderValue

Note that in the both cases, the newly introduced header and query parameter are automatically excused from the signature calculation because they don't show up in the signed lists.

OK, so the RS gets this request, and what does it do? Easy:

First, check the signature on the token. This is self-contained and is a quick JWS operation. [Side note: how does the RS get the private signing/checking key from the AS? I don't care, and neither should you, because it's orthogonal to this part of the spec family.]

Second, the RS parses the body and reads the "signed" member. This "signed" member tells the RS which parts of the original request it needs to check. Even with extra parameters and bits you end up pulling only the parts that you need. And you know what order to smash them together, too, without doing any kind of sorting!

Third, the RS calculates the hash of this string and compares it, literally, to the "hash" parameter that was sent.

Fourth, the RS makes sure any "important" parameters and headers and other bits are actually covered by the hash.

Anyway, I think this method is worlds simpler than what we've got in http-mac right now and it goes back to solving a number of the use cases that have been brought up, including my own of simply protecting an HTTP message apart from tokens.

 -- Justin

---

From: Thomas Broyer <[email-masked]>
Date: Sat, 26 Oct 2013 22:34:24 +0200

On Sat, Oct 26, 2013 at 6:03 PM, Richer, Justin P. <[email-masked]>wrote:

>   >> On our backlog is also support for "service accounts" (to use
> Google's terminology), so clients will likely need to do some
> crypto-related work. Asking them to do it for each and every request to
> sign the access token might not be that
> >
> >
>  I suggested to the group that we try something like this a while ago but
> it didn't get traction at the time. I never really wrote down the whole
> process I had in mind, so here's a quick overview:
>
>
>  First, the client gets a token from the auth server using any normal
> oauth mechanism (or any abnormal mechanism for that matter), and the
> response looks something like this:
>
>  {
>   token_type: signed,
>   alg: <JWS algorithm to use for signing requests to the RS, I'll use
> HS256 for my example below but we could probably tweak this to use
> asymmetric keys too>
>   expires_in: 3600
>   …
> }
>
>
>  Treating this request as a structure, we've got a verb, a url (with
> scheme, host, path, parameters), and some headers. We want the client to be
> able to sign some subset of this with the request, so let's say this client
> wants to sign the verb, scheme+host+port+path, the parameters, and one of
> the headers. So the way I see it we've got a couple options. First is to
> repeat all the items to be signed within a JSON structure and use JWS. This
> is messy and it ignores some of the best stuff about using HTTP/REST these
> days. Second, we can combine, normalize, and hash the signable items. With
> this approach and some sufficient handwavium (because I don't really want
> to get into specifics of serialization and normalization here), we get
> something like this for a base string:
>
>  GET
> http://foo.bar/baz
> quux=bob
> woz=whynot
>  which we can hash using a defined algorithm of the same bit size as our
> signing algorithm. So say we're using HMAC 256, we get a base64url encoded
> hash blob like this fake one I just made up: HJ23dfjoa32fasd23lajkds
>
>  So great, we've got a hash and we've got a set of data that was hashed.
> So far we're in the same boat that got a lot of OAuth 1.0 implementations
> in trouble, due to oddities about normalization. So let's take this a step
> further and tell the server what we're hashing in our signed content, but
> by repeating just the *keys* to this content and not the content itself,
> since the keys will be shorter in many cases and less redundant:
>
>  Note that this uses arrays, which is important because arrays preserve
> order in JSON. Now we have a pretty programmatic way of telling the server
> which bits we care about signing and what order we put them in, with
> normalizing those aspects. This makes us robust against stuff getting
> reordered and new headers or query parameters being inserted (which often
> happens with various web frameworks). Of course, after verifying a
> signature, an app would want to make sure that important parameters were
> covered by that signature, but that's up to the app. Any decent library
> would make the list available to the app easily enough for a quick check.
>
>  And we'll make our normal JWS header, use the above JSON object as the
> bode, and sign it with JWS using the secret/key that we got up in the token
> response:
>
>  [Side note: Maybe if you really wanted to you could also sign it using
> the client secret and include the client id in the signed data, like OAuth
> 1.0 does.]
>
>  And *now* we can send this over using any method comparable to those
> defined in RFC6750, since it's all a single, self-contained value.
>
>  Authorization:
> SignedOAuth eyheaderstufffooo.eybodystuffbaaar.signatureblob
>
>
>  or:
>
>   GET http://foo.bar/baz?quxx=bob&woz=whynot&signed_access_token=
> eyheaderstufffooo.eybodystuffbaaar.signatureblob HTTP/1.1
> Accept: application/json
>  Note that in the both cases, the newly introduced header and query
> parameter are automatically excused from the signature calculation because
> they don't show up in the signed lists.
>
>
>  First, check the signature on the token. This is self-contained and is a
> quick JWS operation. [Side note: how does the RS get the private
> signing/checking key from the AS? I don't care, and neither should you,
> because it's orthogonal to this part of the spec family.]
>
>  Second, the RS parses the body and reads the "signed" member. This
> "signed" member tells the RS which parts of the original request it needs
> to check. Even with extra parameters and bits you end up pulling only the
> parts that you need. And you know what order to smash them together, too,
> without doing any kind of sorting!
>
>  Third, the RS calculates the hash of this string and compares it,
> literally, to the "hash" parameter that was sent.
>
>  Fourth, the RS makes sure any "important" parameters and headers and
> other bits are actually covered by the hash.
>
>
>
>  Anyway, I think this method is worlds simpler than what we've got in
> http-mac right now and it goes back to solving a number of the use cases
> that have been brought up, including my own of simply protecting an HTTP
> message apart from tokens.
>
>
Couldn't we have something middle-ground between bearer tokens "in the
clear" (RFC6750) and signing the request like http-mac or your proposal?

What I'd need is *just* a way so that a "thing" passed from the Client to
the PR couldn't be reused with other PRs (should contain something that
identifies the PR), and ideally couldn't also be "replayed" (let's give it
a validity period, maybe also a nonce).
Doesn't that nicely matches with JWT's "aud", "iat", "exp", "nbf" and
possibly "jti" of JWT, as already used by jwt-bearer? Let's just use the
client_id as "iss" (as in jwt-bearer) and the "access token" as "sub", and
sign that.
It's assumed that the AS already knows the public key of the Client so it
can verify the signature; the access token response from the AS would
probably include the signature algorithm that the Client is expected to
use, but that could also have been "negotiated" before (just as with
jwt-bearer, you have to know what the AS expects you to use).
A compromised PR, despite knowing the access token (unless the JWT is
encrypted rather than just signed), couldn't access other resource servers
as it couldn't
Just as with bearer tokens, it's assumed that PRs are reached through TLS
(if you need OAuth, it means you're accessing data of the End-User, so you
should use TLS anyway for privacy concerns). In the event there's an
eavesdropper nevertheless, the "iat", "exp" and "nbf" limit the reuse of
the token, and "jti" (if used, and used correctly) totally mitigates the
risk of replay attacks.

The major remaining risk is a compromised client (and of course compromised
AS). I don't think we can do much things about it though, apart from heavy
monitoring at the AS and blacklisting the Client whenever some bad use is
detected.

Remember I'm not a security guy though. Would that be too insecure? (I
doubt it, everybody uses bearer tokens nowadays, and the approach is the
same as with jwt-bearer) Have I missed something?

---

From: Justin Richer <[email-masked]>
Date: Mon, 28 Oct 2013 13:56:51 -0400

What you suggest below is essentially what John Bradley proposed as a 
"holder of key" JWT a while ago. The main difference between the two 
approaches is that mine can also cover aspects of the HTTP request 
itself in the signature. I think you could do both of them together by 
simply making the "signed" and "hash" bits optionally empty, which would 
effectively give you the functionality you're after.

  -- Justin

On 10/26/2013 04:34 PM, Thomas Broyer wrote:
>
>
> On Sat, Oct 26, 2013 at 6:03 PM, Richer, Justin P. <[email-masked] 
> <mailto:[email-masked]>> wrote:
>
>>     crypto-related work. Asking them to do it for each and every
>>     request to sign the access token might not be that
>>     >
>>     >
>>     > I assume you mean signing the request or at least some request
>>     data. Just signing the access token won't help.
>>
>     I suggested to the group that we try something like this a while
>     ago but it didn't get traction at the time. I never really wrote
>     down the whole process I had in mind, so here's a quick overview:
>
>
>     First, the client gets a token from the auth server using any
>     normal oauth mechanism (or any abnormal mechanism for that
>     matter), and the response looks something like this:
>
>     {
>       token_type: signed,
>       alg: <JWS algorithm to use for signing requests to the RS, I'll
>     use HS256 for my example below but we could probably tweak this to
>     use asymmetric keys too>
>       expires_in: 3600
>       …
>     }
>
>
>     Treating this request as a structure, we've got a verb, a url
>     (with scheme, host, path, parameters), and some headers. We want
>     the client to be able to sign some subset of this with the
>     request, so let's say this client wants to sign the verb,
>     scheme+host+port+path, the parameters, and one of the headers. So
>     the way I see it we've got a couple options. First is to repeat
>     all the items to be signed within a JSON structure and use JWS.
>     This is messy and it ignores some of the best stuff about using
>     HTTP/REST these days. Second, we can combine, normalize, and hash
>     the signable items. With this approach and some sufficient
>     handwavium (because I don't really want to get into specifics of
>     serialization and normalization here), we get something like this
>     for a base string:
>
>     GET
>     http://foo.bar/baz
>     quux=bob
>     woz=whynot
>     which we can hash using a defined algorithm of the same bit size
>     as our signing algorithm. So say we're using HMAC 256, we get a
>     base64url encoded hash blob like this fake one I just made up:
>     HJ23dfjoa32fasd23lajkds
>
>     So great, we've got a hash and we've got a set of data that was
>     hashed. So far we're in the same boat that got a lot of OAuth 1.0
>     implementations in trouble, due to oddities about normalization.
>     So let's take this a step further and tell the server what we're
>     hashing in our signed content, but by repeating just the *keys* to
>     this content and not the content itself, since the keys will be
>     shorter in many cases and less redundant:
>
>     Note that this uses arrays, which is important because arrays
>     preserve order in JSON. Now we have a pretty programmatic way of
>     telling the server which bits we care about signing and what order
>     we put them in, with normalizing those aspects. This makes us
>     robust against stuff getting reordered and new headers or query
>     parameters being inserted (which often happens with various web
>     frameworks). Of course, after verifying a signature, an app would
>     want to make sure that important parameters were covered by that
>     signature, but that's up to the app. Any decent library would make
>     the list available to the app easily enough for a quick check.
>
>     And we'll make our normal JWS header, use the above JSON object as
>     the bode, and sign it with JWS using the secret/key that we got up
>     in the token response:
>
>     [Side note: Maybe if you really wanted to you could also sign it
>     using the client secret and include the client id in the signed
>     data, like OAuth 1.0 does.]
>
>     And *now* we can send this over using any method comparable to
>     those defined in RFC6750, since it's all a single, self-contained
>     value.
>
>     http://foo.bar/baz?quxx=bob&woz=whynot&signed_access_token=eyheaderstufffooo.eybodystuffbaaar.signatureblob HTTP/1.1
>     Accept: application/json
>     parameter are automatically excused from the signature calculation
>     because they don't show up in the signed lists.
>
>
>     First, check the signature on the token. This is self-contained
>     and is a quick JWS operation. [Side note: how does the RS get the
>     private signing/checking key from the AS? I don't care, and
>     neither should you, because it's orthogonal to this part of the
>     spec family.]
>
>     "signed" member tells the RS which parts of the original request
>     it needs to check. Even with extra parameters and bits you end up
>     pulling only the parts that you need. And you know what order to
>     smash them together, too, without doing any kind of sorting!
>
>     Fourth, the RS makes sure any "important" parameters and headers
>     and other bits are actually covered by the hash.
>
>
>
>     Anyway, I think this method is worlds simpler than what we've got
>     in http-mac right now and it goes back to solving a number of the
>     use cases that have been brought up, including my own of simply
>     protecting an HTTP message apart from tokens.
>
>
> What I'd need is *just* a way so that a "thing" passed from the Client 
> to the PR couldn't be reused with other PRs (should contain something 
> that identifies the PR), and ideally couldn't also be "replayed" 
> (let's give it a validity period, maybe also a nonce).
> possibly "jti" of JWT, as already used by jwt-bearer? Let's just use 
> the client_id as "iss" (as in jwt-bearer) and the "access token" as 
> "sub", and sign that.
> It's assumed that the AS already knows the public key of the Client so 
> it can verify the signature; the access token response from the AS 
> would probably include the signature algorithm that the Client is 
> expected to use, but that could also have been "negotiated" before 
> (just as with jwt-bearer, you have to know what the AS expects you to 
> use).
> encrypted rather than just signed), couldn't access other resource 
> servers as it couldn't
> Just as with bearer tokens, it's assumed that PRs are reached through 
> TLS (if you need OAuth, it means you're accessing data of the 
> End-User, so you should use TLS anyway for privacy concerns). In the 
> event there's an eavesdropper nevertheless, the "iat", "exp" and "nbf" 
> limit the reuse of the token, and "jti" (if used, and used correctly) 
> totally mitigates the risk of replay attacks.
>
> The major remaining risk is a compromised client (and of course 
> compromised AS). I don't think we can do much things about it though, 
> apart from heavy monitoring at the AS and blacklisting the Client 
> whenever some bad use is detected.
>
> doubt it, everybody uses bearer tokens nowadays, and the approach is 
> the same as with jwt-bearer) Have I missed something?
>
>
> -- 
> Thomas Broyer