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/encryption.dart';
|
||||||
import 'package:matrix/matrix.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/models/timeline_chunk.dart';
|
||||||
import 'package:matrix/src/utils/cached_stream_controller.dart';
|
import 'package:matrix/src/utils/cached_stream_controller.dart';
|
||||||
import 'package:matrix/src/utils/client_init_exception.dart';
|
import 'package:matrix/src/utils/client_init_exception.dart';
|
||||||
|
|
@ -195,6 +196,11 @@ class Client extends MatrixApi {
|
||||||
/// most common reason for soft logouts.
|
/// most common reason for soft logouts.
|
||||||
/// You can also perform a new login here by passing the existing deviceId.
|
/// You can also perform a new login here by passing the existing deviceId.
|
||||||
this.onSoftLogout,
|
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 ??
|
}) : syncFilter = syncFilter ??
|
||||||
Filter(
|
Filter(
|
||||||
room: RoomFilter(
|
room: RoomFilter(
|
||||||
|
|
@ -238,6 +244,8 @@ class Client extends MatrixApi {
|
||||||
registerDefaultCommands();
|
registerDefaultCommands();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Duration? customRefreshTokenLifetime;
|
||||||
|
|
||||||
/// Fetches the refreshToken from the database and tries to get a new
|
/// Fetches the refreshToken from the database and tries to get a new
|
||||||
/// access token from the server and then stores it correctly. Unlike the
|
/// access token from the server and then stores it correctly. Unlike the
|
||||||
/// pure API call of `Client.refresh()` this handles the complete soft
|
/// 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');
|
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;
|
accessToken = tokenResponse.accessToken;
|
||||||
final expiresInMs = tokenResponse.expiresInMs;
|
final expiresInMs = tokenResponse.expiresInMs;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue