Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Document the usage of refresh tokens. #11427

Merged
merged 13 commits into from
Dec 8, 2021
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/11427.doc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Document the usage of refresh tokens.
1 change: 1 addition & 0 deletions docs/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
- [SSO Mapping Providers](sso_mapping_providers.md)
- [Password Auth Providers](password_auth_providers.md)
- [JSON Web Tokens](jwt.md)
- [Refresh Tokens](usage/configuration/user_authentication/refresh_tokens.md)
- [Registration Captcha](CAPTCHA_SETUP.md)
- [Application Services](application_services.md)
- [Server Notices](server_notices.md)
Expand Down
124 changes: 124 additions & 0 deletions docs/usage/configuration/user_authentication/refresh_tokens.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# Refresh Tokens

Synapse supports refresh tokens since version 1.49 (some earlier versions had support for an earlier, experimental draft of [MSC2918] which is not compatible).


[MSC2918]: https://github.com/matrix-org/matrix-doc/blob/main/proposals/2918-refreshtokens.md#msc2918-refresh-tokens


## Background and motivation

Synapse users' sessions are identified by **access tokens**; access tokens are
issued to users on login and the access token is then used to identify the user
and device making subsequent requests.
DMRobertson marked this conversation as resolved.
Show resolved Hide resolved

Traditionally, these access tokens were eternally valid (at least until the user
explicitly chose to log out).

In some cases, it may be desirable for these access tokens to expire so that the
potential damage caused by leaking an access token is reduced.
On the other hand, forcing a user to re-authenticate (log in again) often might
be too much of an inconvenience.

**Refresh tokens** are a mechanism to avoid some of this inconvenience whilst
still getting most of the benefits of short access token lifetimes.
DMRobertson marked this conversation as resolved.
Show resolved Hide resolved

When refresh tokens are in use, both an access token and a refresh token will be
issued to users on login. The access token will expire after a predetermined amount
of time, but otherwise works in the same way as before. When the access token is
close to expiring (or has expired), the user's client should present the homeserver
(Synapse) with the refresh token.

The homeserver will then generate a new access token and refresh token for the user
and return them. The old refresh token is invalidated and can not be used again*.

Finally, refresh tokens also make it possible for sessions to be logged out if they
are inactive for too long; see the configuration guide below.
DMRobertson marked this conversation as resolved.
Show resolved Hide resolved


*To prevent issues if clients lose connection half-way through refreshing a token,
DMRobertson marked this conversation as resolved.
Show resolved Hide resolved
the refresh token is only invalidated once the new access token has been used at
least once. For all intents and purposes, the above simplification is sufficient.


## Caveats

There are some caveats:

* If a third party gets both your access token and refresh token, they will be able to
continue to enjoy access to your session.
* This is still an improvement because you (the user) will notice when *your*
session expires and you're not able to use your refresh token.
That would be a giveaway that someone else has compromised your session.
You would be able to log in again and terminate that session.
DMRobertson marked this conversation as resolved.
Show resolved Hide resolved
Previously (with long-length access tokens), a third party that has your access
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest "duration" rather than "length" to avoid confusion with a string length

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or long-lived as below.

Presumably both these terms refer to finite, but large expiry times, rather than no expiry at all?

token could go undetected for a very long time.
* Clients need to implement support for refresh tokens in order for them to be a
useful mechanism.
* It is up to homeserver administrators if they want to issue long-lived access
tokens to clients not implementing refresh tokens.
DMRobertson marked this conversation as resolved.
Show resolved Hide resolved
* For compatibility, it is likely that they should at least until client support
is widespread.
* Users with clients that support refresh tokens will still benefit from the
added security; it's not possible to downgrade a session to using long-lived
access tokens so this effectively gives users the choice.
* In a closed environment where all users use known clients, this may not be
an issue as the homeserver administrator can know if the clients have refresh
token support.


## Configuration Guide

The following configuration options, in the `registration` section, are related:

* `session_lifetime`: maximum length of a session, even if it's refreshed.
In other words, the client must log in again after this time period.
DMRobertson marked this conversation as resolved.
Show resolved Hide resolved
In most cases, this can be unset (infinite) or set to a long time (years or months).
* `refreshable_access_token_lifetime`: lifetime of access tokens that are created
by clients supporting refresh tokens.
This should be short; a good value might be 5 minutes (`5m`).
* `nonrefreshable_access_token_lifetime`: lifetime of access tokens that are created
by clients which don't support refresh tokens.
Make this short if you want to force use of refresh tokens.
Make this long if you don't want to inconvenience users of clients which don't
support refresh tokens.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about if I don't want to offer these at all?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point. Perhaps this ought to have some special behaviour for 0 to reject logins from incapable clients.
That said, you're no worse off offering a 5 minute nonrefreshable access token if you usually offer 5 minute refreshable access token — though the user experience is a concern here: rejecting the login altogether at least protects the user from thinking they're fine and getting logged out abruptly 5 minutes later.

