Skip to content

Commit 8d82366

Browse files
authored
Merge pull request #1056 from uhoreg/refresh_token_spec
Add spec for refresh tokens
2 parents 3130430 + 9bf02ad commit 8d82366

File tree

5 files changed

+239
-21
lines changed

5 files changed

+239
-21
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add refresh tokens, per [MSC2918](https://github.com/matrix-org/matrix-spec-proposals/pull/2918).

content/client-server-api/_index.md

Lines changed: 78 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ These error codes can be returned by any API endpoint:
7171
Forbidden access, e.g. joining a room without permission, failed login.
7272

7373
`M_UNKNOWN_TOKEN`
74-
The access token specified was not recognised.
74+
The access or refresh token specified was not recognised.
7575

7676
An additional response parameter, `soft_logout`, might be present on the
7777
response for 401 HTTP status codes. See [the soft logout
@@ -314,7 +314,8 @@ Most API endpoints require the user to identify themselves by presenting
314314
previously obtained credentials in the form of an `access_token` query
315315
parameter or through an Authorization Header of `Bearer $access_token`.
316316
An access token is typically obtained via the [Login](#login) or
317-
[Registration](#account-registration-and-management) processes.
317+
[Registration](#account-registration-and-management) processes. Access tokens
318+
can expire; a new access token can be generated by using a refresh token.
318319

319320
{{% boxes/note %}}
320321
This specification does not mandate a particular format for the access
@@ -338,40 +339,94 @@ inaccessible for the client.
338339

339340
When credentials are required but missing or invalid, the HTTP call will
340341
return with a status of 401 and the error code, `M_MISSING_TOKEN` or
341-
`M_UNKNOWN_TOKEN` respectively.
342+
`M_UNKNOWN_TOKEN` respectively. Note that an error code of `M_UNKNOWN_TOKEN`
343+
could mean one of four things:
344+
345+
1. the access token was never valid.
346+
2. the access token has been logged out.
347+
3. the access token has been [soft logged out](#soft-logout).
348+
4. {{< added-in v="1.3" >}} the access token [needs to be refreshed](#refreshing-access-tokens).
349+
350+
When a client receives an error code of `M_UNKNOWN_TOKEN`, it should:
351+
352+
- attempt to [refresh the token](#refreshing-access-tokens), if it has a refresh
353+
token;
354+
- if [`soft_logout`](#soft-logout) is set to `true`, it can offer to
355+
re-log in the user, retaining any of the client's persisted
356+
information;
357+
- otherwise, consider the user as having been logged out.
342358

343359
### Relationship between access tokens and devices
344360

345361
Client [devices](../index.html#devices) are closely related to access
346-
tokens. Matrix servers should record which device each access token is
347-
assigned to, so that subsequent requests can be handled correctly.
362+
tokens and refresh tokens. Matrix servers should record which device
363+
each access token and refresh token are assigned to, so that
364+
subsequent requests can be handled correctly. When a refresh token is
365+
used to generate a new access token and refresh token, the new access
366+
and refresh tokens are now bound to the device associated with the
367+
initial refresh token.
348368

349369
By default, the [Login](#login) and [Registration](#account-registration-and-management)
350370
processes auto-generate a new `device_id`. A client is also free to
351371
generate its own `device_id` or, provided the user remains the same,
352372
reuse a device: in either case the client should pass the `device_id` in
353373
the request body. If the client sets the `device_id`, the server will
354-
invalidate any access token previously assigned to that device. There is
355-
therefore at most one active access token assigned to each device at any
356-
one time.
374+
invalidate any access and refresh tokens previously assigned to that device.
375+
376+
### Refreshing access tokens
377+
378+
{{% added-in v="1.3" %}}
379+
380+
Access tokens can expire after a certain amount of time. Any HTTP calls that
381+
use an expired access token will return with an error code `M_UNKNOWN_TOKEN`,
382+
preferably with `soft_logout: true`. When a client receives this error and it
383+
has a refresh token, it should attempt to refresh the access token by calling
384+
[`/refresh`](#post_matrixclientv3refresh). Clients can also refresh their
385+
access token at any time, even if it has not yet expired. If the token refresh
386+
succeeds, the client should use the new token for future requests, and can
387+
re-try previously-failed requests with the new token. When an access token is
388+
refreshed, a new refresh token may be returned; if a new refresh token is
389+
given, the old refresh token will be invalidated, and the new refresh token
390+
should be used when the access token needs to be refreshed.
391+
392+
The old refresh token remains valid until the new access token or refresh token
393+
is used, at which point the old refresh token is revoked. This ensures that if
394+
a client fails to receive or persist the new tokens, it will be able to repeat
395+
the refresh operation.
396+
397+
If the token refresh fails and the error response included a `soft_logout:
398+
true` property, then the client can treat it as a [soft logout](#soft-logout)
399+
and attempt to obtain a new access token by re-logging in. If the error
400+
response does not include a `soft_logout: true` property, the client should
401+
consider the user as being logged out.
402+
403+
Handling of clients that do not support refresh tokens is up to the homeserver;
404+
clients indicate their support for refresh tokens by including a
405+
`refresh_token: true` property in the request body of the
406+
[`/login`](#post_matrixclientv3login) and
407+
[`/register`](#post_matrixclientv3register) endpoints. For example, homeservers
408+
may allow the use of non-expiring access tokens, or may expire access tokens
409+
anyways and rely on soft logout behaviour on clients that don't support
410+
refreshing.
357411

358412
### Soft logout
359413

360-
When a request fails due to a 401 status code per above, the server can
361-
include an extra response parameter, `soft_logout`, to indicate if the
362-
client's persisted information can be retained. This defaults to
363-
`false`, indicating that the server has destroyed the session. Any
414+
A client can be in a "soft logout" state if the server requires
415+
re-authentication before continuing, but does not want to invalidate the
416+
client's session. The server indicates that the client is in a soft logout
417+
state by including a `soft_logout: true` parameter in an `M_UNKNOWN_TOKEN`
418+
error response; the `soft_logout` parameter defaults to `false`. If the
419+
`soft_logout` parameter is omitted or is `false`, this means the server has
420+
destroyed the session and the client should not reuse it. That is, any
364421
persisted state held by the client, such as encryption keys and device
365-
information, must not be reused and must be discarded.
422+
information, must not be reused and must be discarded. If `soft_logout` is
423+
`true` the client can reuse any persisted state.
366424

367-
When `soft_logout` is true, the client can acquire a new access token by
368-
specifying the device ID it is already using to the login API. In most
369-
cases a `soft_logout: true` response indicates that the user's session
370-
has expired on the server-side and the user simply needs to provide
371-
their credentials again.
372-
373-
In either case, the client's previously known access token will no
374-
longer function.
425+
{{% changed-in v="1.3" %}} A client that receives such a response can try to
426+
[refresh its access token](#refreshing-access-tokens), if it has a refresh
427+
token available. If it does not have a refresh token available, or refreshing
428+
fails with `soft_logout: true`, the client can acquire a new access token by
429+
specifying the device ID it is already using to the login API.
375430

376431
### User-Interactive Authentication API
377432

@@ -1105,6 +1160,8 @@ errcode of `M_EXCLUSIVE`.
11051160

11061161
{{% http-api spec="client-server" api="login" %}}
11071162

1163+
{{% http-api spec="client-server" api="refresh" %}}
1164+
11081165
{{% http-api spec="client-server" api="logout" %}}
11091166

11101167
#### Login Fallback

data/api/client-server/login.yaml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Copyright 2016 OpenMarket Ltd
22
# Copyright 2018 New Vector Ltd
3+
# Copyright 2022 The Matrix.org Foundation C.I.C.
34
#
45
# Licensed under the Apache License, Version 2.0 (the "License");
56
# you may not use this file except in compliance with the License.
@@ -133,6 +134,11 @@ paths:
133134
description: |-
134135
A display name to assign to the newly-created device. Ignored
135136
if `device_id` corresponds to a known device.
137+
refresh_token:
138+
type: boolean
139+
description: |-
140+
If true, the client supports refresh tokens.
141+
x-addedInMatrixVersion: "1.3"
136142
required: ["type"]
137143

138144
responses:
@@ -142,6 +148,8 @@ paths:
142148
application/json: {
143149
"user_id": "@cheeky_monkey:matrix.org",
144150
"access_token": "abc123",
151+
"refresh_token": "def456",
152+
"expires_in_ms": 60000,
145153
"device_id": "GHTYAJCE",
146154
"well_known": {
147155
"m.homeserver": {
@@ -163,6 +171,23 @@ paths:
163171
description: |-
164172
An access token for the account.
165173
This access token can then be used to authorize other requests.
174+
refresh_token:
175+
type: string
176+
description: |-
177+
A refresh token for the account. This token can be used to
178+
obtain a new access token when it expires by calling the
179+
`/refresh` endpoint.
180+
x-addedInMatrixVersion: "1.3"
181+
expires_in_ms:
182+
type: integer
183+
description: |-
184+
The lifetime of the access token, in milliseconds. Once
185+
the access token has expired a new access token can be
186+
obtained by using the provided refresh token. If no
187+
refresh token is provided, the client will need to re-log in
188+
to obtain a new access token. If not given, the client can
189+
assume that the access token will not expire.
190+
x-addedInMatrixVersion: "1.3"
166191
home_server:
167192
type: string
168193
description: |-
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# Copyright 2022 The Matrix.org Foundation C.I.C.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
swagger: '2.0'
15+
info:
16+
title: "Matrix Client-Server Registration and Login API"
17+
version: "1.0.0"
18+
host: localhost:8008
19+
schemes:
20+
- https
21+
- http
22+
basePath: /_matrix/client/v3
23+
consumes:
24+
- application/json
25+
produces:
26+
- application/json
27+
paths:
28+
"/refresh":
29+
post:
30+
x-addedInMatrixVersion: "1.3"
31+
summary: Refresh an access token
32+
description: |-
33+
Refresh an access token. Clients should use the returned access token
34+
when making subsequent API calls, and store the returned refresh token
35+
(if given) in order to refresh the new access token when necessary.
36+
37+
After an access token has been refreshed, a server can choose to
38+
invalidate the old access token immediately, or can choose not to, for
39+
example if the access token would expire soon anyways. Clients should
40+
not make any assumptions about the old access token still being valid,
41+
and should use the newly provided access token instead.
42+
43+
The old refresh token remains valid until the new access token or refresh token
44+
is used, at which point the old refresh token is revoked.
45+
46+
Note that this endpoint does not require authentication via an
47+
access token. Authentication is provided via the refresh token.
48+
49+
Application Service identity assertion is disabled for this endpoint.
50+
operationId: refresh
51+
parameters:
52+
- in: body
53+
name: body
54+
required: true
55+
schema:
56+
type: object
57+
example: {
58+
"refresh_token": "some_token"
59+
}
60+
properties:
61+
refresh_token:
62+
type: string
63+
description: The refresh token
64+
responses:
65+
200:
66+
description: A new access token and refresh token were generated.
67+
examples:
68+
application/json: {
69+
"access_token": "a_new_token",
70+
"expires_in_ms": 60000,
71+
"refresh_token": "another_new_token"
72+
}
73+
schema:
74+
type: object
75+
properties:
76+
access_token:
77+
type: string
78+
description: |-
79+
The new access token to use.
80+
refresh_token:
81+
type: string
82+
description: |-
83+
The new refresh token to use when the access token needs to
84+
be refreshed again. If not given, the old refresh token can
85+
be re-used.
86+
expires_in_ms:
87+
type: integer
88+
description: |-
89+
The lifetime of the access token, in milliseconds. If not
90+
given, the client can assume that the access token will not
91+
expire.
92+
required:
93+
- access_token
94+
401:
95+
description: |-
96+
The provided token was unknown, or has already been used.
97+
examples:
98+
application/json: {
99+
"errcode": "M_UNKNOWN_TOKEN",
100+
"error": "Soft logged out",
101+
"soft_logout": true
102+
}
103+
schema:
104+
"$ref": "definitions/errors/error.yaml"
105+
429:
106+
description: This request was rate-limited.
107+
schema:
108+
"$ref": "definitions/errors/rate_limited.yaml"

data/api/client-server/registration.yaml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# Copyright 2016 OpenMarket Ltd
2+
# Copyright 2022 The Matrix.org Foundation C.I.C.
23
#
34
# Licensed under the Apache License, Version 2.0 (the "License");
45
# you may not use this file except in compliance with the License.
@@ -127,6 +128,11 @@ paths:
127128
returned from this call, therefore preventing an automatic
128129
login. Defaults to false.
129130
example: false
131+
refresh_token:
132+
type: boolean
133+
description: |-
134+
If true, the client supports refresh tokens.
135+
x-addedInMatrixVersion: "1.3"
130136
responses:
131137
200:
132138
description: The account has been registered.
@@ -152,6 +158,27 @@ paths:
152158
An access token for the account.
153159
This access token can then be used to authorize other requests.
154160
Required if the `inhibit_login` option is false.
161+
refresh_token:
162+
type: string
163+
description: |-
164+
A refresh token for the account. This token can be used to
165+
obtain a new access token when it expires by calling the
166+
`/refresh` endpoint.
167+
168+
Omitted if the `inhibit_login` option is false.
169+
x-addedInMatrixVersion: "1.3"
170+
expires_in_ms:
171+
type: integer
172+
description: |-
173+
The lifetime of the access token, in milliseconds. Once
174+
the access token has expired a new access token can be
175+
obtained by using the provided refresh token. If no
176+
refresh token is provided, the client will need to re-log in
177+
to obtain a new access token. If not given, the client can
178+
assume that the access token will not expire.
179+
180+
Omitted if the `inhibit_login` option is false.
181+
x-addedInMatrixVersion: "1.3"
155182
home_server:
156183
type: string
157184
description: |-

0 commit comments

Comments
 (0)