Skip to content

Commit c9e8326

Browse files
committed
Reword following widget spec
1 parent e304109 commit c9e8326

File tree

1 file changed

+130
-45
lines changed

1 file changed

+130
-45
lines changed

proposals/1960-integrations-openid.md

Lines changed: 130 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,155 @@
11
# MSC1960: OpenID Connect information exchange for widgets
22

3-
With the various integrations API proposals, widgets are left with no options to verify the
4-
requesting user's ID if they need it. Widgets like the sticker picker must know who is making
5-
the request and as such need a way to get accurate information about who is contacting them.
3+
Widgets are currently left with no options to verify the user's ID, making it hard for
4+
personalized and authenticated widgets to exist. The spec says the `$matrix_user_id`
5+
template variable cannot be relied upon due to how easy it is to faslify, which is true.
66

7-
This proposal introduces a way for widgets (room and account) to do so over the `fromWidget`
8-
API proposed by [MSC1236](https://github.com/matrix-org/matrix-doc/issues/1236).
7+
This MSC aims to solve the problem with verifiably accurate OpenID Connect credentials.
98

9+
As of writing, the best resource to learn more about the widgets spec is the following
10+
spec PR: https://github.com/matrix-org/matrix-doc/pull/2764
1011

1112
## Proposal
1213

13-
Room and account widgets may request new OpenID Connect credentials from the user so they can log in/register with
14-
the backing integration manager or other application. This is largely based on the prior art available
15-
[here (element-web#7153)](https://github.com/vector-im/element-web/issues/7153). The rationale for such an
16-
API is so that widgets can load things like a user's sticker packs or other information without having
17-
to rely on secret strings. For example, a room could be used to let a user create custom sticker packs
18-
via a common widget - it would be nice if that widget could auth the user without asking them to enter
19-
their username and password into an iframe.
20-
21-
Widgets can request OpenID Connect credentials from the user by sending a `fromWidget` action of `get_openid`
22-
to initiate the token exchange process. The client responds with an acknowledgement of
23-
`{"state":"request"}` (or `{"state":"blocked"}` if the client/user doesn't think the widget is safe).
24-
The client then prompts the user if the widget should be allowed to get details about the user,
25-
optionally providing a way for the user to always accept/deny the widget. If the user agrees, the
26-
client sends a `toWidget` action of `openid_credentials` with `data` holding the raw OpenID Connect credentials
27-
object returned from the homeserver, and a `success: true` parameter, similar to the following:
14+
Typically widgets which need to accurately verify the user's identity will also have a
15+
backend service of some kind. This backend service likely already uses the integration
16+
manager authentication APIs introduced by [MSC1961](https://github.com/matrix-org/matrix-doc/pull/1961).
17+
18+
Through using the same concepts from MSC1961, the widget can verify the user's identity
19+
by requesting a fresh OpenID Connect credential object to pass along to its backend, like
20+
the integration manager which might be running it.
21+
22+
The protocol sequence defined here is based upon the previous discussion in the Element Web
23+
issue tracker: https://github.com/vector-im/element-web/issues/7153
24+
25+
It is proposed that after the capabilities negotation, the widget can ask the client for
26+
an OpenID Connect credential object so it can pass it along to its backend for validation.
27+
The request SHOULD result in the user being prompted to confirm that the widget can have
28+
their information. Because of this user interaction, it's not always possible for the user
29+
to complete the approval within the 10 second suggested timeout by the widget spec. As
30+
such, the initial request by the widget can have one of three states:
31+
32+
1. The client indicates that the user is being prompted (to be followed up on).
33+
2. The client sends over credentials for the widget to verify.
34+
3. The client indicates the request was blocked/denied.
35+
36+
The initial request from the widget looks as follows:
37+
38+
```json
39+
{
40+
"api": "fromWidget",
41+
"action": "get_openid",
42+
"requestId": "AAABBB",
43+
"widgetId": "CCCDDD",
44+
"data": {}
45+
}
46+
```
47+
48+
Which then receives a response which has a `state` field alongside potentially the credentials
49+
to be verified. Matching the order of possible responses above, here are examples:
50+
51+
```json
52+
{
53+
"api": "fromWidget",
54+
"action": "get_openid",
55+
"requestId": "AAABBB",
56+
"widgetId": "CCCDDD",
57+
"data": {},
58+
"response": {
59+
"state": "request"
60+
}
61+
}
2862
```
63+
64+
```json
65+
{
66+
"api": "fromWidget",
67+
"action": "get_openid",
68+
"requestId": "AAABBB",
69+
"widgetId": "CCCDDD",
70+
"data": {},
71+
"response": {
72+
"state": "allowed",
73+
"access_token": "s3cr3t",
74+
"token_type": "Bearer",
75+
"matrix_server_name": "example.org",
76+
"expires_in": 3600
77+
}
78+
}
79+
```
80+
81+
```json
82+
{
83+
"api": "fromWidget",
84+
"action": "get_openid",
85+
"requestId": "AAABBB",
86+
"widgetId": "CCCDDD",
87+
"data": {},
88+
"response": {
89+
"state": "blocked"
90+
}
91+
}
92+
```
93+
94+
The credential information is directly copied from the `/_matrix/client/r0/user/:userId/openid/request_token`
95+
response.
96+
97+
In the case of `state: "request"`, the user is being asked to approve the widget's attempt to
98+
verify their identity. To ensure that future requests are quicker, clients are encouraged to
99+
include a "remember this widget" option to make use of the immediate `state: "allowed"` or
100+
`state: "blocked"` responses above.
101+
102+
There is no timeout associated with the user making their selection. Once a user does make
103+
a selection (allow or deny the request), the client sends a `toWidget` request to indicate the
104+
result, using a very similar structure to the above immediate responses:
105+
106+
```json
29107
{
30108
"api": "toWidget",
31-
"requestId": "AABBCC",
32109
"action": "openid_credentials",
33-
"widgetId": "DDEEFF",
110+
"requestId": "EEEFFF",
111+
"widgetId": "CCCDDD",
34112
"data": {
35-
"success": true,
36-
"access_token": "SecretTokenHere",
113+
"state": "allowed",
114+
"original_request_id": "AAABBB",
115+
"access_token": "s3cr3t",
37116
"token_type": "Bearer",
38-
"matrix_server_name": "example.com",
117+
"matrix_server_name": "example.org",
39118
"expires_in": 3600
40119
}
41120
}
42121
```
43122

44-
For clarity, the `data` consists of properties as returned by `/_matrix/client/r0/user/:userId/openid/request_token`
45-
plus the `success` parameter.
46-
47-
If the user denies the widget, just `success: false` is returned in the `data` property.
48-
49-
To lessen the number of requests, a client can also respond to the original `get_openid` request with a
50-
`state` of `"allowed"`, `success: true`, and the OpenID Connect credentials object (just like in the `data` for
51-
`openid_credentials`).
123+
```json
124+
{
125+
"api": "toWidget",
126+
"action": "openid_credentials",
127+
"requestId": "EEEFFF",
128+
"widgetId": "CCCDDD",
129+
"data": {
130+
"state": "blocked",
131+
"original_request_id": "AAABBB"
132+
}
133+
}
134+
```
52135

53-
The widget should not request OpenID Connect credentials until after it has exchanged capabilities with the client,
54-
however this is not required to wait for the capabiltiies exchange.
136+
`original_request_id` is the `requestId` of the `get_openid` request which started the prompt,
137+
for the widget's reference.
55138

56-
The widget acknowledges the `openid_credentials` request with an empty response object.
139+
The widget acknowledges receipt of the credentials with an empty `response` object.
57140

58-
A successful sequence diagram for this flow is as follows:
141+
A typical sequence diagram for this flow is as follows:
59142

60143
```
61144
+-------+ +---------+ +---------+
62145
| User | | Client | | Widget |
63146
+-------+ +---------+ +---------+
64147
| | |
65148
| | Capabilities negotiation |
66-
| |<-----------------------------------------|
149+
| |----------------------------------------->|
67150
| | |
68151
| | Capabilities negotiation |
69-
| |----------------------------------------->|
152+
| |<-----------------------------------------|
70153
| | |
71154
| | fromWidget get_openid request |
72155
| |<-----------------------------------------|
@@ -89,14 +172,16 @@ A successful sequence diagram for this flow is as follows:
89172

90173
Prior to this proposal, widgets could use an undocumented `scalar_token` parameter if the client chose to
91174
send it to the widget. Clients typically chose to send it if the widget's URL matched a whitelist for URLs
92-
the client trusts. Widgets are now not able to rely on this behaviour with this proposal, although clients
93-
may wish to still support it until adoption is complete. Widgets may wish to look into cookies and other
94-
storage techniques to avoid continously requesting credentials, regardless of how they got those credentials.
175+
the client trusts. With the widget specification as written, widgets cannot rely on this behaviour.
95176

96-
An implementation of this proposal is [here](https://github.com/matrix-org/matrix-react-sdk/pull/2781).
177+
Widgets may wish to look into cookies and other storage techniques to avoid continously requesting
178+
credentials. Widgets should also look into [MSC1961](https://github.com/matrix-org/matrix-doc/pull/1961)
179+
for information on how to properly verify the OpenID Connect credentials it will be receiving. The
180+
widget is ultimately responsible for how it deals with the credentials, though the author recommends
181+
handing it off to an integration manager's `/register` endpoint to acquire a single token string
182+
instead.
97183

98-
The widget is left responsible for dealing with the OpenID object it receives, likely handing it off to
99-
the integration manager it is backed by to exchange it for a long-lived Bearer token.
184+
An implementation of this proposal's early draft is here: https://github.com/matrix-org/matrix-react-sdk/pull/2781
100185

101186
## Security considerations
102187

0 commit comments

Comments
 (0)