docs(service-clients): Document Service Clients, JKUs, and JWTs
Closes #329
This commit is contained in:
Родитель
0a0e3034bb
Коммит
799f0e22d3
14
docs/api.md
14
docs/api.md
|
@ -368,20 +368,26 @@ particular user.
|
|||
|
||||
#### Request Parameters
|
||||
|
||||
- `client_id`: The id returned from client registration.
|
||||
- `client_secret`: The secret returned from client registration.
|
||||
- `ttl`: (optional) Seconds that this access_token should be valid.
|
||||
|
||||
The default and maximum value is 2 weeks.
|
||||
- `grant_type`: Either the string `authorization_code` or `refresh_token`.
|
||||
- `grant_type`: Either `authorization_code`, `refresh_token`, or `urn:ietf:params:oauth:grant-type:jwt-bearer`.
|
||||
- If `authorization_code`:
|
||||
- `client_id`: The id returned from client registration.
|
||||
- `client_secret`: The secret returned from client registration.
|
||||
- `code`: A string that was received from the [authorization][] endpoint.
|
||||
- If `refresh_token`:
|
||||
- `client_id`: The id returned from client registration.
|
||||
- `client_secret`: The secret returned from client registration.
|
||||
- `refresh_token`: A string that received from the [token][]
|
||||
endpoint specifically as a refresh token.
|
||||
- `scope`: (optional) A subset of scopes provided to this
|
||||
refresh_token originally, to receive an access_token with less
|
||||
permissions.
|
||||
- If `urn:ietf:params:oauth:grant-type:jwt-bearer`:
|
||||
- `assertion`: A signed JWT assertion. See [Service
|
||||
Clients][] for more.
|
||||
|
||||
|
||||
**Example:**
|
||||
|
||||
|
@ -501,3 +507,5 @@ A valid request will return JSON with these properties:
|
|||
[delete]: #post-v1destroy
|
||||
[verify]: #post-v1verify
|
||||
[developer-activate]: #post-v1developeractivate
|
||||
|
||||
[Service Clients]: ./service-clients.md
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
# Service Clients
|
||||
|
||||
Do you wish to allow users to authenticate to your app, as well as fetch
|
||||
some information about them? Then you don't want to be a Service Client.
|
||||
Be a regular client.
|
||||
|
||||
Service Clients exist as privileged apps that need to be able to request
|
||||
information about a user, without ever having received permission to do
|
||||
so. Sounds nefarious. However, as said, these are **privileged** apps,
|
||||
meaning they are also run by **us** (Mozilla). So these apps are not
|
||||
gaining access to something that we don't already know. Plus, before
|
||||
ever being promoted to a Service Client, real humans are involved to
|
||||
make sure it's the correct use case.
|
||||
|
||||
## All Powerful
|
||||
|
||||
A Service Client exists by being in the config array `serviceClients`.
|
||||
Each entry (if any) is an object, with the following values:
|
||||
|
||||
- `id` - `String`: a unique hex value in identical format to regular
|
||||
client ids.
|
||||
- `name` - `String`: a plaintext name for the client that's friendly to
|
||||
human readers.
|
||||
- `scope` - `String`: space-separated scopes that this client will be
|
||||
using when requesting access tokens.
|
||||
- `jku` - `String`: a unique URL that will host a JWK Set. Unique as in
|
||||
unique in the current list of Service Clients.
|
||||
|
||||
## JKUs and JWK Sets
|
||||
|
||||
Imagine a service client with the `jku` of `https://example.dom.ain/keys`.
|
||||
The document hosted at that URL should contain something like:
|
||||
|
||||
```json
|
||||
{
|
||||
"keys":[{
|
||||
"kid":"key-id-can-whatever-1",
|
||||
"use": "sig",
|
||||
"kty":"RSA",
|
||||
"n":"W_lCUvksZMVxW2JLNtoyPPshvSHng28H5FggSBGBjmzv3eHkMgRdc8hpOkgcPwXYxHdVM6udtVdXZtbGN8nUyQX8gxD3AJg-GSrH3UOsoArPLCmcxwIEpk4B0wqwP68oK8dQHt0iK3N-XeCnMpv75ULlVn3LEOZT8CsuNraVOthYeClUb8r1PjRwqRB06QGNqnnhcPMmh-6cRzQ9HmTMz6CDcugiH5n2sjrvpeBugEsnXt3KpzVdSc4usXrIEmLRuFjwFbkzoo7FiAtSoXxBqc074qz8ejm-V0-2Wv3p6ePeLODeYkPQho4Lb1TBdoidr9RHY29Out4mhzb4nUrHHQ",
|
||||
"e":"AQAB"
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
This JKU is important when making requests for access tokens.
|
||||
|
||||
## JWTs and Authorization
|
||||
|
||||
To request an access token, a service client must generate a signed [JWT][],
|
||||
and then send it to our [/v1/token][] endpoint.
|
||||
|
||||
Here's an example of creating a JWT in JavaScript:
|
||||
|
||||
```js
|
||||
var now = Math.floor(Date.now() / 1000); // in seconds
|
||||
var header = {
|
||||
alg: 'RS256',
|
||||
typ: 'JWT',
|
||||
jku: 'https://basket.mozilla.org/.well-known/jku',
|
||||
kid: 'k1'
|
||||
};
|
||||
var claims = {
|
||||
scope: 'profile:email',
|
||||
aud: 'https://oauth.accounts.firefox.com/v1/token',
|
||||
iat: now,
|
||||
exp: now + (60 * 5),
|
||||
sub: '9b052aebbc48c8376257c777e2a7f009'
|
||||
};
|
||||
|
||||
var token = base64(JSON.stringify(header)) + '.' + base64(JSON.stringify(claims));
|
||||
var sig = rsa256(Buffer(token, 'base64'), privateKey);
|
||||
var jwt = token + '.' + base64(sig);
|
||||
```
|
||||
|
||||
Once you have a signed JWT, you would make the following request:
|
||||
|
||||
```sh
|
||||
curl -v \
|
||||
-X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
"https://oauth.accounts.firefox.com/v1/token" \
|
||||
-d '{
|
||||
"grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
|
||||
"assertion": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImprdSI6Imh0dHBzOi8vYmFza2V0LmFjY291bnRzLmZpcmVmb3guY29tLy53ZWxsLWtub3duL2prdSIsImtpZCI6ImsxIn0.eyJzdWIiOiI1OTAxYmQwOTM3NmZhZGFhNTkwMWJkMDkzNzZmYWRhYUBhY2NvdW50cy5maXJlZm94LmNvbSIsInNjb3BlIjoicHJvZmlsZTplbWFpbCIsImF1ZCI6Imh0dHBzOi8vb2F1dGguYWNjb3VudHMuZmlyZWZveC5jb20vdjEvdG9rZW4iLCJpYXQiOjE0NDM2NjI0ODEsImV4cCI6MTQ0MzY2Mjc4MX0.Kmwfq7yZrKpwrcZ78NTLPs8v4ijMhoKVNZ45VJY-skyK_XD_U5DJeKq8IE6PspU6B6p0DPkW1EEKeKOAbpyzFIBi9uG7l329x32JkzXGwybxannbGrdd5DFZbIaBSZDf-64MXbxGBGQ8xy18dfXmgbmNsvYPRZqqS2gmoM1EvWg"
|
||||
}'
|
||||
```
|
||||
|
||||
The response is described in the [API docs][/v1/token].
|
||||
|
||||
[/v1/token]: ./api.md#post-v1token
|
||||
[JWT]: http://jwt.io/
|
Загрузка…
Ссылка в новой задаче