diff --git a/data/resources/resources.gresource.xml b/data/resources/resources.gresource.xml
index 088f12e9..874d4dbd 100644
--- a/data/resources/resources.gresource.xml
+++ b/data/resources/resources.gresource.xml
@@ -34,6 +34,7 @@
ui/in-app-notification.ui
ui/components-avatar.ui
ui/avatar-with-selection.ui
+ ui/components-auth-dialog.ui
style.css
icons/scalable/actions/send-symbolic.svg
icons/scalable/status/welcome.svg
diff --git a/data/resources/ui/components-auth-dialog.ui b/data/resources/ui/components-auth-dialog.ui
new file mode 100644
index 00000000..66cc4226
--- /dev/null
+++ b/data/resources/ui/components-auth-dialog.ui
@@ -0,0 +1,132 @@
+
+
+
+ true
+ true
+
+ 0
+ button_ok
+
+
+
+
+
+
+
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 2086295f..4dc61b5d 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -6,6 +6,7 @@ data/org.gnome.FractalNext.metainfo.xml.in.in
# UI files
data/resources/ui/add_account.ui
+data/resources/ui/components-auth-dialog.ui
data/resources/ui/components-avatar.ui
data/resources/ui/avatar-with-selection.ui
data/resources/ui/content-divider-row.ui
@@ -36,6 +37,7 @@ data/resources/ui/window.ui
# Rust files
src/application.rs
+src/components/auth_dialog.rs
src/components/avatar.rs
src/components/context_menu_bin.rs
src/components/custom_entry.rs
diff --git a/src/components/auth_dialog.rs b/src/components/auth_dialog.rs
new file mode 100644
index 00000000..42067862
--- /dev/null
+++ b/src/components/auth_dialog.rs
@@ -0,0 +1,383 @@
+use adw::subclass::prelude::*;
+use gtk::gdk;
+use gtk::gio::prelude::*;
+use gtk::glib::clone;
+use gtk::prelude::*;
+use gtk::subclass::prelude::*;
+use gtk::{glib, CompositeTemplate};
+use std::cell::Cell;
+use std::future::Future;
+
+use crate::session::Session;
+use crate::session::UserExt;
+use crate::RUNTIME;
+
+use matrix_sdk::{
+ ruma::api::{
+ client::{
+ error::ErrorBody,
+ r0::uiaa::{
+ AuthData as MatrixAuthData,
+ FallbackAcknowledgement as MatrixFallbackAcknowledgement,
+ Password as MatrixPassword, UiaaInfo, UiaaResponse, UserIdentifier,
+ },
+ },
+ error::{FromHttpResponseError, ServerError},
+ OutgoingRequest,
+ },
+ ruma::assign,
+ HttpError,
+ HttpError::UiaaError,
+ HttpResult,
+};
+
+use std::fmt::Debug;
+
+pub struct Password {
+ pub user_id: String,
+ pub password: String,
+ pub session: Option,
+}
+
+pub struct FallbackAcknowledgement {
+ pub session: String,
+}
+
+// FIXME: we can't move the ruma AuthData between threads
+// because it's not owned data and doesn't live long enough.
+// Therefore we have our own AuthData.
+pub enum AuthData {
+ Password(Password),
+ FallbackAcknowledgement(FallbackAcknowledgement),
+}
+
+impl AuthData {
+ pub fn as_matrix_auth_data(&self) -> MatrixAuthData {
+ match self {
+ AuthData::Password(Password {
+ user_id,
+ password,
+ session,
+ }) => MatrixAuthData::Password(assign!(MatrixPassword::new(
+ UserIdentifier::MatrixId(&user_id),
+ &password,
+ ), { session: session.as_deref() })),
+ AuthData::FallbackAcknowledgement(FallbackAcknowledgement { session }) => {
+ MatrixAuthData::FallbackAcknowledgement(MatrixFallbackAcknowledgement::new(
+ &session,
+ ))
+ }
+ }
+ }
+}
+
+mod imp {
+ use super::*;
+ use glib::subclass::{InitializingObject, Signal};
+ use glib::SignalHandlerId;
+ use once_cell::sync::Lazy;
+ use std::cell::RefCell;
+
+ #[derive(Debug, Default, CompositeTemplate)]
+ #[template(resource = "/org/gnome/FractalNext/components-auth-dialog.ui")]
+ pub struct AuthDialog {
+ pub session: RefCell