>> 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
_______________________________________________
OAuth mailing list
OAuth@ietf.org
https://www.ietf.org/mailman/listinfo/oauth

Reply via email to