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
90173Prior to this proposal, widgets could use an undocumented ` scalar_token ` parameter if the client chose to
91174send 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