client-api: Add support for refresh tokens
According to MSC2918
This commit is contained in:
parent
1605fcc027
commit
90cef5a50b
@ -5,6 +5,10 @@ Breaking changes:
|
|||||||
* Remove `PartialEq` implementations for a number of types
|
* Remove `PartialEq` implementations for a number of types
|
||||||
* If the lack of such an `impl` causes problems, please open a GitHub issue
|
* If the lack of such an `impl` causes problems, please open a GitHub issue
|
||||||
|
|
||||||
|
Improvements:
|
||||||
|
|
||||||
|
* Add unstable support for refresh tokens (MSC2918)
|
||||||
|
|
||||||
# 0.14.1
|
# 0.14.1
|
||||||
|
|
||||||
Improvements:
|
Improvements:
|
||||||
|
@ -23,6 +23,7 @@ unstable-msc2448 = []
|
|||||||
unstable-msc2654 = []
|
unstable-msc2654 = []
|
||||||
unstable-msc2676 = []
|
unstable-msc2676 = []
|
||||||
unstable-msc2677 = []
|
unstable-msc2677 = []
|
||||||
|
unstable-msc2918 = []
|
||||||
unstable-msc3440 = []
|
unstable-msc3440 = []
|
||||||
unstable-msc3488 = []
|
unstable-msc3488 = []
|
||||||
client = []
|
client = []
|
||||||
|
@ -7,6 +7,9 @@ pub mod v3 {
|
|||||||
//!
|
//!
|
||||||
//! [spec]: https://spec.matrix.org/v1.2/client-server-api/#post_matrixclientv3register
|
//! [spec]: https://spec.matrix.org/v1.2/client-server-api/#post_matrixclientv3register
|
||||||
|
|
||||||
|
#[cfg(feature = "unstable-msc2918")]
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
use ruma_common::{api::ruma_api, DeviceId, OwnedDeviceId, OwnedUserId};
|
use ruma_common::{api::ruma_api, DeviceId, OwnedDeviceId, OwnedUserId};
|
||||||
|
|
||||||
use super::{LoginType, RegistrationKind};
|
use super::{LoginType, RegistrationKind};
|
||||||
@ -81,12 +84,24 @@ pub mod v3 {
|
|||||||
/// [admin]: https://spec.matrix.org/v1.2/application-service-api/#server-admin-style-permissions
|
/// [admin]: https://spec.matrix.org/v1.2/application-service-api/#server-admin-style-permissions
|
||||||
#[serde(rename = "type", skip_serializing_if = "Option::is_none")]
|
#[serde(rename = "type", skip_serializing_if = "Option::is_none")]
|
||||||
pub login_type: Option<&'a LoginType>,
|
pub login_type: Option<&'a LoginType>,
|
||||||
|
|
||||||
|
/// If set to `true`, the client supports refresh tokens.
|
||||||
|
#[cfg(feature = "unstable-msc2918")]
|
||||||
|
#[serde(
|
||||||
|
default,
|
||||||
|
skip_serializing_if = "ruma_common::serde::is_default",
|
||||||
|
rename = "org.matrix.msc2918.refresh_token",
|
||||||
|
alias = "refresh_token",
|
||||||
|
)]
|
||||||
|
pub refresh_token: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
response: {
|
response: {
|
||||||
/// An access token for the account.
|
/// An access token for the account.
|
||||||
///
|
///
|
||||||
/// This access token can then be used to authorize other requests.
|
/// This access token can then be used to authorize other requests.
|
||||||
|
///
|
||||||
|
/// Required if the request's `inhibit_login` was set to `false`.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub access_token: Option<String>,
|
pub access_token: Option<String>,
|
||||||
|
|
||||||
@ -96,7 +111,37 @@ pub mod v3 {
|
|||||||
/// ID of the registered device.
|
/// ID of the registered device.
|
||||||
///
|
///
|
||||||
/// Will be the same as the corresponding parameter in the request, if one was specified.
|
/// Will be the same as the corresponding parameter in the request, if one was specified.
|
||||||
|
///
|
||||||
|
/// Required if the request's `inhibit_login` was set to `false`.
|
||||||
pub device_id: Option<OwnedDeviceId>,
|
pub device_id: Option<OwnedDeviceId>,
|
||||||
|
|
||||||
|
/// A refresh token for the account.
|
||||||
|
///
|
||||||
|
/// This token can be used to obtain a new access token when it expires by calling the
|
||||||
|
/// `/refresh` endpoint.
|
||||||
|
///
|
||||||
|
/// Omitted if the request's `inhibit_login` was set to `true`.
|
||||||
|
#[cfg(feature = "unstable-msc2918")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub refresh_token: Option<String>,
|
||||||
|
|
||||||
|
/// The lifetime of the access token, in milliseconds.
|
||||||
|
///
|
||||||
|
/// Once the access token has expired, a new access token can be obtained by using the
|
||||||
|
/// provided refresh token. If no refresh token is provided, the client will need to
|
||||||
|
/// re-login to obtain a new access token.
|
||||||
|
///
|
||||||
|
/// If this is `None`, the client can assume that the access token will not expire.
|
||||||
|
///
|
||||||
|
/// Omitted if the request's `inhibit_login` was set to `true`.
|
||||||
|
#[cfg(feature = "unstable-msc2918")]
|
||||||
|
#[serde(
|
||||||
|
with = "ruma_common::serde::duration::opt_ms",
|
||||||
|
default,
|
||||||
|
skip_serializing_if = "Option::is_none",
|
||||||
|
rename = "expires_in_ms",
|
||||||
|
)]
|
||||||
|
pub expires_in: Option<Duration>,
|
||||||
}
|
}
|
||||||
|
|
||||||
error: UiaaResponse
|
error: UiaaResponse
|
||||||
@ -112,7 +157,15 @@ pub mod v3 {
|
|||||||
impl Response {
|
impl Response {
|
||||||
/// Creates a new `Response` with the given user ID.
|
/// Creates a new `Response` with the given user ID.
|
||||||
pub fn new(user_id: OwnedUserId) -> Self {
|
pub fn new(user_id: OwnedUserId) -> Self {
|
||||||
Self { access_token: None, user_id, device_id: None }
|
Self {
|
||||||
|
access_token: None,
|
||||||
|
user_id,
|
||||||
|
device_id: None,
|
||||||
|
#[cfg(feature = "unstable-msc2918")]
|
||||||
|
refresh_token: None,
|
||||||
|
#[cfg(feature = "unstable-msc2918")]
|
||||||
|
expires_in: None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,5 +5,7 @@ pub mod login;
|
|||||||
pub mod login_fallback;
|
pub mod login_fallback;
|
||||||
pub mod logout;
|
pub mod logout;
|
||||||
pub mod logout_all;
|
pub mod logout_all;
|
||||||
|
#[cfg(feature = "unstable-msc2918")]
|
||||||
|
pub mod refresh_token;
|
||||||
pub mod sso_login;
|
pub mod sso_login;
|
||||||
pub mod sso_login_with_provider;
|
pub mod sso_login_with_provider;
|
||||||
|
@ -5,6 +5,9 @@ pub mod v3 {
|
|||||||
//!
|
//!
|
||||||
//! [spec]: https://spec.matrix.org/v1.2/client-server-api/#post_matrixclientv3login
|
//! [spec]: https://spec.matrix.org/v1.2/client-server-api/#post_matrixclientv3login
|
||||||
|
|
||||||
|
#[cfg(feature = "unstable-msc2918")]
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
use ruma_common::{
|
use ruma_common::{
|
||||||
api::ruma_api,
|
api::ruma_api,
|
||||||
serde::{Incoming, JsonObject},
|
serde::{Incoming, JsonObject},
|
||||||
@ -44,6 +47,16 @@ pub mod v3 {
|
|||||||
/// Ignored if `device_id` corresponds to a known device.
|
/// Ignored if `device_id` corresponds to a known device.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub initial_device_display_name: Option<&'a str>,
|
pub initial_device_display_name: Option<&'a str>,
|
||||||
|
|
||||||
|
/// If set to `true`, the client supports refresh tokens.
|
||||||
|
#[cfg(feature = "unstable-msc2918")]
|
||||||
|
#[serde(
|
||||||
|
default,
|
||||||
|
skip_serializing_if = "ruma_common::serde::is_default",
|
||||||
|
rename = "org.matrix.msc2918.refresh_token",
|
||||||
|
alias = "refresh_token",
|
||||||
|
)]
|
||||||
|
pub refresh_token: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
response: {
|
response: {
|
||||||
@ -71,6 +84,30 @@ pub mod v3 {
|
|||||||
/// If present, clients SHOULD use the provided object to reconfigure themselves.
|
/// If present, clients SHOULD use the provided object to reconfigure themselves.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub well_known: Option<DiscoveryInfo>,
|
pub well_known: Option<DiscoveryInfo>,
|
||||||
|
|
||||||
|
/// A refresh token for the account.
|
||||||
|
///
|
||||||
|
/// This token can be used to obtain a new access token when it expires by calling the
|
||||||
|
/// `/refresh` endpoint.
|
||||||
|
#[cfg(feature = "unstable-msc2918")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub refresh_token: Option<String>,
|
||||||
|
|
||||||
|
/// The lifetime of the access token, in milliseconds.
|
||||||
|
///
|
||||||
|
/// Once the access token has expired, a new access token can be obtained by using the
|
||||||
|
/// provided refresh token. If no refresh token is provided, the client will need to
|
||||||
|
/// re-login to obtain a new access token.
|
||||||
|
///
|
||||||
|
/// If this is `None`, the client can assume that the access token will not expire.
|
||||||
|
#[cfg(feature = "unstable-msc2918")]
|
||||||
|
#[serde(
|
||||||
|
with = "ruma_common::serde::duration::opt_ms",
|
||||||
|
default,
|
||||||
|
skip_serializing_if = "Option::is_none",
|
||||||
|
rename = "expires_in_ms",
|
||||||
|
)]
|
||||||
|
pub expires_in: Option<Duration>,
|
||||||
}
|
}
|
||||||
|
|
||||||
error: crate::Error
|
error: crate::Error
|
||||||
@ -79,14 +116,30 @@ pub mod v3 {
|
|||||||
impl<'a> Request<'a> {
|
impl<'a> Request<'a> {
|
||||||
/// Creates a new `Request` with the given login info.
|
/// Creates a new `Request` with the given login info.
|
||||||
pub fn new(login_info: LoginInfo<'a>) -> Self {
|
pub fn new(login_info: LoginInfo<'a>) -> Self {
|
||||||
Self { login_info, device_id: None, initial_device_display_name: None }
|
Self {
|
||||||
|
login_info,
|
||||||
|
device_id: None,
|
||||||
|
initial_device_display_name: None,
|
||||||
|
#[cfg(feature = "unstable-msc2918")]
|
||||||
|
refresh_token: false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Response {
|
impl Response {
|
||||||
/// Creates a new `Response` with the given user ID, access token and device ID.
|
/// Creates a new `Response` with the given user ID, access token and device ID.
|
||||||
pub fn new(user_id: OwnedUserId, access_token: String, device_id: OwnedDeviceId) -> Self {
|
pub fn new(user_id: OwnedUserId, access_token: String, device_id: OwnedDeviceId) -> Self {
|
||||||
Self { user_id, access_token, home_server: None, device_id, well_known: None }
|
Self {
|
||||||
|
user_id,
|
||||||
|
access_token,
|
||||||
|
home_server: None,
|
||||||
|
device_id,
|
||||||
|
well_known: None,
|
||||||
|
#[cfg(feature = "unstable-msc2918")]
|
||||||
|
refresh_token: None,
|
||||||
|
#[cfg(feature = "unstable-msc2918")]
|
||||||
|
expires_in: None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -374,6 +427,8 @@ pub mod v3 {
|
|||||||
login_info: LoginInfo::Token(Token { token: "0xdeadbeef" }),
|
login_info: LoginInfo::Token(Token { token: "0xdeadbeef" }),
|
||||||
device_id: None,
|
device_id: None,
|
||||||
initial_device_display_name: Some("test"),
|
initial_device_display_name: Some("test"),
|
||||||
|
#[cfg(feature = "unstable-msc2918")]
|
||||||
|
refresh_token: false,
|
||||||
}
|
}
|
||||||
.try_into_http_request(
|
.try_into_http_request(
|
||||||
"https://homeserver.tld",
|
"https://homeserver.tld",
|
||||||
@ -402,6 +457,8 @@ pub mod v3 {
|
|||||||
}),
|
}),
|
||||||
device_id: None,
|
device_id: None,
|
||||||
initial_device_display_name: Some("test"),
|
initial_device_display_name: Some("test"),
|
||||||
|
#[cfg(feature = "unstable-msc2918")]
|
||||||
|
refresh_token: false,
|
||||||
}
|
}
|
||||||
.try_into_http_request(
|
.try_into_http_request(
|
||||||
"https://homeserver.tld",
|
"https://homeserver.tld",
|
||||||
|
84
crates/ruma-client-api/src/session/refresh_token.rs
Normal file
84
crates/ruma-client-api/src/session/refresh_token.rs
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
//! `POST /_matrix/client/*/refresh`
|
||||||
|
//!
|
||||||
|
//! 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.
|
||||||
|
|
||||||
|
pub mod unstable {
|
||||||
|
//! `/unstable/` (MSC2918)
|
||||||
|
//!
|
||||||
|
//! [MSC2918]: https://github.com/matrix-org/matrix-spec-proposals/pull/2918
|
||||||
|
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use ruma_common::api::ruma_api;
|
||||||
|
|
||||||
|
ruma_api! {
|
||||||
|
metadata: {
|
||||||
|
description: "Refresh an access token.",
|
||||||
|
method: POST,
|
||||||
|
name: "refresh",
|
||||||
|
unstable_path: "/_matrix/client/unstable/org.matrix.msc2918/refresh",
|
||||||
|
rate_limited: true,
|
||||||
|
authentication: None,
|
||||||
|
}
|
||||||
|
|
||||||
|
request: {
|
||||||
|
/// The refresh token.
|
||||||
|
pub refresh_token: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
response: {
|
||||||
|
/// The new access token to use.
|
||||||
|
pub access_token: String,
|
||||||
|
|
||||||
|
/// The new refresh token to use when the access token needs to be refreshed again.
|
||||||
|
///
|
||||||
|
/// If this is `None`, the old refresh token can be re-used.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub refresh_token: Option<String>,
|
||||||
|
|
||||||
|
/// The lifetime of the access token, in milliseconds.
|
||||||
|
///
|
||||||
|
/// If this is `None`, the client can assume that the access token will not expire.
|
||||||
|
#[serde(
|
||||||
|
with = "ruma_common::serde::duration::opt_ms",
|
||||||
|
default,
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
pub expires_in_ms: Option<Duration>,
|
||||||
|
}
|
||||||
|
|
||||||
|
error: crate::Error
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Request {
|
||||||
|
/// Creates a new `Request` with the given refresh token.
|
||||||
|
pub fn new(refresh_token: String) -> Self {
|
||||||
|
Self { refresh_token }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Response {
|
||||||
|
/// Creates a new `Response` with the given access token.
|
||||||
|
pub fn new(access_token: String) -> Self {
|
||||||
|
Self { access_token, refresh_token: None, expires_in_ms: None }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -135,6 +135,7 @@ unstable-msc2677 = [
|
|||||||
]
|
]
|
||||||
unstable-msc2746 = ["ruma-common/unstable-msc2746"]
|
unstable-msc2746 = ["ruma-common/unstable-msc2746"]
|
||||||
unstable-msc2870 = ["ruma-signatures?/unstable-msc2870"]
|
unstable-msc2870 = ["ruma-signatures?/unstable-msc2870"]
|
||||||
|
unstable-msc2918 = ["ruma-client-api?/unstable-msc2918"]
|
||||||
unstable-msc3245 = ["ruma-common/unstable-msc3245"]
|
unstable-msc3245 = ["ruma-common/unstable-msc3245"]
|
||||||
unstable-msc3246 = ["ruma-common/unstable-msc3246"]
|
unstable-msc3246 = ["ruma-common/unstable-msc3246"]
|
||||||
unstable-msc3381 = ["ruma-common/unstable-msc3381"]
|
unstable-msc3381 = ["ruma-common/unstable-msc3381"]
|
||||||
@ -165,6 +166,7 @@ __ci = [
|
|||||||
"unstable-msc2677",
|
"unstable-msc2677",
|
||||||
"unstable-msc2746",
|
"unstable-msc2746",
|
||||||
"unstable-msc2870",
|
"unstable-msc2870",
|
||||||
|
"unstable-msc2918",
|
||||||
"unstable-msc3245",
|
"unstable-msc3245",
|
||||||
"unstable-msc3246",
|
"unstable-msc3246",
|
||||||
"unstable-msc3381",
|
"unstable-msc3381",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user