Struct matrix_sdk::oidc::Oidc
source · pub struct Oidc { /* private fields */ }
experimental-oidc
only.Expand description
A high-level authentication API to interact with an OpenID Connect Provider.
Implementations§
source§impl Oidc
impl Oidc
sourcepub async fn enable_cross_process_refresh_lock(
&self,
lock_value: String,
) -> Result<(), OidcError>
pub async fn enable_cross_process_refresh_lock( &self, lock_value: String, ) -> Result<(), OidcError>
Enable a cross-process store lock on the state store, to coordinate refreshes across different processes.
sourcepub async fn fetch_authentication_issuer(&self) -> Result<String, HttpError>
pub async fn fetch_authentication_issuer(&self) -> Result<String, HttpError>
Get the authentication issuer advertised by the homeserver.
Returns an error if the request fails. An error with a
StatusCode::NOT_FOUND
should mean that the homeserver does not support
authenticating via OpenID Connect (MSC3861).
sourcepub fn login_with_qr_code<'a>(
&'a self,
data: &'a QrCodeData,
client_metadata: VerifiedClientMetadata,
) -> LoginWithQrCode<'a>
Available on crate feature e2e-encryption
and non-WebAssembly only.
pub fn login_with_qr_code<'a>( &'a self, data: &'a QrCodeData, client_metadata: VerifiedClientMetadata, ) -> LoginWithQrCode<'a>
e2e-encryption
and non-WebAssembly only.Log in using a QR code.
This method allows you to log in with a QR code, the existing device needs to display the QR code which this device can scan and call this method to log in.
A successful login using this method will automatically mark the device as verified and transfer all end-to-end encryption related secrets, like the private cross-signing keys and the backup key from the existing device to the new device.
§Example
use anyhow::bail;
use futures_util::StreamExt;
use matrix_sdk::{
authentication::qrcode::{LoginProgress, QrCodeData, QrCodeModeData},
Client,
oidc::types::registration::VerifiedClientMetadata,
};
// You'll need to use a different library to scan and extract the raw bytes from the QR
// code.
let qr_code_data = QrCodeData::from_bytes(bytes)?;
// Fetch the homeserver out of the parsed QR code data.
let QrCodeModeData::Reciprocate{ server_name } = qr_code_data.mode_data else {
bail!("The QR code is invalid, we did not receive a homeserver in the QR code.");
};
// Build the client as usual.
let client = Client::builder()
.server_name_or_homeserver_url(server_name)
.handle_refresh_tokens()
.build()
.await?;
let oidc = client.oidc();
let metadata: VerifiedClientMetadata = client_metadata();
// Subscribing to the progress is necessary since we need to input the check
// code on the existing device.
let login = oidc.login_with_qr_code(&qr_code_data, metadata);
let mut progress = login.subscribe_to_progress();
// Create a task which will show us the progress and tell us the check
// code to input in the existing device.
let task = tokio::spawn(async move {
while let Some(state) = progress.next().await {
match state {
LoginProgress::Starting => (),
LoginProgress::EstablishingSecureChannel { check_code } => {
let code = check_code.to_digit();
println!("Please enter the following code into the other device {code:02}");
},
LoginProgress::WaitingForToken { user_code } => {
println!("Please use your other device to confirm the log in {user_code}")
},
LoginProgress::Done => break,
}
}
});
// Now run the future to complete the login.
login.await?;
task.abort();
println!("Successfully logged in: {:?} {:?}", client.user_id(), client.device_id());
sourcepub async fn url_for_oidc(
&self,
client_metadata: VerifiedClientMetadata,
registrations: OidcRegistrations,
prompt: Prompt,
) -> Result<OidcAuthorizationData, OidcError>
pub async fn url_for_oidc( &self, client_metadata: VerifiedClientMetadata, registrations: OidcRegistrations, prompt: Prompt, ) -> Result<OidcAuthorizationData, OidcError>
A higher level wrapper around the configuration and login methods that
will take some client metadata, register the client if needed and begin
the login process, returning the authorization data required to show a
webview for a user to login to their account. Call
Oidc::login_with_oidc_callback
to finish the process when the
webview is complete.
sourcepub async fn login_with_oidc_callback(
&self,
authorization_data: &OidcAuthorizationData,
callback_url: Url,
) -> Result<()>
pub async fn login_with_oidc_callback( &self, authorization_data: &OidcAuthorizationData, callback_url: Url, ) -> Result<()>
A higher level wrapper around the methods to complete a login after the
user has logged in through a webview. This method should be used in
tandem with Oidc::url_for_oidc
.
sourcepub fn issuer(&self) -> Option<&str>
pub fn issuer(&self) -> Option<&str>
The OpenID Connect Provider used for authorization.
Returns None
if the client registration was not restored with
Oidc::restore_registered_client()
or
Oidc::restore_session()
.
sourcepub async fn account_management_actions_supported(
&self,
) -> Result<Option<Vec<AccountManagementAction>>, OidcError>
pub async fn account_management_actions_supported( &self, ) -> Result<Option<Vec<AccountManagementAction>>, OidcError>
The account management actions supported by the provider’s account management URL.
Returns Ok(None)
if the data was not found. Returns an error if the
request to get the provider metadata fails.
sourcepub async fn account_management_url(
&self,
action: Option<AccountManagementActionFull>,
) -> Result<Option<Url>, OidcError>
pub async fn account_management_url( &self, action: Option<AccountManagementActionFull>, ) -> Result<Option<Url>, OidcError>
Build the URL where the user can manage their account.
§Arguments
action
- An optional action that wants to be performed by the user when they open the URL. The list of supported actions by the account management URL can be found in theVerifiedProviderMetadata
, or directly withOidc::account_management_actions_supported()
.
Returns Ok(None)
if the URL was not found. Returns an error if the
request to get the provider metadata fails or the URL could not be
parsed.
sourcepub async fn given_provider_metadata(
&self,
issuer: &str,
) -> Result<VerifiedProviderMetadata, OidcError>
pub async fn given_provider_metadata( &self, issuer: &str, ) -> Result<VerifiedProviderMetadata, OidcError>
Fetch the OpenID Connect metadata of the given issuer.
Returns an error if fetching the metadata failed.
sourcepub async fn provider_metadata(
&self,
) -> Result<VerifiedProviderMetadata, OidcError>
pub async fn provider_metadata( &self, ) -> Result<VerifiedProviderMetadata, OidcError>
Fetch the OpenID Connect metadata of the issuer.
Returns an error if the client registration was not restored, or if an error occurred when fetching the metadata.
sourcepub fn client_metadata(&self) -> Option<&VerifiedClientMetadata>
pub fn client_metadata(&self) -> Option<&VerifiedClientMetadata>
The OpenID Connect metadata of this client used during registration.
Returns None
if the client registration was not restored with
Oidc::restore_registered_client()
or
Oidc::restore_session()
.
sourcepub fn client_credentials(&self) -> Option<&ClientCredentials>
pub fn client_credentials(&self) -> Option<&ClientCredentials>
The OpenID Connect credentials of this client obtained after registration.
Returns None
if the client registration was not restored with
Oidc::restore_registered_client()
or
Oidc::restore_session()
.
sourcepub fn session_tokens(&self) -> Option<OidcSessionTokens>
pub fn session_tokens(&self) -> Option<OidcSessionTokens>
The tokens received after authorization of this client.
Returns None
if the client was not logged in with the OpenID Connect
API.
sourcepub fn session_tokens_stream(
&self,
) -> Option<impl Stream<Item = OidcSessionTokens>>
pub fn session_tokens_stream( &self, ) -> Option<impl Stream<Item = OidcSessionTokens>>
Get changes to the session tokens as a Stream
.
Returns None
if the client was not logged in with the OpenID Connect
API.
After login, the tokens should only change when refreshing the access token or authorizing new scopes.
§Examples
use futures_util::StreamExt;
use matrix_sdk::Client;
let homeserver = "http://example.com";
let client = Client::builder()
.homeserver_url(homeserver)
.handle_refresh_tokens()
.build()
.await?;
// Login with the OpenID Connect API…
let oidc = client.oidc();
let session = oidc.full_session().expect("Client should be logged in");
persist_session(&session);
// Handle when at least one of the tokens changed.
let mut tokens_stream =
oidc.session_tokens_stream().expect("Client should be logged in");
loop {
if tokens_stream.next().await.is_some() {
let session =
oidc.full_session().expect("Client should be logged in");
persist_session(&session);
}
}
sourcepub fn access_token(&self) -> Option<String>
pub fn access_token(&self) -> Option<String>
Get the current access token for this session.
Returns None
if the client was not logged in with the OpenID Connect
API.
sourcepub fn refresh_token(&self) -> Option<String>
pub fn refresh_token(&self) -> Option<String>
Get the current refresh token for this session.
Returns None
if the client was not logged in with the OpenID Connect
API, or if the access token cannot be refreshed.
sourcepub fn latest_id_token(&self) -> Option<IdToken<'static>>
pub fn latest_id_token(&self) -> Option<IdToken<'static>>
The ID Token received after the latest authorization of this client, if any.
Returns None
if the client was not logged in with the OpenID Connect
API, or if the issuer did not provide one.
sourcepub fn user_session(&self) -> Option<UserSession>
pub fn user_session(&self) -> Option<UserSession>
The OpenID Connect user session of this client.
Returns None
if the client was not logged in with the OpenID Connect
API.
sourcepub fn full_session(&self) -> Option<OidcSession>
pub fn full_session(&self) -> Option<OidcSession>
The full OpenID Connect session of this client.
Returns None
if the client was not logged in with the OpenID Connect
API.
sourcepub async fn register_client(
&self,
issuer: &str,
client_metadata: VerifiedClientMetadata,
software_statement: Option<String>,
) -> Result<ClientRegistrationResponse, OidcError>
pub async fn register_client( &self, issuer: &str, client_metadata: VerifiedClientMetadata, software_statement: Option<String>, ) -> Result<ClientRegistrationResponse, OidcError>
Register a client with an OpenID Connect Provider.
This should be called before any authorization request with an unknown
authentication issuer. If the client is already registered with the
given issuer, it should use Oidc::restore_registered_client()
directly.
Note that the client should adapt the security measures enabled in its
metadata according to the capabilities advertised in
Oidc::given_provider_metadata()
.
§Arguments
-
issuer
- The OpenID Connect Provider to register with. Can be obtained withOidc::fetch_authentication_issuer()
. -
client_metadata
- TheVerifiedClientMetadata
to register. -
software_statement
- A software statement, a digitally signed version of the metadata, as a JWT. Any claim in this JWT will override the corresponding field in the client metadata. It must include asoftware_id
claim that is used to uniquely identify a client and ensure the sameclient_id
is returned on subsequent registration, allowing to update the registered client metadata.
The credentials in the response should be persisted for future use and reused for the same issuer, along with the client metadata sent to the provider, even for different sessions or user accounts.
§Example
use matrix_sdk::{Client, ServerName};
use matrix_sdk::oidc::types::client_credentials::ClientCredentials;
use matrix_sdk::oidc::types::registration::ClientMetadata;
let server_name = ServerName::parse("my_homeserver.org").unwrap();
let client = Client::builder().server_name(&server_name).build().await?;
let oidc = client.oidc();
if let Ok(issuer) = oidc.fetch_authentication_issuer().await {
let response = oidc
.register_client(&issuer, client_metadata.clone(), None)
.await?;
println!(
"Registered with client_id: {}",
response.client_id
);
// In this case we registered a public client, so it has no secret.
let credentials = ClientCredentials::None {
client_id: response.client_id,
};
persist_client_registration(&issuer, &client_metadata, &credentials);
}
sourcepub fn restore_registered_client(
&self,
issuer: String,
client_metadata: VerifiedClientMetadata,
client_credentials: ClientCredentials,
)
pub fn restore_registered_client( &self, issuer: String, client_metadata: VerifiedClientMetadata, client_credentials: ClientCredentials, )
Set the data of a client that is registered with an OpenID Connect Provider.
This should be called after registration or when logging in with a provider that is already known by the client.
§Arguments
-
issuer
- The OpenID Connect Provider we’re interacting with. -
client_metadata
- TheVerifiedClientMetadata
that was registered. -
client_credentials
- The credentials necessary to authenticate the client with the provider, obtained after registration.
§Panic
Panics if authentication data was already set.
sourcepub async fn restore_session(&self, session: OidcSession) -> Result<()>
pub async fn restore_session(&self, session: OidcSession) -> Result<()>
sourcepub fn login(
&self,
redirect_uri: Url,
device_id: Option<String>,
) -> Result<OidcAuthCodeUrlBuilder, OidcError>
pub fn login( &self, redirect_uri: Url, device_id: Option<String>, ) -> Result<OidcAuthCodeUrlBuilder, OidcError>
Login via OpenID Connect with the Authorization Code flow.
This should be called after the registered client has been restored with
Oidc::restore_registered_client()
.
If this is a brand new login, Oidc::finish_login()
must be called
after Oidc::finish_authorization()
, to finish loading the user
session.
§Arguments
-
redirect_uri
- The URI where the end user will be redirected after authorizing the login. It must be one of the redirect URIs sent in the client metadata during registration. -
device_id
- The unique ID that will be associated with the session. If not set, a random one will be generated. It can be an existing device ID from a previous login call. Note that this should be done only if the client also holds the corresponding encryption keys.
§Errors
Returns an error if the device ID is not valid.
§Example
use matrix_sdk::{Client};
let oidc = client.oidc();
oidc.restore_registered_client(
issuer_info,
client_metadata,
client_credentials,
);
let auth_data = oidc.login(redirect_uri, None)?.build().await?;
// Open auth_data.url and wait for response at the redirect URI.
// The full URL obtained is called here `redirected_to_uri`.
let auth_response = AuthorizationResponse::parse_uri(&redirected_to_uri)?;
let code = match auth_response {
AuthorizationResponse::Success(code) => code,
AuthorizationResponse::Error(error) => {
return Err(anyhow!("Authorization failed: {:?}", error));
}
};
let _tokens_response = oidc.finish_authorization(code).await?;
// Important! Without this we can't access the full session.
oidc.finish_login().await?;
// The session tokens can be persisted either from the response, or from
// one of the `Oidc::session_tokens()` method.
// You can now make any request compatible with the requested scope.
let _me = client.whoami().await?;
sourcepub async fn finish_login(&self) -> Result<()>
pub async fn finish_login(&self) -> Result<()>
Finish the login process.
Must be called after Oidc::finish_authorization()
after logging into
a brand new session, to load the last part of the user session and
complete the initialization of the Client
.
§Panic
Panics if the login was already completed.
Authorize a given scope with the Authorization Code flow.
This should be used if a new scope is necessary to make a request. For
example, if the homeserver returns an Error
with an
AuthenticateError::InsufficientScope
.
This should be called after the registered client has been restored or the client was logged in.
§Arguments
-
scope
- The scope to authorize. -
redirect_uri
- The URI where the end user will be redirected after authorizing the scope. It must be one of the redirect URIs sent in the client metadata during registration.
Finish the authorization process.
This method should be called after the URL returned by
OidcAuthCodeUrlBuilder::build()
has been presented and the user has
been redirected to the redirect URI after a successful authorization.
If the authorization has not been successful,
Oidc::abort_authorization()
should be used instead to clean up the
local data.
§Arguments
auth_code
- The response received as part of the redirect URI when the authorization was successful.
Returns an error if a request fails.
Abort the authorization process.
This method should be called after the URL returned by
OidcAuthCodeUrlBuilder::build()
has been presented and the user has
been redirected to the redirect URI after a failed authorization, or if
the authorization should be aborted before it is completed.
If the authorization has been successful,
Oidc::finish_authorization()
should be used instead.
§Arguments
state
- The state received as part of the redirect URI when the authorization failed, or the one provided inOidcAuthorizationData
after building the authorization URL.
sourcepub async fn refresh_access_token(&self) -> Result<(), RefreshTokenError>
pub async fn refresh_access_token(&self) -> Result<(), RefreshTokenError>
Refresh the access token.
This should be called when the access token has expired. It should not
be needed to call this manually if the Client
was constructed with
ClientBuilder::handle_refresh_tokens()
.
This method is protected behind a lock, so calling this method several
times at once will only call the endpoint once and all subsequent calls
will wait for the result of the first call. The first call will
return Ok(Some(response))
or a RefreshTokenError
, while the others
will return Ok(None)
if the token was refreshed by the first call
or the same RefreshTokenError
, if it failed.
sourcepub async fn logout(
&self,
) -> Result<Option<OidcEndSessionUrlBuilder>, OidcError>
pub async fn logout( &self, ) -> Result<Option<OidcEndSessionUrlBuilder>, OidcError>
Log out from the currently authenticated session.
On success, if the provider supports RP-Initiated Logout, an
OidcEndSessionUrlBuilder
will be provided to build the URL allowing
the user to log out from their account in the provider’s interface.
Trait Implementations§
Auto Trait Implementations§
impl Freeze for Oidc
impl !RefUnwindSafe for Oidc
impl Send for Oidc
impl Sync for Oidc
impl Unpin for Oidc
impl !UnwindSafe for Oidc
Blanket Implementations§
source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
source§default unsafe fn clone_to_uninit(&self, dst: *mut T)
default unsafe fn clone_to_uninit(&self, dst: *mut T)
clone_to_uninit
)§impl<T> CompatExt for T
impl<T> CompatExt for T
source§impl<T> FutureExt for T
impl<T> FutureExt for T
source§fn with_context(self, otel_cx: Context) -> WithContext<Self>
fn with_context(self, otel_cx: Context) -> WithContext<Self>
source§fn with_current_context(self) -> WithContext<Self>
fn with_current_context(self) -> WithContext<Self>
source§impl<T, UT> HandleAlloc<UT> for T
impl<T, UT> HandleAlloc<UT> for T
source§fn consume_handle(handle: Handle) -> Arc<T>
fn consume_handle(handle: Handle) -> Arc<T>
Arc<>
source§impl<T, W> HasTypeWitness<W> for Twhere
W: MakeTypeWitness<Arg = T>,
T: ?Sized,
impl<T, W> HasTypeWitness<W> for Twhere
W: MakeTypeWitness<Arg = T>,
T: ?Sized,
source§impl<T> Identity for Twhere
T: ?Sized,
impl<T> Identity for Twhere
T: ?Sized,
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
source§impl<T> IntoEither for T
impl<T> IntoEither for T
source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moresource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read more