>> 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
[email protected]
https://www.ietf.org/mailman/listinfo/oauth