-
Notifications
You must be signed in to change notification settings - Fork 385
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
MSC2964: Usage of OAuth 2.0 authorization code grant and refresh token grant #2964
base: main
Are you sure you want to change the base?
Changes from 1 commit
2af8b49
5962618
38c97a5
e12ee77
20d865d
261e3b0
38bb557
45d510b
d114f82
8fc3ea1
029e1e5
0802d8f
20ee4a3
6e387d8
4a2ed74
40048da
f0e319a
55215c1
21fee1c
2c0625d
24e0290
d145fd2
acfa845
fa506ff
378348e
c859c0b
c1c8312
05748a2
1034122
4830d47
f84428f
c57be5e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
# MSC2964: Matrix profile for OAuth 2.0 | ||
|
||
The current authentication mechanisms in Matrix does look like a lot like OAuth 2.0 without most of its security mechanisms. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. UIA and OAuth have two different goals, though. OAuth could be e.g. a UIA stage There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While it is still under discussion, the end goal is to completely replace the current authentication mechanism of Matrix with OAuth 2.0, not add OAuth as a UIA stage. This series of MSC are written with this in mind |
||
This MSC is part of a change to replace Matrix authentication mechanisms with OAuth 2.0. | ||
This MSC in particular defines how clients should authenticate with OAuth 2.0 to access the Matrix Client-to-Server API. | ||
|
||
## Proposal | ||
|
||
### Terminology | ||
|
||
**OAuth 2.0** is an authentication framework. Authentication systems are built on top of OAuth2. It is based on numerous RFCs by the IETF. | ||
hughns marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
**OpenID Connect** is a set of specifications defining a standard auth system built on top of OAuth2. Often abbreviated OIDC. Specs to know about: OIDC Core defines the actual auth system, OIDC Discovery defines the discovery of OP metadata, OIDC Registration allows clients to register themselves dynamically. | ||
|
||
An **Authorization/Authentication Server** (AS) or **OIDC Provider** (OP) in the context of OIDC is the service that fulfills an authentication request. In the context of Matrix, it is either the homeserver itself acting as the OP or an external one like Keycloak, Auth0, etc. | ||
hughns marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
A **Resource Server** (RS) is a protected service that requires authentication. In the context of Matrix, the homeserver is a RS. | ||
|
||
A **Resource Owner** (RO) is an end user. | ||
|
||
A **Relying Party** (RP) (client applications) is an app using resources from RS on behalf of the RO. In the context of Matrix, Matrix clients like Element Web are RP. | ||
|
||
A **User-Agent** (UA) is a thing that hosts client applications, like a web browser. | ||
|
||
### Assumptions and existing specifications | ||
|
||
This change assumes the client (RP) knows what authentication server (AS) it should use. | ||
The AS discovery is defined in [MSC2965](https://github.com/matrix-org/matrix-doc/pull/2965). | ||
|
||
It also assumes the client (RP) is already known by the authentication server (AS). | ||
The client registration process is defined in [MSC2966](https://github.com/matrix-org/matrix-doc/pull/2966). | ||
|
||
The goal of this MSC is not to explain how OAuth 2.0 works but rather what mechanisms of OAuth 2.0 RP and AS are expected to implement. | ||
This is done to ensure interoperability between Matrix clients and Homeservers while ensuring that the login flow is secure. | ||
|
||
### Client profiles | ||
|
||
#### Native and browser-based clients | ||
|
||
This client type applies to clients that are running directly on the user-agent. | ||
These clients are either browser-based or are capable of interacting with a separate web browser to have the user interact with the authentication server. | ||
|
||
Those clients must use the authorization code flow by directing the user to the authorization endpoint to obtain authorization. | ||
After the user authenticated and authorized the client, the user's web browser is redirected to a URI hosted by the client with an authorization code. | ||
The client then exchanges the authorization code to obtain an access token using the token endpoint. | ||
|
||
Those clients are public and therefore must use [PKCE](https://tools.ietf.org/html/rfc7636) with the S256 code challenge mechanism. | ||
|
||
The authorization must issue refresh tokens for those type of clients if requested by them. | ||
|
||
#### Server-based clients | ||
|
||
This client type applies to hosted clients. | ||
These clients must be capable to redirect the user to have them interact with the authentication server. | ||
|
||
As with native and public browser-based clients, they must use the authorization code flow to obtain authorization. | ||
Those clients are confidential and must authenticate their requests to the authorization server with their client credentials. | ||
|
||
The authorization must issue refresh tokens for those type of clients if requested by them. | ||
|
||
#### TBD | ||
|
||
Restricted input clients like TVs might use the [Device Authorization Grant](https://tools.ietf.org/html/rfc8628). | ||
CLI tools might use the [Client Credentials Grant](https://tools.ietf.org/html/rfc6749#section-4.4). | ||
|
||
The details of those are still TBD. | ||
|
||
### Requests to the authorization endpoint | ||
|
||
When making a request to the authorization endpoint, clients must provide an unpredicatble value for the `state` parameter and validate it when returning to the redirect URI. | ||
They must ensure the `state` value is securely tied to the current session. | ||
|
||
The redirect URIs used by the clients must match exactly with the ones registered to prevent open redirection attaks. | ||
The full redirect URI must be included in the authorization request. | ||
|
||
The client might include a login hint to what MXID the user is trying to use. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So far the spec only requires a username on login and There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would like to see some more info on what a "login hint to what MXID" is. Can that be the username or does it have to be the mxid? Does the client now have to do the mxid mapping, that so far was pretty much implementation defined? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If I understood correctly, like the name suggests, it's only a hint, to avoid the user having to enter their MXID/username several times. For example, with a client you would have these steps:
In no way it should limit the choice of username for the user, or force the auth server or homeserver to use it. That's what I understand of the intentions for that field from the OIDC spec anyway. Although ultimately the auth server is free to do whatever it pleases and might also ignore this parameter altogether. I would guess it's also up to the auth server and homeserver to decide if the username used for authentication matches the one in the MXID. Irc, it's already the case in Synapse's OIDC config where one can chose to map the username from the auth server to anything else. To get the final MXID, the client needs to call the homeserver's There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, often clients actually use separate fields for server and username (or the server is even preconfigured). Users then just enter "FirstName LastName", so would that be an acceptible login hint or does it have to be an mxid? |
||
|
||
The scopes the client can request are defined in [MSC2967](https://github.com/matrix-org/matrix-doc/pull/2967). | ||
|
||
Sample authorization request: | ||
|
||
``` | ||
https://account.example.com/oauth2/auth? | ||
client_id = s6BhdRkqt3 & | ||
response_type = code & | ||
redirect_uri = https://app.example.com/oauth2-callback & | ||
scope = openid urn:matrix:* & | ||
state = ewubooN9weezeewah9fol4oothohroh3 & | ||
nonce = aazeiD3ahmai6ui9eiveiphochoyaewi & | ||
login_hint = mxid:@john:example.com & | ||
code_challenge = 72xySjpngTcCxgbPfFmkPHjMvVDl2jW1aWP7-J6rmwU & | ||
code_challenge_method = S256 | ||
``` | ||
|
||
### Requests to the token endpoint | ||
|
||
When exchanging the `code`, clients must include their `client_id` and the `redirect_uri` they used for the initial request. | ||
The server must verify they match for this `code`. | ||
|
||
If PKCE was used in the authorization request (required for public client), the client must include the `code_verifier` and the server must validate it. | ||
|
||
If the client is confidential, it must authenticate by including its `client_secret`. | ||
|
||
TBD: should confidential clients use [JWT assertions](https://tools.ietf.org/html/rfc7523#section-2.2) instead? | ||
|
||
``` | ||
POST /oauth2/token HTTP/1.1 | ||
Host: account.example.com | ||
Content-Type: application/x-www-form-urlencoded | ||
Accept: application/json | ||
|
||
grant_type=authorization_code | ||
&code=iuB7Eiz9heengah1joh2ioy9ahChuP6R | ||
&redirect_uri=https%3A%2F%2Fapp.element.io%2Foauth2-callback | ||
&client_id=s6BhdRkqt3 | ||
&code_verifier=ogie4iVaeteeKeeLaid0aizuimairaCh | ||
``` | ||
|
||
```json | ||
{ | ||
"access_token": "2YotnFZFEjr1zCsicMWpAA", | ||
"token_type": "Bearer", | ||
"expires_in": 299, | ||
"refresh_token": "tGzv3JOkF0XG5Qx2TlKWIA", | ||
"scope": "openid urn:matrix:api:*", | ||
"id_token": "..." | ||
} | ||
``` | ||
|
||
The access token must be short-lived and should be refreshed using the `refresh_token` when expired. | ||
|
||
### Existing authentication types equivalence | ||
|
||
The current authentication mechanism can have multiple stages allowing to ask users to perform certains actions. | ||
This includes: | ||
|
||
- social login (`m.login.sso`), with multiple providers ([MSC2858](https://github.com/matrix-org/matrix-doc/pull/2858)) | ||
- complete a CAPTCHA (`m.login.recaptcha`) | ||
- agree to terms of services and privacy policies (`m.login.terms`, [MSC1692](https://github.com/matrix-org/matrix-doc/pull/1692)) | ||
- TOTP/2FA (`m.login.totp`, [MSC2271](https://github.com/matrix-org/matrix-doc/pull/2271)) | ||
|
||
All of this can be done by the authentication server without any modification to the specification. | ||
|
||
### Replacement of UIA | ||
|
||
Some API endpoints use User-Interactive Authentication to perform some higher-privileged operations, like deleting a device or adding a 3PID. | ||
An equivalent behaviour can be achieved by temporarily upgrade the client authorization with additional scopes. | ||
|
||
Whenever the client ask for a token (either with a refresh token or by initiating a authorization code flow) the authentication server returns the list of scopes for which the token is valid. | ||
This helps client track what scopes they currently have access to, and let them upgrade temporarily a token with additional scopes to perform privileged actions. | ||
The authorization server can also downgrade the scopes of a session after a certain time by returning a reduced list of scopes when refreshing the token. | ||
The scope definitions are out of scope of this MSC and are defined in [MSC2967](https://github.com/matrix-org/matrix-doc/pull/2967). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Couldn't this be replaced with; the client requesting for a seperate token with only the required scope to perform this action, only for it to be dropped (deactivated) immidiately after? Something about upgrading the same token doesn't sit well with me from a security perspective, it might be a deliberately locked-down token, and/or multiple actions at once could race to upgrade/downgrade the current token. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Having a separate token purely for one scope / set of scopes sounds like a really good idea, especially for race condition reasons. Races could be also avoided by introducing state on AS/OP side, but that is quite out of scope of oauth2 specification (if I'm not mistaken) At the same time, it would make specification compatible with more possible OP implementations. Making it single use would be easily doable using jti claim on that token. |
||
|
||
### User registration | ||
|
||
User can register themselves by initiating a authorization code flow with the `prompt=create` parameter as defined in [_Initiating User Registration via OpenID Connect - draft 03_](https://openid.net/specs/openid-connect-prompt-create-1_0.html). | ||
|
||
### Logging out | ||
|
||
TBD. [OIDC Frontchannel logout](https://openid.net/specs/openid-connect-frontchannel-1_0.html) might be helpful. | ||
|
||
## Potential issues | ||
|
||
There are still many open questions that need to be adressed in future MSCs. | ||
This includes: | ||
|
||
- using OAuth 2.0 to authenticate application services | ||
- account management, including active session management | ||
- interactions with widgets and integrations | ||
- 3PID logins | ||
- guest logins | ||
|
||
The current authentication mechanism will be deprecated later on, but a migration period where the two authentication mechanisms cohabit needs to exist. | ||
This is doable in clients but harder to do in servers. | ||
One requirement for a smooth migration is to adopt [MSC2918](https://github.com/matrix-org/matrix-doc/pull/2918). | ||
The migration path and the deprecation of the current APIs will be done in a separate MSC. | ||
|
||
## Alternatives | ||
|
||
None relevant. | ||
hughns marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
## Security considerations | ||
|
||
Since this touches one of the most sensitive part of the API, there a lot of security considerations to have. | ||
The [OAuth 2.0 Security Best Practice](https://tools.ietf.org/html/draft-ietf-oauth-security-topics-16) IETF draft has many attack scenarios. | ||
Many of those scenarios are mitigated by the choices enforced in the client profiles outlined in this MSC. | ||
|
||
## Unstable prefix | ||
|
||
None relevant. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Soru is not sure if these OAuth proposals in their current form work. There are a couple fundamental issues with them:
3.1. OAuth steps are completed on the website --> we execute code to handle our password from the server. The entire point of [WIP] MSC2957: Cryptographically Concealed Credentials #2957 is to not trust the server with this
3.2. We'd need to get the calculated SSSS key from webbrowser to client somehow
An idea would be to use oauth just for sso, and replace
m.login.sso
withm.login.oauth
and introduce UIA to/login
(#2835). While a server could chose to just always use oauth then, instead of "normal" login, this would negate all the extra stuff we would get by using OAuth scopes.Another idea would be to not require a browser / browser-like environment to complete the needed OAuth steps, and (for point 3), not execute any code given by the server for being able to authenticate yourself.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I synced with @sandhose on this last week, as I share some of the same concerns above (and hadn't had a chance to discuss them before these MSCs were written) Taking them point by point:
However, I'm not sure that the right solution is to turn
m.login.sso
intom.login.oauth
and add UIA to/login
. We then end up with both the complexity of UIA and OAuth2 flying around. Instead, how about we aim to have 3 separate login flows: plain login, OAuth (covering all SSO), and cryptologin?The main flaw I see is that we'd need a place to support TOTP-style 2FA such that it works for all flows if configured (it feels suboptimal to make it SSO-only, given cryptologin + 2FA sounds very desirable, for instance)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally sounds good, yes. Another issue would be that with plain login we don't have the scope management.
As for the concerns, the issue is that for TOTP (or basically any other 2fa) we need more back-and-forth communication one way or another. The cryptographic authentication might also require that (while no exact flows are layd out yet in the MSC, a login does require a few requests back-and-forth, though). It seems to soru that the simplest solution for that is adding UIA to
/login
, but yes, i seems like duplicate work.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not entirely convinced by this. Some servers (of which matrix.org will soon be one) allow either username/password or SSO (via social login). If we split username/pass and OAuth into two separate flows, we effectively undo the work we did for social login in presenting the Identity Providers next to the username/password box, since we're now back to "log into matrix.org" (without knowing anything on the client side about what auth mechanisms matrix.org might offer).
Of course that's a problem with OAuth generally, but at least if the username/password mechanism follows the same flow as other logins, we don't get this jarring "username/password" vs "everything else".
There is another problem with Social Login, which is solved by having the server manage the choice of login flow (OAuth-stylee), which is: how to correctly brand login buttons without having to have support for every conceivable brand in every client.
I'm not sure I want to discuss this further here; the point is basically that I think we need to take a hard look at whether what we have designed for Social Login is the right solution, or whether we need to do something more OAuthy.
To pick up a couple of other points:
@Sorunome wrote:
Disagree. I'm not convinced the entry barrier for SSO is any higher than username/pass, since it's just a couple of redirects; the server takes care of most of it. IMHO the reason few clients implement SSO is because there is no need to: few servers currently implement SSO.
@ara4n wrote
except it's not, is it? It only solves it for servers which choose to offer a username/password flow, with no 2FA? That might work for specific deployments, but it doesn't sound like a general solution.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@richvdh
I think the issue here is not really the code needed to do the requests but actually that there might be a webpage to be displayed to do the actual SSO. Which usually tends to be hard for native desktop apps and TUI clients as those have a harder time communicating with a browser (and with those that do js sometimes even). Thats in my opinion the main challenge of SSO currently. Though if OAuth gives token/code based auth (as google does it for example) this would be an upgrade and make this easier. (google shows you a token a user can easily copy from their browser so the client doesnt need to spin up a local server to redirect too or similar).
Also I agree with @richvdh on the embedding part (basicly what I said above).
I overall do like having oauth in the spec as a main login thing but I have the feeling in the current proposal it either breaks many clients and servers at once or atleast clutters the login process. I personally like the feature proposed but not the way it is implemented. Though I cannot offer another solution to this.