* `refresh_token_lifetime`: lifetime of refresh tokens.
Unless you want to log inactive sessions out, it is often fine to use a long
value here or even leave it unset (infinite).
Beware that making it too short will inconvenience clients that do not connect
very often, including mobile clients and clients of infrequent users.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two uses of inconvenience here. Can we explain how they're inconvenienced, i.e. that they must re-authenticate with the login credentials?



### Using refresh token expiry to log out inactive sessions

If you'd like to force sessions to be logged out upon inactivity, you can enable
refreshable access token expiry and refresh token expiry.
DMRobertson marked this conversation as resolved.
Show resolved Hide resolved

Assuming that clients keep their access token valid whilst they are active, and
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

keep their access token valid

What does this mean?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Short answer: it's misleading but I mean that the clients keep refreshing their access tokens when needed so they always have a valid one.

I'm making a bit of an assumption that an active client wants to be syncing all the time.
To sync, it needs a valid access token.
I'm then saying that an 'active' client that has a valid refresh token but an invalid access token will refresh immediately, because otherwise it can't sync (and therefore it contradicts the fact that it's supposedly an 'active' client and all active clients sync all the time).

that you set `refresh_token_lifetime` to some value *R* and
`refreshable_access_token_lifetime` to some value *A* (which is not bigger than *R*),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I parse this as A <= R. Judging by point 1 below, I think you don't want to allow A = R?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's nothing too wrong with A = R; clients would just have to be diligent about refreshing...

The only confusing part is that the section below explaining the range of inactivities that will kick a client would then have a lower bound of zero.
In reality this depends on client behaviour and it's unlikely that clients would wait until the absolute last second to refresh their tokens, but I was trying to be helpful to admins who are thinking something like 'I want sessions inactive for 15 minutes to be logged out' and trying to paint a picture that it depends on when the clients happen to have refreshed their token — are you really OK with that meaning that an inactivity of (e.g. 5 minutes) could also trigger that behaviour?

then:
1. sessions may become logged out if they are inactive for more than *R - A*.
(Explanation: if a client goes offline just before it was about to refresh its
access token, then it must come online before the refresh token expires.)
2. sessions will always become logged out if they are inactive for more than *R*.
(Explanation: if a client refreshes its access token just before going offline,
then returns just before the refresh token expires, it will be able to continue
its session.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't follow this. What is the trigger for a session to be logged out? Your refresh token expires without being used?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The key thing I didn't understand here is that the start of the inactivity period can be before your access and refresh tokens were generated. I think the example below would be improved by this.

(Is it always the case that the active access and active refresh tokens are generated at the same instant?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the start of the inactivity period can be before your access and refresh tokens were generated. I think the example below would be improved by this.

I'm confused by this and on first hand it sounds wrong but I think it's more that I've misunderstood.

(Is it always the case that the active access and active refresh tokens are generated at the same instant?)

Yup, maybe I should actually explain that 'refreshing an access token' means that you exchange your (old) refresh token for a new access token AND a new refresh token at the same time. It's kind of implicit knowledge to me now but I suppose I didn't actually tell you that before :P

Clients are able to refresh more frequently than strictly necessary in order to
avoid the case described by point (1) above.

As an example, if refresh tokens are configured to expire after 20 minutes and
access tokens are configured to expire after 5 minutes, then sessions will definitely
end if inactive for 20 minutes, but may end if inactive for as few as 15 minutes.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something like

Suppose I am granted an access token and refresh token at 12:00. These last for 5 and 20 minutes respectively.

  • I can keep using my access token until 12:05.
  • If I go inactive at 12:00 immediately, I must use my refresh token before it expires at 12:20. This gives me a 20 minute window.
  • If I go inactive at 12:02, I must use my refresh token before it expires at 12:20. This gives me an 18 minute window.
  • If I go inactive at 12:05, I must use my refresh token before it expires at 12:20. This gives me a 15 minute window.

Feels like an information overload. I wonder if it'd be simpler to just say something like

Each time they login or refresh a token, clients must refresh again within timeR to avoid being logged out.

Hmm. I'm not really convinced by my effort there.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm attempting (maybe not very well) to paint a picture of how homeserver admins can configure their servers to have which user-visible behaviours.
What clients should do should hopefully be obvious from the spec.

Basically, if a homeserver admin (or one of our customers...) has a problem statement like 'I want sessions to get logged out automatically if inactive for 15 minutes', this document should help them decide what values they need and hopefully explain why you get a bit of a range of times (with the widest range assuming that clients are lazy and only refresh at the last possible moment)...



Note: this will only affect sessions using refresh tokens. You may wish to
set a short `nonrefreshable_access_token_lifetime` to prevent this being bypassed
by clients that do not support refresh tokens.


## Diagram