From ab50b622eb647ea2c9627d3ce861f354ca52a7c3 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Fri, 18 Dec 2020 14:40:37 +0100 Subject: [PATCH 01/22] Refresh tokens MSC --- proposals/2918-refreshtokens.md | 67 +++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 proposals/2918-refreshtokens.md diff --git a/proposals/2918-refreshtokens.md b/proposals/2918-refreshtokens.md new file mode 100644 index 00000000000..e9a928c8440 --- /dev/null +++ b/proposals/2918-refreshtokens.md @@ -0,0 +1,67 @@ +# MSC2918: Refresh tokens + +Requests are currently authenticated using non-expiring, revocable access tokens. +This goes against security best practices known in the OAuth2 world. +This MSC make the access tokens expiring and introduces refresh tokens to renew them to fight against token replay attacks. + +## Proposal + +The access token returned by the login endpoint expires after a short amount of time, forcing the client to renew it with a refresh token. +A refresh token is issued on login and rotates on each usage. + +Homeservers can choose to make the access tokens signed and non-revocable for performance reasons if the expiration is short enough (less than 5 minutes). + +### Login API changes + +The login API returns two additional fields: + +- `expires_in`: The lifetime in seconds of the access token. +- `refresh_token`: The refresh token, which can be used to obtain new access tokens. + +### Token refresh API + +This API lets the client refresh the access token. +A new refresh token is also issued, and the existing one is revoked. +The Matrix server doesn't have to make the old access token invalid, since its lifetime is short enough. + +`POST /refresh` + +```json +{ + "refresh_token": "aaaabbbbccccdddd" +} +``` + +response: + +```json +{ + "access_token": "xxxxyyyyzzz", + "expires_in": 60, + "refresh_token": "eeeeffffgggghhhh" +} +``` + +### Device handling + +The current spec states that "Matrix servers should record which device each access token is assigned to". +This must be updated to reflect that devices are bound to a session, which are created during login and stays the same one after refreshing the token. + +## Potential issues + +The refresh token being rotated on each refresh is strongly recommended in the OAuth2 world for unauthenticated clients to avoid token replay attacks. +This can however make the deployment of CLI tools for Matrix a bit harder, since the credentials can't be statically defined anymore. +This is not an issue in OAuth2 because usually CLI tools use the client credentials flow, also known as service accounts. +An alternative would be to make the refresh token non-rotating for now but recommend clients to support rotation of refresh tokens and enforce it later on. + +## Alternatives + +This MSC defines a new endpoint for token refresh, but it could also be integrated as a new authentication mechanism. + +## Security considerations + +TBD + +## Unstable prefix + +TBD From f8dad2acd6b554c331793cc642c9155542f5b8c7 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Thu, 14 Jan 2021 17:34:10 +0100 Subject: [PATCH 02/22] MSC2918: minor changes --- proposals/2918-refreshtokens.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/proposals/2918-refreshtokens.md b/proposals/2918-refreshtokens.md index e9a928c8440..09e2ccdcd66 100644 --- a/proposals/2918-refreshtokens.md +++ b/proposals/2918-refreshtokens.md @@ -1,7 +1,7 @@ # MSC2918: Refresh tokens Requests are currently authenticated using non-expiring, revocable access tokens. -This goes against security best practices known in the OAuth2 world. +This goes against security best practices known in the OAuth 2.0 world. This MSC make the access tokens expiring and introduces refresh tokens to renew them to fight against token replay attacks. ## Proposal @@ -24,7 +24,7 @@ This API lets the client refresh the access token. A new refresh token is also issued, and the existing one is revoked. The Matrix server doesn't have to make the old access token invalid, since its lifetime is short enough. -`POST /refresh` +`POST /_matrix/client/r0/refresh` ```json { @@ -49,9 +49,9 @@ This must be updated to reflect that devices are bound to a session, which are c ## Potential issues -The refresh token being rotated on each refresh is strongly recommended in the OAuth2 world for unauthenticated clients to avoid token replay attacks. +The refresh token being rotated on each refresh is strongly recommended in the OAuth 2.0 world for unauthenticated clients to avoid token replay attacks. This can however make the deployment of CLI tools for Matrix a bit harder, since the credentials can't be statically defined anymore. -This is not an issue in OAuth2 because usually CLI tools use the client credentials flow, also known as service accounts. +This is not an issue in OAuth 2.0 because usually CLI tools use the client credentials flow, also known as service accounts. An alternative would be to make the refresh token non-rotating for now but recommend clients to support rotation of refresh tokens and enforce it later on. ## Alternatives @@ -60,8 +60,11 @@ This MSC defines a new endpoint for token refresh, but it could also be integrat ## Security considerations -TBD +The time to live (TTL) of access tokens isn't enforced in this MSC but is advised to be kept relatively short. +Servers might choose to have stateless, digitally signed access tokens (JWT are good examples of this), which makes them non-revocable. +The TTL of access tokens should not exceed 15 minutes if they are revocable and 5 minutes if they are not. ## Unstable prefix -TBD +While this MSC is not in a released version of the specification, clients should add a `org.matrix.msc2918.refresh_token=true` query parameter on the login endpoint, e.g. `/_matrix/client/r0/login?org.matrix.msc2918.refresh_token=true`. +The refresh token endpoint should be served and used using the unstable prefix: `POST /_matrix/client/unstable/org.matrix.msc2918/refresh`. From 0e615f78757ac2cb8bafacd2eba69deac00f6967 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Thu, 20 May 2021 12:09:37 +0200 Subject: [PATCH 03/22] MSC2918: access token expiration as milliseconds --- proposals/2918-refreshtokens.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proposals/2918-refreshtokens.md b/proposals/2918-refreshtokens.md index 09e2ccdcd66..f68964c308b 100644 --- a/proposals/2918-refreshtokens.md +++ b/proposals/2918-refreshtokens.md @@ -15,7 +15,7 @@ Homeservers can choose to make the access tokens signed and non-revocable for pe The login API returns two additional fields: -- `expires_in`: The lifetime in seconds of the access token. +- `expires_in_ms`: The lifetime in milliseconds of the access token. - `refresh_token`: The refresh token, which can be used to obtain new access tokens. ### Token refresh API @@ -37,7 +37,7 @@ response: ```json { "access_token": "xxxxyyyyzzz", - "expires_in": 60, + "expires_in_ms": 60, "refresh_token": "eeeeffffgggghhhh" } ``` From 870cded27cd623e5f212feea02d7b77e9c56fe00 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Thu, 20 May 2021 12:10:13 +0200 Subject: [PATCH 04/22] MSC2918: account registration API changes --- proposals/2918-refreshtokens.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/proposals/2918-refreshtokens.md b/proposals/2918-refreshtokens.md index f68964c308b..e6c0639d968 100644 --- a/proposals/2918-refreshtokens.md +++ b/proposals/2918-refreshtokens.md @@ -18,6 +18,14 @@ The login API returns two additional fields: - `expires_in_ms`: The lifetime in milliseconds of the access token. - `refresh_token`: The refresh token, which can be used to obtain new access tokens. + +### Account registration API changes + +Unless `inhibit_login` is `true`, the account registration API returns two additional fields: + +- `expires_in_ms`: The lifetime in milliseconds of the access token. +- `refresh_token`: The refresh token, which can be used to obtain new access tokens. + ### Token refresh API This API lets the client refresh the access token. @@ -45,7 +53,7 @@ response: ### Device handling The current spec states that "Matrix servers should record which device each access token is assigned to". -This must be updated to reflect that devices are bound to a session, which are created during login and stays the same one after refreshing the token. +This must be updated to reflect that devices are bound to a session, which are created during login and stays the same after refreshing the token. ## Potential issues From 6530eccefe95ace7d651fb5c36cfcc3dc1c012d8 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Thu, 20 May 2021 12:13:28 +0200 Subject: [PATCH 05/22] MSC2918: fix `expires_in_ms` example --- proposals/2918-refreshtokens.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/2918-refreshtokens.md b/proposals/2918-refreshtokens.md index e6c0639d968..128e8f35bac 100644 --- a/proposals/2918-refreshtokens.md +++ b/proposals/2918-refreshtokens.md @@ -45,7 +45,7 @@ response: ```json { "access_token": "xxxxyyyyzzz", - "expires_in_ms": 60, + "expires_in_ms": 60000, "refresh_token": "eeeeffffgggghhhh" } ``` From b320001eb431e4bc0896095f302c9d2fc6c1bcd6 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Thu, 3 Jun 2021 16:22:46 +0200 Subject: [PATCH 06/22] MSC2918: add precision about token revocation --- proposals/2918-refreshtokens.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/proposals/2918-refreshtokens.md b/proposals/2918-refreshtokens.md index 128e8f35bac..ba8545100ab 100644 --- a/proposals/2918-refreshtokens.md +++ b/proposals/2918-refreshtokens.md @@ -30,7 +30,8 @@ Unless `inhibit_login` is `true`, the account registration API returns two addit This API lets the client refresh the access token. A new refresh token is also issued, and the existing one is revoked. -The Matrix server doesn't have to make the old access token invalid, since its lifetime is short enough. +Since this request can get lost in flight, the server should delay this revocation to when the client uses the new access token or the new refresh token for the first time. +The Matrix server can but does not have to make the old access token invalid, since its lifetime is short enough. `POST /_matrix/client/r0/refresh` From d433e3b7f19c771411a2a2098fab8cc765d85bf6 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Thu, 3 Jun 2021 16:26:29 +0200 Subject: [PATCH 07/22] MSC2918: specify error codes for the refresh API --- proposals/2918-refreshtokens.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/proposals/2918-refreshtokens.md b/proposals/2918-refreshtokens.md index ba8545100ab..f9aaebd5f44 100644 --- a/proposals/2918-refreshtokens.md +++ b/proposals/2918-refreshtokens.md @@ -51,6 +51,14 @@ response: } ``` +The `refresh_token` parameter can be invalid for two reasons: + + - if it does not exist + - if it was already used once + +In both cases, the server must reply with a `401` HTTP status code and an `M_UNKNOWN_TOKEN` error code. +This new use case of the `M_UNKNOWN_TOKEN` error code must be reflected in the spec. + ### Device handling The current spec states that "Matrix servers should record which device each access token is assigned to". From 87566c3217b44512e5dd41543ffe05d066c75e12 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Thu, 3 Jun 2021 16:35:45 +0200 Subject: [PATCH 08/22] MSC2918: clarify that the change also applies to ASes --- proposals/2918-refreshtokens.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/proposals/2918-refreshtokens.md b/proposals/2918-refreshtokens.md index f9aaebd5f44..13f382eea60 100644 --- a/proposals/2918-refreshtokens.md +++ b/proposals/2918-refreshtokens.md @@ -18,6 +18,7 @@ The login API returns two additional fields: - `expires_in_ms`: The lifetime in milliseconds of the access token. - `refresh_token`: The refresh token, which can be used to obtain new access tokens. +This also applies to logins done by application services. ### Account registration API changes @@ -26,6 +27,8 @@ Unless `inhibit_login` is `true`, the account registration API returns two addit - `expires_in_ms`: The lifetime in milliseconds of the access token. - `refresh_token`: The refresh token, which can be used to obtain new access tokens. +This also applies to registrations done by application services. + ### Token refresh API This API lets the client refresh the access token. From 269fcac2ba61a8212459c60b8682f5a1557940ed Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Thu, 1 Jul 2021 12:17:06 +0200 Subject: [PATCH 09/22] Apply suggestions from code review Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> --- proposals/2918-refreshtokens.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/proposals/2918-refreshtokens.md b/proposals/2918-refreshtokens.md index 13f382eea60..2543a877b71 100644 --- a/proposals/2918-refreshtokens.md +++ b/proposals/2918-refreshtokens.md @@ -1,8 +1,8 @@ # MSC2918: Refresh tokens -Requests are currently authenticated using non-expiring, revocable access tokens. +In Matrix, requests to the Client-Server API are currently authenticated using non-expiring, revocable access tokens. This goes against security best practices known in the OAuth 2.0 world. -This MSC make the access tokens expiring and introduces refresh tokens to renew them to fight against token replay attacks. +This MSC adds support for expiring access tokens and introduces refresh tokens to renew them. ## Proposal @@ -32,8 +32,7 @@ This also applies to registrations done by application services. ### Token refresh API This API lets the client refresh the access token. -A new refresh token is also issued, and the existing one is revoked. -Since this request can get lost in flight, the server should delay this revocation to when the client uses the new access token or the new refresh token for the first time. +A new refresh token is also issued. The existing refresh token remains valid until the new access token (or refresh token) is used, at which point it is revoked. This allows for the request getting lost in flight. The Matrix server can but does not have to make the old access token invalid, since its lifetime is short enough. `POST /_matrix/client/r0/refresh` From 4d73b7ea69c98667754f7069a1b58b8a31ef78b9 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Thu, 15 Jul 2021 18:34:50 +0200 Subject: [PATCH 10/22] MSC2918: clarify what problem this MSC solves --- proposals/2918-refreshtokens.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/proposals/2918-refreshtokens.md b/proposals/2918-refreshtokens.md index 2543a877b71..2d29607d631 100644 --- a/proposals/2918-refreshtokens.md +++ b/proposals/2918-refreshtokens.md @@ -1,7 +1,13 @@ # MSC2918: Refresh tokens In Matrix, requests to the Client-Server API are currently authenticated using non-expiring, revocable access tokens. -This goes against security best practices known in the OAuth 2.0 world. +An access token might leak for various reasons, including: + + - leaking from the server database (and its backups) + - intercepting it with a man-in-the-middle attack + - leaking from the client storage (and its backups) + +In the OAuth 2.0 world, this vector of attack is partly mitigated by having expiring access tokens with short lifetimes and rotating refresh tokens to renew them. This MSC adds support for expiring access tokens and introduces refresh tokens to renew them. ## Proposal From db8ceab7359b2cf96006811c59c426dbddf7bf66 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Thu, 15 Jul 2021 18:35:23 +0200 Subject: [PATCH 11/22] MSC2918: minor formatting and rephrasing --- proposals/2918-refreshtokens.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/proposals/2918-refreshtokens.md b/proposals/2918-refreshtokens.md index 2d29607d631..43e90d8f6fb 100644 --- a/proposals/2918-refreshtokens.md +++ b/proposals/2918-refreshtokens.md @@ -15,7 +15,7 @@ This MSC adds support for expiring access tokens and introduces refresh tokens t The access token returned by the login endpoint expires after a short amount of time, forcing the client to renew it with a refresh token. A refresh token is issued on login and rotates on each usage. -Homeservers can choose to make the access tokens signed and non-revocable for performance reasons if the expiration is short enough (less than 5 minutes). +Homeservers can choose to use signed and non-revocable access tokens (JWTs, Macaroon, etc.) for performance reasons if their expiration is short enough (less than 5 minutes). ### Login API changes @@ -38,8 +38,10 @@ This also applies to registrations done by application services. ### Token refresh API This API lets the client refresh the access token. -A new refresh token is also issued. The existing refresh token remains valid until the new access token (or refresh token) is used, at which point it is revoked. This allows for the request getting lost in flight. -The Matrix server can but does not have to make the old access token invalid, since its lifetime is short enough. +A new refresh token is also issued. +The existing refresh token remains valid until the new access token (or refresh token) is used, at which point it is revoked. +This allows for the request to get lost in flight. +The Matrix server can revoke the old access token right away, but does not have to since its lifetime is short enough that it will expire anyway soon after. `POST /_matrix/client/r0/refresh` From 9bbb4c5616dced1dc302b038a406e823898db434 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Thu, 15 Jul 2021 18:36:04 +0200 Subject: [PATCH 12/22] MSC2918: clarify ratelimiting, masquerading and authentication on refresh token API --- proposals/2918-refreshtokens.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/proposals/2918-refreshtokens.md b/proposals/2918-refreshtokens.md index 43e90d8f6fb..6b2fc2b6057 100644 --- a/proposals/2918-refreshtokens.md +++ b/proposals/2918-refreshtokens.md @@ -69,6 +69,9 @@ The `refresh_token` parameter can be invalid for two reasons: In both cases, the server must reply with a `401` HTTP status code and an `M_UNKNOWN_TOKEN` error code. This new use case of the `M_UNKNOWN_TOKEN` error code must be reflected in the spec. +This new API should be rate-limited and does not require authentication since only the `refresh_token` parameter is needed. +Identity assertion via the `user_id` query parameter as defined by the Application Service API specification is disabled on this endpoint. + ### Device handling The current spec states that "Matrix servers should record which device each access token is assigned to". From a050dc3a17cb50554ff11423d09ccdc75ae6975e Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Thu, 15 Jul 2021 19:22:36 +0200 Subject: [PATCH 13/22] MSC2918: make expires_in_ms/refresh_token optional --- proposals/2918-refreshtokens.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/proposals/2918-refreshtokens.md b/proposals/2918-refreshtokens.md index 6b2fc2b6057..dc29338ad65 100644 --- a/proposals/2918-refreshtokens.md +++ b/proposals/2918-refreshtokens.md @@ -26,6 +26,10 @@ The login API returns two additional fields: This also applies to logins done by application services. +Both fields are optional. +If `expires_in_ms` is missing, the client can assume the access token won't expire. +If `refresh_token` is missing but `expires_in_ms` is present, the client can assume the access token will expire but it won't have a way to refresh the access token without re-logging in. + ### Account registration API changes Unless `inhibit_login` is `true`, the account registration API returns two additional fields: @@ -35,6 +39,8 @@ Unless `inhibit_login` is `true`, the account registration API returns two addit This also applies to registrations done by application services. +As in the login API, both field are optional. + ### Token refresh API This API lets the client refresh the access token. @@ -61,6 +67,8 @@ response: } ``` +If the `refresh_token` is missing from the response, the client can assume the refresh token has not changed and use the same token in subsequent token refresh API requests. + The `refresh_token` parameter can be invalid for two reasons: - if it does not exist From 2c11e6f8306d45d66b28c336339172a37fb6a97a Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Thu, 15 Jul 2021 19:24:10 +0200 Subject: [PATCH 14/22] MSC2918: soft logout in refresh token API --- proposals/2918-refreshtokens.md | 1 + 1 file changed, 1 insertion(+) diff --git a/proposals/2918-refreshtokens.md b/proposals/2918-refreshtokens.md index dc29338ad65..e4ff8f863a2 100644 --- a/proposals/2918-refreshtokens.md +++ b/proposals/2918-refreshtokens.md @@ -76,6 +76,7 @@ The `refresh_token` parameter can be invalid for two reasons: In both cases, the server must reply with a `401` HTTP status code and an `M_UNKNOWN_TOKEN` error code. This new use case of the `M_UNKNOWN_TOKEN` error code must be reflected in the spec. +As with other endpoints, the server can include an extra `soft_logout` parameter in the response to signify the client it should do a soft logout. This new API should be rate-limited and does not require authentication since only the `refresh_token` parameter is needed. Identity assertion via the `user_id` query parameter as defined by the Application Service API specification is disabled on this endpoint. From 4cd94e3ab43c2402fd0facc07487a8ba909b5789 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Thu, 12 Aug 2021 19:24:55 +0200 Subject: [PATCH 15/22] MSC2918: add detailed rationale While not exhaustive, it outlines a few attack vectors this MSC tries to mitigate. --- proposals/2918-refreshtokens.md | 40 +++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/proposals/2918-refreshtokens.md b/proposals/2918-refreshtokens.md index e4ff8f863a2..b82c9f69748 100644 --- a/proposals/2918-refreshtokens.md +++ b/proposals/2918-refreshtokens.md @@ -9,6 +9,7 @@ An access token might leak for various reasons, including: In the OAuth 2.0 world, this vector of attack is partly mitigated by having expiring access tokens with short lifetimes and rotating refresh tokens to renew them. This MSC adds support for expiring access tokens and introduces refresh tokens to renew them. +A more [detailed rationale](#detailed-rationale) of what kind of attacks it mitigates lives at the end of this document. ## Proposal @@ -107,3 +108,42 @@ The TTL of access tokens should not exceed 15 minutes if they are revocable and While this MSC is not in a released version of the specification, clients should add a `org.matrix.msc2918.refresh_token=true` query parameter on the login endpoint, e.g. `/_matrix/client/r0/login?org.matrix.msc2918.refresh_token=true`. The refresh token endpoint should be served and used using the unstable prefix: `POST /_matrix/client/unstable/org.matrix.msc2918/refresh`. + +## Detailed rationale + +This MSC does not aim to protect against a completely compromised client. +More specifically, it does not protect against an attacker that managed to distribute an alternate, compromised version of the client to users. +In contrast, it protects against a whole range of attacks where the access token and/or refresh token get leaked but the client isn't completely compromised. + +For example, those tokens can leak from user backups (user backs up his device on a NAS, the NAS gets compromised and leaks a backup of the client's secret storage), but one can assume those backups could be at least 5 min old. +If the leak only includes the access token, it is useless to the attacker since it would have expired. +If it also includes the refresh token, it is useless *if* the token was refreshed before (which will happen if the user just opens their Matrix client in between). + +Worst case scenario, the leaked refresh token is still valid: in this case, the attacker would consume the refresh token to get a valid access token, but when the original client tries to use the same refresh token, the homeserver can detect it, consider the session has been compromised, end the session and warn the user. + +This kind of attack also applies to leakage from the server, which could happen from database backups, for example. + +The important thing here is while it does not completely prevent attacks in case of a token leakage, it does make this range of attack a lot more time-sensitive and detectable. +A homeserver will notice if a refresh token is being used twice. + +The IETF has interesting [guidelines for refresh tokens](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics#section-4.13.2). +They recommend that either: + + - the refresh tokens are sender-bound and require client authentication (making token leakage completely useless if the client credentials are not leaked at the same time) + - or make them rotate to make the attack a lot harder, as described just above. + +Since all clients are "public" in the Matrix world, there are no client-bound credentials that could be used, hence the rotation of refresh tokens. + +--- + +The other kind of scenario where this change makes sense is to help further changes in the homeservers. +A good, recent example of this, is in Synapse v1.34.0 [they moved away from macaroons for access tokens](https://github.com/matrix-org/synapse/pull/5588) to random, shorter, saved in database tokens, similar to [what GitHub did recently](https://github.blog/2021-04-05-behind-githubs-new-authentication-token-formats/). + +Because there is no refresh token mechanism in the C2S API, most Synapse instances now have a mix of the two formats of tokens, and for a long time. +It makes it impossible to enforce the new format of tokens without invalidating all existing sessions, making it impossible to roll out changes like a web-app firewall in front of Synapse that verifies the shape and checksums of tokens even before reaching Synapse. + +--- + +Lastly, expiring tokens already exist in Synapse (via the `session_lifetime` configuration parameter). +Before this MSC, clients had no idea when the session would end and relied on the server replying with a 401 error with `soft_logout: true` in the response on a random request to trigger a soft logout and go through the authentication process again. +A side effect of this MSC (although it could have been introduced separately) is that the login responses can now include a `expires_in_ms` to inform the clients when the token will expire. From 04ae1c373a62f65bd685d6e39b8dc4cbe74fac86 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Fri, 13 Aug 2021 00:30:43 +0200 Subject: [PATCH 16/22] MSC2918: minor fix Co-authored-by: Hubert Chathi --- proposals/2918-refreshtokens.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/2918-refreshtokens.md b/proposals/2918-refreshtokens.md index b82c9f69748..aa8265ed470 100644 --- a/proposals/2918-refreshtokens.md +++ b/proposals/2918-refreshtokens.md @@ -106,7 +106,7 @@ The TTL of access tokens should not exceed 15 minutes if they are revocable and ## Unstable prefix -While this MSC is not in a released version of the specification, clients should add a `org.matrix.msc2918.refresh_token=true` query parameter on the login endpoint, e.g. `/_matrix/client/r0/login?org.matrix.msc2918.refresh_token=true`. +While this MSC is not in a released version of the specification, clients should add a `org.matrix.msc2918.refresh_token=true` query parameter on the login and registration endpoints, e.g. `/_matrix/client/r0/login?org.matrix.msc2918.refresh_token=true`. The refresh token endpoint should be served and used using the unstable prefix: `POST /_matrix/client/unstable/org.matrix.msc2918/refresh`. ## Detailed rationale From 488e9e1a87b80824ea0a62fd552d784731a09ea1 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Thu, 9 Sep 2021 23:29:32 +0200 Subject: [PATCH 17/22] MSC2918: clarifications on backward compatibility --- proposals/2918-refreshtokens.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/proposals/2918-refreshtokens.md b/proposals/2918-refreshtokens.md index aa8265ed470..1d3ad9e5d0e 100644 --- a/proposals/2918-refreshtokens.md +++ b/proposals/2918-refreshtokens.md @@ -13,10 +13,11 @@ A more [detailed rationale](#detailed-rationale) of what kind of attacks it miti ## Proposal -The access token returned by the login endpoint expires after a short amount of time, forcing the client to renew it with a refresh token. +Homeservers can choose to have access tokens returned by the registration and login endpoints after a short amount of time, forcing the client to renew it with a refresh token. A refresh token is issued on login and rotates on each usage. -Homeservers can choose to use signed and non-revocable access tokens (JWTs, Macaroon, etc.) for performance reasons if their expiration is short enough (less than 5 minutes). +It allows homeservers to opt for signed and non-revocable access tokens (JWTs, Macaroon, etc.) for performance reasons if their expiration is short enough (less than 5 minutes). +Whether the access token expire and what lifetime they have is up to the homeserver, but client have to support refreshing tokens. ### Login API changes @@ -109,6 +110,8 @@ The TTL of access tokens should not exceed 15 minutes if they are revocable and While this MSC is not in a released version of the specification, clients should add a `org.matrix.msc2918.refresh_token=true` query parameter on the login and registration endpoints, e.g. `/_matrix/client/r0/login?org.matrix.msc2918.refresh_token=true`. The refresh token endpoint should be served and used using the unstable prefix: `POST /_matrix/client/unstable/org.matrix.msc2918/refresh`. +Once this MSC is in a released version of the specification, clients using endpoints from that version must support refreshing token, even if the homeserver might choose to keep sending non-refreshing ones. + ## Detailed rationale This MSC does not aim to protect against a completely compromised client. From 4cf821c7c2339b6a46676c0a8b92b1593e8850a9 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Fri, 10 Sep 2021 14:18:50 +0200 Subject: [PATCH 18/22] MSC2918: advertise support in the request body --- proposals/2918-refreshtokens.md | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/proposals/2918-refreshtokens.md b/proposals/2918-refreshtokens.md index 1d3ad9e5d0e..72a275ab76d 100644 --- a/proposals/2918-refreshtokens.md +++ b/proposals/2918-refreshtokens.md @@ -13,12 +13,18 @@ A more [detailed rationale](#detailed-rationale) of what kind of attacks it miti ## Proposal -Homeservers can choose to have access tokens returned by the registration and login endpoints after a short amount of time, forcing the client to renew it with a refresh token. +Homeservers can choose to have access tokens expire after a short amount of time, forcing the client to renew them with a refresh token. A refresh token is issued on login and rotates on each usage. It allows homeservers to opt for signed and non-revocable access tokens (JWTs, Macaroon, etc.) for performance reasons if their expiration is short enough (less than 5 minutes). Whether the access token expire and what lifetime they have is up to the homeserver, but client have to support refreshing tokens. +It is heavily recommended for clients to support refreshing tokens for additional security. +They can advertise their support by adding a `"refresh_token": true` field in the request body on the `/login` and `/register` APIs. + +Handling of clients that do *not* support refreshing access tokens is up to individual homeserver deployments. +For example, server administrators may choose to support such clients for backwards-compatibility, or to expire access tokens anyway for improved security at the cost of inferior user experience in legacy clients. + ### Login API changes The login API returns two additional fields: @@ -32,6 +38,8 @@ Both fields are optional. If `expires_in_ms` is missing, the client can assume the access token won't expire. If `refresh_token` is missing but `expires_in_ms` is present, the client can assume the access token will expire but it won't have a way to refresh the access token without re-logging in. +Clients advertise their support for refreshing tokens by setting the `refresh_token` field to `true` in the request body. + ### Account registration API changes Unless `inhibit_login` is `true`, the account registration API returns two additional fields: @@ -43,6 +51,8 @@ This also applies to registrations done by application services. As in the login API, both field are optional. +Clients advertise their support for refreshing tokens by setting the `refresh_token` field to `true` in the request body. + ### Token refresh API This API lets the client refresh the access token. @@ -103,15 +113,13 @@ This MSC defines a new endpoint for token refresh, but it could also be integrat The time to live (TTL) of access tokens isn't enforced in this MSC but is advised to be kept relatively short. Servers might choose to have stateless, digitally signed access tokens (JWT are good examples of this), which makes them non-revocable. -The TTL of access tokens should not exceed 15 minutes if they are revocable and 5 minutes if they are not. +The TTL of access tokens should be around 15 minutes if they are revocable and should not exceed 5 minutes if they are not. ## Unstable prefix -While this MSC is not in a released version of the specification, clients should add a `org.matrix.msc2918.refresh_token=true` query parameter on the login and registration endpoints, e.g. `/_matrix/client/r0/login?org.matrix.msc2918.refresh_token=true`. +While this MSC is not in a released version of the specification, clients should use the `org.matrix.msc2918.refresh_token` field in place of the `refresh_token` field in requests to the login and registration endpoints. The refresh token endpoint should be served and used using the unstable prefix: `POST /_matrix/client/unstable/org.matrix.msc2918/refresh`. -Once this MSC is in a released version of the specification, clients using endpoints from that version must support refreshing token, even if the homeserver might choose to keep sending non-refreshing ones. - ## Detailed rationale This MSC does not aim to protect against a completely compromised client. From c0767632c83e97f7af3204525e73953de0268c16 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Fri, 10 Sep 2021 14:26:47 +0200 Subject: [PATCH 19/22] MSC2918: clarify on what happen when token expire --- proposals/2918-refreshtokens.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/proposals/2918-refreshtokens.md b/proposals/2918-refreshtokens.md index 72a275ab76d..7a6768c0862 100644 --- a/proposals/2918-refreshtokens.md +++ b/proposals/2918-refreshtokens.md @@ -25,6 +25,10 @@ They can advertise their support by adding a `"refresh_token": true` field in th Handling of clients that do *not* support refreshing access tokens is up to individual homeserver deployments. For example, server administrators may choose to support such clients for backwards-compatibility, or to expire access tokens anyway for improved security at the cost of inferior user experience in legacy clients. +If a client uses an access token that has expired, the server will respond with an `M_UNKNOWN_TOKEN` error. +Thus, if a client receives an `M_UNKNOWN_TOKEN` error, and it has a refresh token available, it should no longer assume that it has been logged out, and instead attempt to refresh the token. +If the client was in fact logged out, then the server will respond with an `M_UNKNOWN_TOKEN` error, possibly with the `soft_logout` parameter set. + ### Login API changes The login API returns two additional fields: From a157cc358d083abc0ba72248418ad74f399f208a Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Thu, 23 Sep 2021 14:52:40 +0200 Subject: [PATCH 20/22] MSC2918: remove redundant precision about token expiration and lifetime Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> --- proposals/2918-refreshtokens.md | 1 - 1 file changed, 1 deletion(-) diff --git a/proposals/2918-refreshtokens.md b/proposals/2918-refreshtokens.md index 7a6768c0862..6bfc8c5aadb 100644 --- a/proposals/2918-refreshtokens.md +++ b/proposals/2918-refreshtokens.md @@ -17,7 +17,6 @@ Homeservers can choose to have access tokens expire after a short amount of time A refresh token is issued on login and rotates on each usage. It allows homeservers to opt for signed and non-revocable access tokens (JWTs, Macaroon, etc.) for performance reasons if their expiration is short enough (less than 5 minutes). -Whether the access token expire and what lifetime they have is up to the homeserver, but client have to support refreshing tokens. It is heavily recommended for clients to support refreshing tokens for additional security. They can advertise their support by adding a `"refresh_token": true` field in the request body on the `/login` and `/register` APIs. From ed542131c8ec6b4741940057231364d2496920d1 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Thu, 23 Sep 2021 14:56:12 +0200 Subject: [PATCH 21/22] MSC2918: minor clarification --- proposals/2918-refreshtokens.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/2918-refreshtokens.md b/proposals/2918-refreshtokens.md index 6bfc8c5aadb..e11585c0b9f 100644 --- a/proposals/2918-refreshtokens.md +++ b/proposals/2918-refreshtokens.md @@ -26,7 +26,7 @@ For example, server administrators may choose to support such clients for backwa If a client uses an access token that has expired, the server will respond with an `M_UNKNOWN_TOKEN` error. Thus, if a client receives an `M_UNKNOWN_TOKEN` error, and it has a refresh token available, it should no longer assume that it has been logged out, and instead attempt to refresh the token. -If the client was in fact logged out, then the server will respond with an `M_UNKNOWN_TOKEN` error, possibly with the `soft_logout` parameter set. +If the client was in fact logged out, then the server will respond with an `M_UNKNOWN_TOKEN` error to the token refresh request, possibly with the `soft_logout` parameter set. ### Login API changes From 70b2dfcde2f087c4c2e9eea33792e0b13a64e0e9 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Thu, 23 Sep 2021 16:47:47 +0200 Subject: [PATCH 22/22] MSC2918: soft logout when using expired token --- proposals/2918-refreshtokens.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/2918-refreshtokens.md b/proposals/2918-refreshtokens.md index e11585c0b9f..8caaef8fa6d 100644 --- a/proposals/2918-refreshtokens.md +++ b/proposals/2918-refreshtokens.md @@ -24,7 +24,7 @@ They can advertise their support by adding a `"refresh_token": true` field in th Handling of clients that do *not* support refreshing access tokens is up to individual homeserver deployments. For example, server administrators may choose to support such clients for backwards-compatibility, or to expire access tokens anyway for improved security at the cost of inferior user experience in legacy clients. -If a client uses an access token that has expired, the server will respond with an `M_UNKNOWN_TOKEN` error. +If a client uses an access token that has expired, the server will respond with an `M_UNKNOWN_TOKEN` error, preferably with the `soft_logout` parameter set to `true` to improve the user experience in legacy clients. Thus, if a client receives an `M_UNKNOWN_TOKEN` error, and it has a refresh token available, it should no longer assume that it has been logged out, and instead attempt to refresh the token. If the client was in fact logged out, then the server will respond with an `M_UNKNOWN_TOKEN` error to the token refresh request, possibly with the `soft_logout` parameter set.