feat: Implement unpublished MSC custom refresh token lifetime
This commit is contained in:
parent
5ecff08bf4
commit
3f8a4c8189
|
|
@ -0,0 +1,56 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:http/http.dart';
|
||||
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
extension MscUnpublishedCustomRefreshTokenLifetime on MatrixApi {
|
||||
static const String customFieldKey = 'com.famedly.refresh_token_lifetime_ms';
|
||||
|
||||
/// Refresh an access token. Clients should use the returned access token
|
||||
/// when making subsequent API calls, and store the returned refresh token
|
||||
/// (if given) in order to refresh the new access token when necessary.
|
||||
///
|
||||
/// After an access token has been refreshed, a server can choose to
|
||||
/// invalidate the old access token immediately, or can choose not to, for
|
||||
/// example if the access token would expire soon anyways. Clients should
|
||||
/// not make any assumptions about the old access token still being valid,
|
||||
/// and should use the newly provided access token instead.
|
||||
///
|
||||
/// The old refresh token remains valid until the new access token or refresh token
|
||||
/// is used, at which point the old refresh token is revoked.
|
||||
///
|
||||
/// Note that this endpoint does not require authentication via an
|
||||
/// access token. Authentication is provided via the refresh token.
|
||||
///
|
||||
/// Application Service identity assertion is disabled for this endpoint.
|
||||
///
|
||||
/// [refreshToken] The refresh token
|
||||
Future<RefreshResponse> refreshWithCustomRefreshTokenLifetime(
|
||||
String refreshToken, {
|
||||
/// This allows clients to pass an extra parameter when refreshing a token,
|
||||
/// which overrides the configured refresh token timeout in the Synapse
|
||||
/// config. This allows a client to opt into a shorter (or longer) lifetime
|
||||
/// for their refresh token, which could be used to sign out web sessions
|
||||
/// with a specific timeout.
|
||||
///
|
||||
/// Experimental implementation in Synapse:
|
||||
/// https://github.com/famedly/synapse/pull/10
|
||||
int? refreshTokenLifetimeMs,
|
||||
}) async {
|
||||
final requestUri = Uri(path: '_matrix/client/v3/refresh');
|
||||
final request = Request('POST', baseUri!.resolveUri(requestUri));
|
||||
request.headers['content-type'] = 'application/json';
|
||||
request.bodyBytes = utf8.encode(jsonEncode({
|
||||
'refresh_token': refreshToken,
|
||||
if (refreshTokenLifetimeMs != null)
|
||||
customFieldKey: refreshTokenLifetimeMs,
|
||||
}));
|
||||
final response = await httpClient.send(request);
|
||||
final responseBody = await response.stream.toBytes();
|
||||
if (response.statusCode != 200) unexpectedResponse(response, responseBody);
|
||||
final responseString = utf8.decode(responseBody);
|
||||
final json = jsonDecode(responseString);
|
||||
return RefreshResponse.fromJson(json as Map<String, Object?>);
|
||||
}
|
||||
}
|
||||
|
|
@ -31,6 +31,7 @@ import 'package:random_string/random_string.dart';
|
|||
|
||||
import 'package:matrix/encryption.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
import 'package:matrix/msc_extensions/msc_unpublished_custom_refresh_token_lifetime/msc_unpublished_custom_refresh_token_lifetime.dart';
|
||||
import 'package:matrix/src/models/timeline_chunk.dart';
|
||||
import 'package:matrix/src/utils/cached_stream_controller.dart';
|
||||
import 'package:matrix/src/utils/client_init_exception.dart';
|
||||
|
|
@ -195,6 +196,11 @@ class Client extends MatrixApi {
|
|||
/// most common reason for soft logouts.
|
||||
/// You can also perform a new login here by passing the existing deviceId.
|
||||
this.onSoftLogout,
|
||||
|
||||
/// Experimental feature which allows to send a custom refresh token
|
||||
/// lifetime to the server which overrides the default one. Needs server
|
||||
/// support.
|
||||
this.customRefreshTokenLifetime,
|
||||
}) : syncFilter = syncFilter ??
|
||||
Filter(
|
||||
room: RoomFilter(
|
||||
|
|
@ -238,6 +244,8 @@ class Client extends MatrixApi {
|
|||
registerDefaultCommands();
|
||||
}
|
||||
|
||||
Duration? customRefreshTokenLifetime;
|
||||
|
||||
/// Fetches the refreshToken from the database and tries to get a new
|
||||
/// access token from the server and then stores it correctly. Unlike the
|
||||
/// pure API call of `Client.refresh()` this handles the complete soft
|
||||
|
|
@ -257,7 +265,10 @@ class Client extends MatrixApi {
|
|||
throw Exception('Cannot refresh access token when not logged in');
|
||||
}
|
||||
|
||||
final tokenResponse = await refresh(refreshToken);
|
||||
final tokenResponse = await refreshWithCustomRefreshTokenLifetime(
|
||||
refreshToken,
|
||||
refreshTokenLifetimeMs: customRefreshTokenLifetime?.inMilliseconds,
|
||||
);
|
||||
|
||||
accessToken = tokenResponse.accessToken;
|
||||
final expiresInMs = tokenResponse.expiresInMs;
|
||||
|
|
|
|||
Loading…
Reference in New Issue