Skip to content
This repository was archived by the owner on Apr 13, 2022. It is now read-only.

Commit 0f92430

Browse files
jaxoncreeddmitrizagidulin
authored andcommitted
In depth documentation up to auth request
1 parent c4aeff6 commit 0f92430

File tree

2 files changed

+289
-0
lines changed

2 files changed

+289
-0
lines changed

ApplicationLoginFlow.png

54.7 KB
Loading

application-workflow-detailed.md

Lines changed: 289 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,289 @@
1+
# Detailed Application Authentication
2+
3+
This document outlines, in detail, the login and request process for an application using WebId-OIDC. In general, our user, *Alice* will be using a thrid-party application at `https://www.decentphotos.example` to access data on both her pod at `https://alice.example` and her friend, Bob's pod at `https://bob.example`.
4+
5+
## Actors
6+
7+
In this example a multitude of actors are at play:
8+
9+
**Alice** - Alice will be providing consent for decentphotos to use her pod. Let's assume that Alice is using a standard web browser.
10+
11+
**Bob's Pod (RS)** - We will be trying to access photos Bob's Pod, known in the OIDC world as a Resource Server (RS). Bob is a friend of Alice. For this use case, let's assume that Bob has previously indicated via access control that Alice may access his photo using any app. You can read more about access control [here](https://github.com/solid/web-access-control-spec#referring-to-origins-ie-web-apps). For this example, bob's pod is at `bob.solid.example`.
12+
13+
**Alice's OP** - Alice's OpenID Provider (OP), also known as an IDP (Identity Provider), is the service responsible for authorizing our thrid-party app by providing it with the tokens necessary to gain access to any pod. In this demo, alice's OP is at `secureauth.example`.
14+
15+
**Alice's Pod (RS)** - Alice's Pod is hosted at `alice.coolpod.example`, giving Alice the webId of `https://alice.coolpod.example/profile/card#me`.
16+
17+
**Decent Photos (RP)** - decentphotos is a third party photo viewing application hosted at `https://www.decentphotos.example`. This app allows you to view your photos as well as your friend's photos. It will also perform cron jobs on the photos to detect faces. In the OIDC world this is known as the Relying Party (RP).
18+
19+
## Application Flow
20+
21+
![Application Login Flow](ApplicationLoginFlow.png)
22+
23+
### Authorization
24+
25+
Before any requests can be made, Alice must log in:
26+
27+
#### 1. Alice naviages to www.decentphotos.example
28+
29+
Alice has heard of a great new site that allows her to view her friend's photos and tag faces. She navigates to `www.decentphotos.example` via he web browser which returns and html page. This page contains JavaScript that will help with the authorization process.
30+
31+
#### 2. Alice clicks the "Connect" button
32+
33+
Before decentphotos can start displaying images, Alice needs to start the process of providing consent. To do so, she must either provider her webId (`https://alice.coolpod.example/profile/card#me`) or the service the url of her OP (`https://secureauth.example`)
34+
35+
While it is not the case with Alice, a user's Pod and OP can be hosted at the same domain. For example, Bob's pod could be `bob.solid.example` with a webId of `https://bob.solid.example/profile/card#me`, but his OP is at `https://solid.example`.
36+
37+
#### 3. Request OP Configuration
38+
39+
Now that Alice has indicated either her webId or her OP's url, the RP must make a request to retrieve the OP's configuration.
40+
41+
If Alice entered her webId the request would be her webId's origin plus a path for the OIDC configuration:
42+
```bash
43+
GET https://alice.coolpod.example/.well-known/openid-configuration
44+
```
45+
46+
If Alice entered her OP's url, the RP would simply append the OIDC configuration to the end.
47+
48+
```
49+
GET https://secureauth.example/.well-known/openid-configuration
50+
```
51+
52+
#### 4. Returns OP Configuration
53+
54+
Regardless of the what Alice entered, the response body should be the same. The [openid-configuration](https://auth0.com/docs/protocols/oidc/openid-connect-discovery) describes everything the client will need to know to authorize with Alice's specific OP.
55+
56+
Response Body:
57+
```json
58+
{
59+
"issuer":"https://secureauth.example",
60+
"authorization_endpoint":"https://secureauth.example/authorize",
61+
"token_endpoint":"https://secureauth.example/token",
62+
"userinfo_endpoint":"https://secureauth.example/userinfo",
63+
"jwks_uri":"https://secureauth.example/jwks",
64+
"registration_endpoint":"https://secureauth.example/register",
65+
"response_types_supported":[
66+
"code",
67+
"code token",
68+
"code id_token",
69+
"id_token",
70+
"id_token token",
71+
"code id_token token",
72+
"none"
73+
],
74+
"response_modes_supported":[
75+
"query",
76+
"fragment"
77+
],
78+
"grant_types_supported":[
79+
"authorization_code",
80+
"implicit",
81+
"refresh_token",
82+
"client_credentials"
83+
],
84+
"subject_types_supported":[
85+
"public"
86+
],
87+
"id_token_signing_alg_values_supported":[
88+
"RS256",
89+
"RS384",
90+
"RS512",
91+
"none"
92+
],
93+
"token_endpoint_auth_methods_supported":[
94+
"client_secret_basic"
95+
],
96+
"token_endpoint_auth_signing_alg_values_supported":[
97+
"RS256"
98+
],
99+
"display_values_supported":[
100+
101+
],
102+
"claim_types_supported":[
103+
"normal"
104+
],
105+
"claims_supported":[
106+
107+
],
108+
"claims_parameter_supported":false,
109+
"request_parameter_supported":true,
110+
"request_uri_parameter_supported":false,
111+
"require_request_uri_registration":false,
112+
"check_session_iframe":"https://secureauth.example/session",
113+
"end_session_endpoint":"https://secureauth.example/logout"
114+
}
115+
```
116+
117+
*RECOMMENDATION: It is recommended that this configuration is saved to local storage so that it does not need to be retrieved every time the RP needs to make a request to the OP*
118+
119+
Currently in local storage:
120+
```
121+
OPENID_CONFIGURATION
122+
```
123+
124+
125+
#### 5. Generates a Private/Public key pair
126+
127+
WebId-OIDC depends on [Proof of Posession (PoP) tokens](README.md#securing-tokens-for-multiple-resource-servers). PoP tokens ensure that third-party applications can send requests to any number of Pods, while ensuring that evil pods can't steal a user's token.
128+
129+
The first step to generating a PoP token is generating a public and private key pair on the third-party RP. In our example, the private key is generated using `RSA256` and looks like:
130+
131+
```json
132+
{
133+
"alg":"RS256",
134+
"d":"UA69ET5dNnBYs1lbtNKEjozUXa3S5XYAjTkCcop1hxYAP4gM52iAkEQ0Jgs6CuVs74MxQM9vL__tMjH6KQ0sBvKTF_asnGYitftxBkABySwa-9bsDKtSrYO3F33Ctsiqp1WmZaT0eZi6rqjibm5ByYJRbyf9NDUI_farEaKoN6fTYGnIajNzzTKVm3PChbT4VyiOAADPGyJGOq5PX0oIbOHRG817NXYSZq8ZtDbm2_HoQwXjkSqz31d1UL8HKyghPWU4gBrkPyo_JWaoxbYlV5FGGXXUKBIvoaETf2-w5c7xNtpKJA7IS9IIKvZx-pVXP0nl5FjVC-I4ksQRY-FceQ",
135+
"dp":"Sa70sh4J65bbcDBEuHtx4wjxcsgDJjNHTbWc2B9HaZw49QF-sEI63SYezhF9DgR5oF_opEwjISAIv6bruHcb7Um7lxyxFV-iczR8NfO_wMhP9_EP8PyodBkX0YYQt2pBAizPwM_knKlRJOL3Dw5G2lnBDlzg6bWnA8oEM1UFvFk",
136+
"dq":"AmLtOjwwJPjt80yHGZc_OoFlKGDnm5m-5U8aS_kfIGbAFADYPuXacnMeOCVCthg8avCBgS68rC3hfNZeWkPnG2vXIiZqFLMPblQu6sjnlcvJS3peNQrJMs46ah6NJeUfLtniIcbveRu_CaosLwH_au5sPzpyStgELWiX5yV-bw",
137+
"e":"AQAB",
138+
"ext":true,
139+
"key_ops":[
140+
"sign"
141+
],
142+
"kty":"RSA",
143+
"n":"qpm6eDf1JvcOmhX1icr--xrD2_mx-SxpqIDArguhEcnhVsA6usKjttars25H8fpc_rtN6qvdhHCRHxIafLZ0PtWeZ9-CCKNgMnYViBW-F5j70RXSBfJI8zal2UrQQycbBhmPi6ATTLHaQyVfDM_rFpRmR99wh4h6QR2fBRAX2_J9_lPvFMofmjcYcfaOT9l3TIoghfW2ma3oLkIG4La0MSScfwzPFuAjqr7xO-sRGYB9OQDbOHJpuXOw0FYb8wxuMZjBRzFsudjaxlzlpr1eR6a5sTA8tAIs0f3j0oZQts358mMxp4oRPstUuExvrZcIQ7XODi3AvMwjbbqd5b1How",
144+
"p":"1nWyuXZpF7DcAXOxGzsod-itCTEI1hYv4CGXQ5daSvbasF0tqs9LuRzpTEGokLlzPINNjTPqo-lUElLIhdMkQsdbeYdIwI6FqmxjHx30V1yQqhhCsTT8RKRaHoN53EQsqb1r1RyEzGT6mhll7M0fMVxMuHnHTBPhrvMM5Yj6C_k",
145+
"q":"y6U0YyN1uFukE34iCh2bQDU4l1qpgHN_r1UzsSOzLKAo6vlqlLMdbzA5Fn5JHlDWZE7QkBSeTi845_O64MB1G6YvVIQTtGFgdom_p_DKO8pdFo3lIv9p3SRoHafBe2xb_bBT4wXAA71hzbydug95pJ0PN5CBw2-seZcalHcxf3s",
146+
"qi":"ZK7ILqxNETFmBOA3xiBZiT7pylUqUCjbnxc_Jv_1I8QyiCwO5WPjPuCeclZiPPVSf7IlA3mY9hB7HB72d33zIeL8Esd95iFj_rr4SiiQ9V5sS_vo1roAbfApTNx2uT7Jdcp5Td_362971qbvZbj8kvrrvgi7Dv7jffIhKx9ez4w"
147+
}
148+
```
149+
From now on we will refer to this as `RP_PRIVATE_KEY`. The public key looks like:
150+
151+
```json
152+
{
153+
"jwk":{
154+
"alg":"RS256",
155+
"e":"AQAB",
156+
"ext":true,
157+
"key_ops":[
158+
"verify"
159+
],
160+
"kty":"RSA",
161+
"n":"mVnn-HwEQi5mZR3Z0Wc7TBrJouOb7acKiseVSkjrj4mWCSEw21VTGNfovzUS71WYKoxFAd8zfkI9-lsAn3tkL8ppcMuI3F8KxsO86nNHSKrxZIlk-bP7RDFfpI9KWyifulKdipEmRit4iN-EFI2mK9KREscPWG083vqn4D81Xe4s0-gmRsBrVanwwu-mTwEKy8RFomV8CXOTcTNntdR3krluXZ38_uKBB1qg6_phBQwZ_sDMXWs8E90eCXhd_EQ6S8PGzCDPT2vg9wCB57ifAXt_8e4ZnqySmFPxegy7j3GcMuyhHzdpvv2fX5DvOxsgkjhsBzby9LD0bxStdBCSFQ"
162+
}
163+
}
164+
```
165+
From now on we will refer to this as `RP_PUBLIC_KEY`.
166+
167+
#### 6. Saves the Public/Private key to local storage
168+
169+
The public/private key pair must be saved so that it can be referenced once the OP redirects back to the RP. It is recommended to save it to local storage, but that is not required.
170+
171+
Currently in local storage:
172+
```
173+
OPENID_CONFIGURATION
174+
RP_PRIVATE_KEY
175+
RP_PUBLIC_KEY
176+
```
177+
178+
#### 7. Requests OP JWKs
179+
180+
Now that the RP's Public/Private keys are generated. The RP needs to be aware of the OP's public key. To do so a request should be made to the `jwks_uri` from the openid-configuration:
181+
182+
```
183+
GET https://secureauth.example/jwks
184+
```
185+
186+
#### 8. Returns OP JWKs
187+
188+
The [JSON Web Key Set (JWKS)](https://auth0.com/docs/jwks) is returned. These will eventually be used to validate the signature of the token the OP will eventually issue. It is recommended that the result of this request should be saved to local storage.
189+
190+
Response body:
191+
```json
192+
{
193+
"keys":[
194+
{
195+
"kty":"RSA",
196+
"kid":"xeOjes9u3AcU4LBzcanEM7pZLwSlxaN7U62ZzOBDQuw",
197+
"alg":"RS256",
198+
"key_ops":[
199+
"verify"
200+
],
201+
"e":"AQAB",
202+
"n":"oB2LgkiZZ5iLAz1d4ua7sVxdbzY2nIRkDtf4UE08mWsD6UYRzLR98_gMAfnKB8i9yPCQkxfA5w_SZq6Y7odG1qSwLHM2mb_O2GSvY9kaG00UpeeEJCR19c7Jkcmq3GXh4yujnm2TFQ6YAzYNgrXkHlusaFUApJaQN6zr4AvmR_vX_5i__Ku7nuU-GbaV75LSr8o0QANdYFF0ooz5DJvydPplF8mO9_oD7ceSNLWP1AXlFs5JH6MEhH02dELb4-zeLcVzhoqON60cABTpbYSf1lLbYZsVUQ3cYE9CxXaByY2YNuQgc0k29mSmUvwEs0hNA5xUcE3-y_qKpYKniErb9Q"
203+
}
204+
]
205+
}
206+
```
207+
208+
Currently in local storage:
209+
```
210+
OPENID_CONFIGURATION
211+
RP_PRIVATE_KEY
212+
RP_PUBLIC_KEY
213+
OP_JWKS
214+
```
215+
216+
#### 9. Sends Dynamic Registration Parameters
217+
218+
Now we have everything we need to perform [dynamic client registration](https://openid.net/specs/openid-connect-registration-1_0.html). Because each Solid user could have a different OP, it is not feasible to expect the developers of RPs to manually register with every OP. Therefore, the client (RP) is registered dynamically. A request is sent to the OP's `registration_endpoint`:
219+
220+
```
221+
POST https://secureauth.example/register
222+
```
223+
Data:
224+
```json
225+
{
226+
grant_types: ["implicit"]
227+
issuer: "https://secureauth.example"
228+
redirect_uris: ["https://www.decentphotos.example/"]
229+
response_types: ["id_token token"]
230+
scope: "openid profile"
231+
}
232+
```
233+
234+
Each of these communicates something about the new client to the OP:
235+
- `grant_types`: A list of [OIDC grant types](http://docs.identityserver.io/en/latest/topics/grant_types.html) this client will use. `implicit` is great for web applications.
236+
- `issuer`: Alice's OP
237+
- `redirect_uris`: Redirect uris provided at the client registration stage state which redirect uris are valid during the authorization stage.
238+
- `response_types`: A list of [OIDC response types](https://openid.net/specs/oauth-v2-multiple-response-types-1_0.html) the client can use. `id_token token` means that // TODO: Ask Dmitri about wrapping an id_token in a pop token. Should it not be the access token?
239+
- `scope`: OIDC uses scope as a way of defining what a client can have acces to. However, Solid has it's own access control system, so scope will always be `openid profile`
240+
241+
#### 10: Saves Client Information
242+
243+
The OP saves the client information to read later.
244+
245+
#### 11: Returns successful registration
246+
247+
The OP responds confirming the request, and with some new data.
248+
249+
Response Body:
250+
```json
251+
{
252+
"client_id":"7243fd594bdcf9c71a9b902274afaa30",
253+
"redirect_uris":[
254+
"https://chat.o.team/"
255+
],
256+
"response_types":[
257+
"id_token token"
258+
],
259+
"grant_types":[
260+
"implicit"
261+
],
262+
"application_type":"web",
263+
"id_token_signed_response_alg":"RS256",
264+
"token_endpoint_auth_method":"client_secret_basic",
265+
"frontchannel_logout_session_required":false,
266+
"registration_access_token":"eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczovL3NvbGlkLmNvbW11bml0eSIsInN1YiI6IjcyNDNmZDU5NGJkY2Y5YzcxYTliOTAyMjc0YWZhYTMwIiwiYXVkIjoiNzI0M2ZkNTk0YmRjZjljNzFhOWI5MDIyNzRhZmFhMzAifQ.gypiiq3K5_oRpEN7e1KaobI5CwWdrr7ZpwhdjUMneSEOEUVOwE0qeWlzu44j24eOIGeX8PzTc-f5ca0cRk22HSSRZIcAVo-GmGlZ4oAA5uGOuiEdncaF3ZKDv-0q1WXiyUFD_2hiiUrQwLtt-iSo3ZQOlCMP3opC6A73-b6UpOJTc9Q-V-sNTtOZ5IHpgOSkQZbgSuQr_vTGRLjoHl_v_8-AarjUIytbf_6h9iEFuPOyqugMUFALeNPBHSN8CTgJI3jcvx4HZtM9ByHNGGPjZv4TJrXy1sJIHokJkwdg1Pv_3mkUKVwtO4zxKAOu5MlspaZo6c-Oku__9S2mnu88xQ",
267+
"registration_client_uri":"https://solid.community/register/7243fd594bdcf9c71a9b902274afaa30",
268+
"client_id_issued_at":1557964995
269+
}
270+
```
271+
272+
The main one to keep note of is the `client_id` which will be used to tie subsequent requests back to this registered client.
273+
274+
This information should be saved to local storage.
275+
276+
Currently in local storage:
277+
```
278+
OPENID_CONFIGURATION
279+
RP_PRIVATE_KEY
280+
RP_PUBLIC_KEY
281+
OP_JWKS
282+
CLIENT_REGISTRATION_RESPONSE
283+
```
284+
285+
#### 12. Authorization Request
286+
287+
// TODO complete explanation
288+
289+
####

0 commit comments

Comments
 (0)