diff --git a/callback/index.html b/callback/index.html
new file mode 100644
index 0000000..4239269
--- /dev/null
+++ b/callback/index.html
@@ -0,0 +1,17 @@
+
+
+
+
+
+ Linking Twitter...
+
+
+
+
+
Linking your Twitter account...
+
+
+
+
+
+
\ No newline at end of file
diff --git a/callback/styles.css b/callback/styles.css
new file mode 100644
index 0000000..1c401d7
--- /dev/null
+++ b/callback/styles.css
@@ -0,0 +1,22 @@
+body {
+ font-family: sans-serif;
+ text-align: center;
+ padding-top: 50px;
+ background: #1a1a1a;
+ color: white;
+}
+
+.loader {
+ border: 4px solid #f3f3f3;
+ border-top: 4px solid #1DA1F2;
+ border-radius: 50%;
+ width: 40px;
+ height: 40px;
+ animation: spin 2s linear infinite;
+ margin: 20px auto;
+}
+
+@keyframes spin {
+ 0% { transform: rotate(0deg); }
+ 100% { transform: rotate(360deg); }
+}
\ No newline at end of file
diff --git a/callback/twitter.js b/callback/twitter.js
new file mode 100644
index 0000000..2b3b08c
--- /dev/null
+++ b/callback/twitter.js
@@ -0,0 +1,37 @@
+async function finalizeLink() {
+ const urlParams = new URLSearchParams(window.location.search);
+ const code = urlParams.get('code');
+ const state = urlParams.get('state');
+
+ const statusDiv = document.getElementById('status');
+
+ if (!code || !state) {
+ statusDiv.innerHTML = "Error: Missing data from Twitter
";
+ return;
+ }
+
+ try {
+ const response = await fetch(`/api/v1/me/twitter/confirm?state=${state}&code=${code}`, {
+ method: 'GET',
+ });
+
+ const data = await response.json();
+
+ if (response.ok) {
+ statusDiv.innerHTML = `
+ Success!
+ Linked as @${data.handle}
+ Redirecting you back...
+ `;
+ setTimeout(() => {
+ window.location.href = '/';
+ }, 2000);
+ } else {
+ statusDiv.innerHTML = `Error: ${data.detail || 'Failed to link'}
`;
+ }
+ } catch (err) {
+ statusDiv.innerHTML = "Failed to connect to backend
";
+ }
+}
+
+finalizeLink();
\ No newline at end of file