diff --git a/client/package-lock.json b/client/package-lock.json
index 1ed4e53..f1ae0bc 100644
--- a/client/package-lock.json
+++ b/client/package-lock.json
@@ -9,6 +9,7 @@
       "version": "1.0.0",
       "license": "MIT",
       "dependencies": {
+        "jsqr": "^1.4.0",
         "nostr-login": "^1.7.11",
         "nostr-tools": "^2.12.0",
         "qrcode": "^1.5.4",
@@ -5311,6 +5312,12 @@
         "json5": "lib/cli.js"
       }
     },
+    "node_modules/jsqr": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/jsqr/-/jsqr-1.4.0.tgz",
+      "integrity": "sha512-dxLob7q65Xg2DvstYkRpkYtmKm2sPJ9oFhrhmudT1dZvNFFTlroai3AWSpLey/w5vMcLBXRgOJsbXpdN9HzU/A==",
+      "license": "Apache-2.0"
+    },
     "node_modules/keyv": {
       "version": "4.5.4",
       "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
diff --git a/client/src/auth-manager.ts b/client/src/auth-manager.ts
index 4c45377..a0d0afa 100644
--- a/client/src/auth-manager.ts
+++ b/client/src/auth-manager.ts
@@ -93,12 +93,16 @@ export async function loginWithNostrLogin(): Promise<string | null> {
       executePostAuthQueue();
       
       return result.pubkey;
+    } else if (result.error) {
+      // If we have a specific error message from the authentication service
+      console.error("Authentication failed with message:", result.error);
+      throw new Error(result.error);
     }
     
     return null;
   } catch (error) {
     console.error("Error using Nostr login:", error);
-    return null;
+    throw error; // Rethrow to allow the caller to handle specific error messages
   }
 }
 
diff --git a/client/src/billboard.ts b/client/src/billboard.ts
index 9f39e61..6089b69 100644
--- a/client/src/billboard.ts
+++ b/client/src/billboard.ts
@@ -52,11 +52,27 @@ document.addEventListener('DOMContentLoaded', () => {
           updateUIBasedOnAuth();
         } else {
           console.log('Login attempt failed, showing error');
-          alert('Login failed. Please make sure you have a Nostr extension installed (like Alby or nos2x).');
+          alert('Login failed. Authentication with nostr-login was unsuccessful. Please check the console for error details.');
         }
       } catch (error) {
         console.error('Authentication error:', error);
-        alert(`Authentication error: ${error instanceof Error ? error.message : 'Unknown error'}`);
+        
+        let errorMessage = 'Authentication error';
+        
+        if (error instanceof Error) {
+          if (error.message.includes('Rejected') || error.message.includes('Cancelled')) {
+            errorMessage = 'Login was cancelled. Please try again when you are ready to authenticate.';
+          } else {
+            errorMessage = error.message;
+          }
+        } else if (error && typeof error === 'object' && 'error' in error) {
+          const errorValue = error.error;
+          errorMessage = typeof errorValue === 'string' ? errorValue : errorMessage;
+        } else {
+          errorMessage = String(error || 'Unknown error');
+        }
+        
+        alert(errorMessage);
       }
     });
   }
@@ -271,7 +287,7 @@ async function handleConnectRelay(): Promise<void> {
         updateUIBasedOnAuth();
         updateRelayStatus('Authentication successful. Connecting...', 'connecting');
       } else {
-        updateRelayStatus('Authentication failed. Please try again or install a Nostr extension like Alby or nos2x.', 'error');
+        updateRelayStatus('Authentication failed. Please try again. nostr-login authentication was unsuccessful.', 'error');
         return;
       }
     } catch (error) {
diff --git a/client/src/client-event-handler.ts b/client/src/client-event-handler.ts
index 6911b76..1b5a691 100644
--- a/client/src/client-event-handler.ts
+++ b/client/src/client-event-handler.ts
@@ -17,6 +17,9 @@ import type { NostrRelayService } from './services/NostrRelayService';
 // Create a singleton instance of the client event store
 const clientEventStore = new ClientEventStore();
 
+// Track events that have been published to avoid duplicates
+const publishedEvents = new Set<string>();
+
 // The table UI component (initialized in setup)
 let clientEventsTable: ClientEventsTable | null = null;
 
@@ -216,12 +219,46 @@ export function trackOutgoingEvent(event: NostrEvent): string | null {
     console.warn(`Expected KIND 21120 event, got ${event.kind}`);
   }
   
+  // Check if this event is already tracked
+  const existingEvent = clientEventStore.getEvent(event.id);
+  if (existingEvent) {
+    console.log(`Event ${event.id} is already being tracked, not adding again`);
+    return event.id;
+  }
+  
+  // Check if this event has already been published
+  if (publishedEvents.has(event.id)) {
+    console.log(`Event ${event.id} has already been published, not adding again`);
+    return event.id;
+  }
+  
   // Add to the store
   const eventId = clientEventStore.addOutgoingEvent(event);
   console.log(`Tracked outgoing event: ${eventId}`);
   return eventId;
 }
 
+/**
+ * Mark an event as published to prevent duplicate publishing
+ * @param eventId The ID of the event that was published
+ */
+export function markEventAsPublished(eventId: string): void {
+  if (!eventId) return;
+  
+  // Add to the set of published events
+  publishedEvents.add(eventId);
+  console.log(`Marked event ${eventId} as published`);
+}
+
+/**
+ * Check if an event has already been published
+ * @param eventId The ID of the event to check
+ * @returns True if the event has been published, false otherwise
+ */
+export function isEventPublished(eventId: string): boolean {
+  return publishedEvents.has(eventId);
+}
+
 /**
  * Handle a pending 21120 event before it's published
  * @param event The event being prepared
diff --git a/client/src/client.ts b/client/src/client.ts
index 5a88b2f..f7dd135 100644
--- a/client/src/client.ts
+++ b/client/src/client.ts
@@ -41,7 +41,9 @@ import {
   initClientEventHandler,
   trackOutgoingEvent,
   handleIncomingResponse,
-  reconnectRelayService
+  reconnectRelayService,
+  markEventAsPublished,
+  isEventPublished
 } from './client-event-handler';
 import type { NostrEvent } from './converter';
 // Import functions from internal modules
@@ -609,10 +611,35 @@ function initNostrLogin(): void {
           authManager.setAuthenticated(true, pubkey);
         }
       }).catch(err => {
-        console.warn("Not currently connected to Nostr extension:", err);
+        console.warn("Not currently connected to Nostr provider:", err);
       });
     } else {
-      console.warn("Nostr extension not available");
+      console.warn("Nostr provider not available. Using nostr-login if available.");
+      
+      // Try to use nostr-login library if available
+      if (NostrLogin) {
+        try {
+          console.log("Using nostr-login in initNostrLogin");
+          const nostrLogin = new NostrLogin();
+          
+          nostrLogin.getPublicKey().then((pubkey: string) => {
+            if (pubkey) {
+              console.log(`Found pubkey from nostr-login: ${pubkey.slice(0, 8)}...`);
+              // Update UI to show pubkey
+              updateClientPubkeyDisplay(pubkey);
+              
+              // Update auth state in the service
+              authManager.setAuthenticated(true, pubkey);
+            }
+          }).catch((err: Error) => {
+            console.warn("Not currently connected to nostr-login:", err);
+          });
+        } catch (nostrLoginError) {
+          console.error('nostr-login error:', nostrLoginError);
+        }
+      } else {
+        console.warn("No Nostr provider available");
+      }
     }
   } catch (error) {
     const errorMessage = error instanceof Error ? error.message : String(error);
@@ -651,11 +678,9 @@ async function ensureAuthenticated(): Promise<boolean> {
     return true;
   }
   
-  // Not authenticated, check if extension is available
-  if (!window.nostr) {
-    console.warn("Nostr extension not available");
-    return false;
-  }
+  // Not authenticated, try to use nostr-login or extension
+  // We no longer need to check window.nostr because loginWithNostrLogin handles that
+  console.log("No active authentication, attempting to authenticate with nostr-login...");
   
   try {
     // Try to get the user's public key
@@ -698,6 +723,12 @@ async function handlePublishEvent(): Promise<void> {
             showLoading(publishResultDiv, 'Publishing to relay...');
             
             try {
+                // Check if this event has already been published
+                if (event.id && isEventPublished(event.id)) {
+                    showSuccess(publishResultDiv, "Event was already published, not sending duplicate");
+                    return;
+                }
+                
                 // Track the event before publishing
                 console.log('Tracking outgoing event:', event.id);
                 trackOutgoingEvent(event);
@@ -705,6 +736,12 @@ async function handlePublishEvent(): Promise<void> {
                 // Publish the event
                 console.log('Publishing event to relay:', relayUrl);
                 const result = await publishToRelay(event, relayUrl);
+                
+                // Mark the event as published to prevent duplicates
+                if (event.id) {
+                    markEventAsPublished(event.id);
+                }
+                
                 showSuccess(publishResultDiv, result);
                 
                 // Force reconnect to ensure we're subscribed for the response
@@ -782,6 +819,12 @@ async function handlePublishEvent(): Promise<void> {
         publishResultDiv.innerHTML += '<br><span>Attempting to publish...</span>';
         
         try {
+            // Check if this event has already been published
+            if (event.id && isEventPublished(event.id)) {
+                showSuccess(publishResultDiv, "Event was already published, not sending duplicate");
+                return;
+            }
+            
             // Track the event in our client store
             console.log('Tracking outgoing event:', event.id);
             trackOutgoingEvent(event);
@@ -789,6 +832,12 @@ async function handlePublishEvent(): Promise<void> {
             // Publish the event
             console.log('Publishing event to relay:', relayUrl);
             const result = await publishToRelay(event, relayUrl);
+            
+            // Mark the event as published to prevent duplicates
+            if (event.id) {
+                markEventAsPublished(event.id);
+            }
+            
             showSuccess(publishResultDiv, result);
             
             // Force reconnect to ensure we're subscribed for the response
@@ -1595,12 +1644,32 @@ document.addEventListener('DOMContentLoaded', function(): void {
     
     // Try to get pubkey again after DOM is ready
     if (window.nostr) {
-        window.nostr.getPublicKey().then(pubkey => {
-            console.log(`DOM ready: Retrieved pubkey: ${pubkey.slice(0, 8)}...`);
+        window.nostr.getPublicKey().then((pubkey: string) => {
+            console.log(`DOM ready: Retrieved pubkey from extension: ${pubkey.slice(0, 8)}...`);
             localStorage.setItem('userPublicKey', pubkey);
-        }).catch(err => {
-            console.warn("DOM ready: Failed to get pubkey:", err);
+        }).catch((err: Error) => {
+            console.warn("DOM ready: Failed to get pubkey from extension:", err);
         });
+    } else if (NostrLogin) {
+        // Try to use nostr-login if window.nostr is not available
+        try {
+            console.log("DOM ready: Using nostr-login to get pubkey");
+            const nostrLogin = new NostrLogin();
+            
+            nostrLogin.getPublicKey().then((pubkey: string) => {
+                if (pubkey) {
+                    console.log(`DOM ready: Retrieved pubkey from nostr-login: ${pubkey.slice(0, 8)}...`);
+                    localStorage.setItem('userPublicKey', pubkey);
+                    updateClientPubkeyDisplay(pubkey);
+                }
+            }).catch((err: Error) => {
+                console.warn("DOM ready: Failed to get pubkey from nostr-login:", err);
+            });
+        } catch (nostrLoginError) {
+            console.error('DOM ready: nostr-login error:', nostrLoginError);
+        }
+    } else {
+        console.warn("DOM ready: No Nostr provider available");
     }
     
     // Set default HTTP request
diff --git a/client/src/components/Nostr21121Creator.ts b/client/src/components/Nostr21121Creator.ts
index ad3a36c..d02e80b 100644
--- a/client/src/components/Nostr21121Creator.ts
+++ b/client/src/components/Nostr21121Creator.ts
@@ -190,7 +190,7 @@ export class Nostr21121Creator {
       
       // Always add reference to the request event
       if (requestEvent.id) {
-        tags.push(['e', requestEvent.id, '', 'reply']);
+        tags.push(['e', requestEvent.id]);
       }
       
       // Add kind reference
diff --git a/client/src/converter.ts b/client/src/converter.ts
index 9427a5c..0ccfda9 100644
--- a/client/src/converter.ts
+++ b/client/src/converter.ts
@@ -438,6 +438,12 @@ if (publishRelayInput) {
         
         // Import the tracking function from client-event-handler
         import('./client-event-handler').then(module => {
+            // Check if this event is already published
+            if (signedEvent.id && module.isEventPublished(signedEvent.id)) {
+                showSuccess(publishResult, "Event was already published, not sending duplicate");
+                return;
+            }
+            
             // Track the event before publishing
             try {
                 module.trackOutgoingEvent(signedEvent);
@@ -449,6 +455,10 @@ if (publishRelayInput) {
             // Publish the event using the publishToRelay function
             publishToRelay(signedEvent, relayUrl)
                 .then((result: string) => {
+                    // Mark the event as published to prevent duplicates
+                    if (signedEvent.id) {
+                        module.markEventAsPublished(signedEvent.id);
+                    }
                     showSuccess(publishResult, result);
                 })
                 .catch((error: Error) => {
@@ -685,16 +695,10 @@ if (publishRelayInput) {
 
 // Initialize event listeners when the DOM is fully loaded
 document.addEventListener('DOMContentLoaded', () => {
-    // Set up the click event handler without any automatic encryption
-    const convertButton = document.getElementById('convertButton');
+    // The Convert button event listener is already set in client.ts
+    // so we don't set it here to avoid duplicate calls and double events
     const publishButton = document.getElementById('publishButton');
     
-    if (convertButton) {
-        convertButton.addEventListener('click', (): void => {
-            void displayConvertedEvent();
-        });
-    }
-    
     // Add a handler for the publish button to check if an event is available
     if (publishButton) {
         publishButton.addEventListener('click', (): void => {
diff --git a/client/src/services/AuthenticationService.ts b/client/src/services/AuthenticationService.ts
index 2250311..527d928 100644
--- a/client/src/services/AuthenticationService.ts
+++ b/client/src/services/AuthenticationService.ts
@@ -4,9 +4,9 @@
  * Stateless authentication service that directly uses the Nostr extension.
  * Removed all localStorage and session dependencies.
  */
-
 import type * as nostrTools from 'nostr-tools';
 
+
 /**
  * Interface for authentication operation results
  */
@@ -64,32 +64,122 @@ export class AuthenticationService {
    */
   public async authenticate(): Promise<AuthResult> {
     try {
-      // Check if a Nostr extension is available
-      if (!window.nostr) {
-        return {
-          success: false,
-          error: 'Nostr extension not found. Please install Alby or nos2x.'
-        };
+      console.log("AuthenticationService: Using nostr-login for authentication");
+      
+      // Try to use nostr-login library if available
+      const nostrLoginModule = typeof require !== 'undefined' ? require('nostr-login') : null;
+      
+      if (nostrLoginModule && nostrLoginModule.init) {
+        try {
+          console.log("nostr-login loaded, initializing...");
+          
+          // Initialize nostr-login which sets up window.nostr
+          await nostrLoginModule.init({
+            // Options for nostr-login
+            darkMode: document.body.getAttribute('data-theme') === 'dark',
+            noBanner: true, // Don't show the banner
+          });
+          
+          console.log("nostr-login initialized, window.nostr should be available");
+          
+          // Check if window.nostr was successfully set up
+          if (window.nostr) {
+            console.log("Attempting to get pubkey through window.nostr...");
+            // Get pubkey through window.nostr
+            const pubkey = await window.nostr.getPublicKey();
+            console.log("window.nostr.getPublicKey returned:", pubkey);
+            
+            if (pubkey) {
+              console.log(`Authentication successful with pubkey: ${pubkey.substring(0, 8)}...`);
+              // Cache the pubkey in memory
+              this.cachedPubkey = pubkey;
+              
+              // Notify listeners of authentication change
+              this.notifyAuthStateChanged(true, pubkey);
+              
+              // Set the global nostrPubkey for backwards compatibility with existing code
+              if (window) {
+                window.nostrPubkey = pubkey;
+              }
+              
+              return {
+                success: true,
+                pubkey
+              };
+            }
+          } else {
+            console.error('nostr-login initialized but window.nostr is not available');
+          }
+        } catch (nostrLoginError) {
+          console.error('nostr-login error:', nostrLoginError);
+          console.error('nostr-login stack:', nostrLoginError instanceof Error ? nostrLoginError.stack : 'No stack available');
+          console.error('nostr-login error details:', JSON.stringify(nostrLoginError));
+          
+          // Check for specific error types
+          const errorMessage = nostrLoginError instanceof Error ? nostrLoginError.message : String(nostrLoginError);
+          
+          if (errorMessage.includes('Already started')) {
+            console.warn('nostr-login was already initialized, this is usually not a problem');
+            // Continue with window.nostr if it's available despite the "Already started" error
+            if (window.nostr) {
+              try {
+                console.log("nostr-login already initialized, using window.nostr directly");
+                const pubkey = await window.nostr.getPublicKey();
+                if (pubkey) {
+                  console.log(`Authentication successful with pubkey: ${pubkey.substring(0, 8)}...`);
+                  this.cachedPubkey = pubkey;
+                  this.notifyAuthStateChanged(true, pubkey);
+                  if (window) {
+                    window.nostrPubkey = pubkey;
+                  }
+                  return {
+                    success: true,
+                    pubkey
+                  };
+                }
+              } catch (directNostrError) {
+                console.error('Direct window.nostr error:', directNostrError);
+              }
+            }
+          } else if (errorMessage.includes('Rejected by user') || errorMessage.includes('Cancelled')) {
+            console.warn('User rejected or cancelled the nostr-login authentication');
+            return {
+              success: false,
+              error: 'Authentication was cancelled by the user. Please try again.'
+            };
+          }
+          // Fall back to window.nostr if NostrLogin fails for other reasons
+        }
       }
       
-      // Directly request the public key from the Nostr extension
-      const pubkey = await window.nostr.getPublicKey();
-      
-      if (pubkey) {
-        // Cache the pubkey in memory
-        this.cachedPubkey = pubkey;
+      // Fall back to window.nostr if NostrLogin is not available
+      if (window.nostr) {
+        console.log("Falling back to window.nostr");
         
-        // Notify listeners of authentication change
-        this.notifyAuthStateChanged(true, pubkey);
+        // Directly request the public key from the Nostr extension
+        const pubkey = await window.nostr.getPublicKey();
         
-        // Set the global nostrPubkey for backwards compatibility with existing code
-        if (window) {
-          window.nostrPubkey = pubkey;
+        if (pubkey) {
+          // Cache the pubkey in memory
+          this.cachedPubkey = pubkey;
+          
+          // Notify listeners of authentication change
+          this.notifyAuthStateChanged(true, pubkey);
+          
+          // Set the global nostrPubkey for backwards compatibility with existing code
+          if (window) {
+            window.nostrPubkey = pubkey;
+          }
+          
+          return {
+            success: true,
+            pubkey
+          };
         }
-        
+      } else {
         return {
-          success: true,
-          pubkey
+          success: false,
+          error: 'Authentication failed. No Nostr provider found.'
         };
       }
       
@@ -119,9 +209,52 @@ export class AuthenticationService {
         return true;
       }
       
-      // No cached pubkey, try to get it from the extension
+      // Try to use nostr-login library if available
+      const nostrLoginModule = typeof require !== 'undefined' ? require('nostr-login') : null;
+      
+      if (nostrLoginModule && nostrLoginModule.init) {
+        try {
+          console.log("Using nostr-login to check authentication");
+          
+          // Initialize nostr-login which sets up window.nostr
+          await nostrLoginModule.init({
+            darkMode: document.body.getAttribute('data-theme') === 'dark',
+            noBanner: true, // Don't show the banner
+          });
+          
+          console.log("nostr-login initialized for auth check, window.nostr should be available");
+          
+          // Check if window.nostr was successfully set up
+          if (window.nostr) {
+            console.log("Attempting to get pubkey through window.nostr for auth check...");
+            // Get pubkey through window.nostr
+            const pubkey = await window.nostr.getPublicKey();
+            console.log("window.nostr.getPublicKey returned for auth check:", pubkey);
+            
+            if (pubkey) {
+              console.log(`Authentication check successful with pubkey: ${pubkey.substring(0, 8)}...`);
+              this.cachedPubkey = pubkey;
+              // Set the global nostrPubkey for backwards compatibility
+              if (window) {
+                window.nostrPubkey = pubkey;
+              }
+              return true;
+            }
+          } else {
+            console.error('nostr-login initialized but window.nostr is not available for auth check');
+          }
+        } catch (nostrLoginError) {
+          console.error('Failed to get pubkey from nostr-login:', nostrLoginError);
+          console.error('nostr-login stack:', nostrLoginError instanceof Error ? nostrLoginError.stack : 'No stack available');
+          console.error('nostr-login error details:', JSON.stringify(nostrLoginError));
+          // Fall back to window.nostr if NostrLogin fails
+        }
+      }
+      
+      // Fall back to window.nostr if NostrLogin is not available
       if (window.nostr) {
         try {
+          console.log("Falling back to window.nostr to check authentication");
           const pubkey = await window.nostr.getPublicKey();
           if (pubkey) {
             this.cachedPubkey = pubkey;
@@ -163,12 +296,52 @@ export class AuthenticationService {
   public async getPubkey(): Promise<string | null> {
     // If we have a cached pubkey, return it
     if (this.cachedPubkey) {
+      console.log(`Using cached pubkey: ${this.cachedPubkey.substring(0, 8)}...`);
       return this.cachedPubkey;
     }
     
-    // Try to get pubkey from extension
+    // Try to use nostr-login library if available
+    const nostrLoginModule = typeof require !== 'undefined' ? require('nostr-login') : null;
+    
+    if (nostrLoginModule && nostrLoginModule.init) {
+      try {
+        console.log("Using nostr-login to get pubkey");
+        
+        // Initialize nostr-login which sets up window.nostr
+        await nostrLoginModule.init({
+          darkMode: document.body.getAttribute('data-theme') === 'dark',
+          noBanner: true, // Don't show the banner
+        });
+        
+        console.log("nostr-login initialized in getPubkey, window.nostr should be available");
+        
+        // Check if window.nostr was successfully set up
+        if (window.nostr) {
+          console.log("Attempting to get pubkey through window.nostr in getPubkey...");
+          // Get pubkey through window.nostr
+          const pubkey = await window.nostr.getPublicKey();
+          console.log("window.nostr.getPublicKey returned in getPubkey:", pubkey);
+          
+          if (pubkey) {
+            console.log(`getPubkey successful with: ${pubkey.substring(0, 8)}...`);
+            this.cachedPubkey = pubkey;
+            return pubkey;
+          }
+        } else {
+          console.error('nostr-login initialized but window.nostr is not available in getPubkey');
+        }
+      } catch (nostrLoginError) {
+        console.error('Failed to get pubkey from nostr-login:', nostrLoginError);
+        console.error('NostrLogin stack:', nostrLoginError instanceof Error ? nostrLoginError.stack : 'No stack available');
+        console.error('NostrLogin error details:', JSON.stringify(nostrLoginError));
+        // Fall back to window.nostr if NostrLogin fails
+      }
+    }
+    
+    // Fall back to window.nostr if NostrLogin is not available
     try {
       if (window.nostr) {
+        console.log("Falling back to window.nostr to get pubkey");
         const pubkey = await window.nostr.getPublicKey();
         if (pubkey) {
           this.cachedPubkey = pubkey;
diff --git a/client/src/services/Nostr21121Service.ts b/client/src/services/Nostr21121Service.ts
index d6ed409..3fa0898 100644
--- a/client/src/services/Nostr21121Service.ts
+++ b/client/src/services/Nostr21121Service.ts
@@ -96,7 +96,7 @@ export class Nostr21121Service {
       
       // Always add reference to the request event
       if (requestEvent.id) {
-        tags.push(['e', requestEvent.id, '']);
+        tags.push(['e', requestEvent.id]);
       }
       
       // Get the pubkey of the request creator (client) for encryption
diff --git a/client/src/services/Nostr31120Service.ts b/client/src/services/Nostr31120Service.ts
index 6627b6b..1ba499e 100644
--- a/client/src/services/Nostr31120Service.ts
+++ b/client/src/services/Nostr31120Service.ts
@@ -192,21 +192,41 @@ export class Nostr31120Service {
         }
       }
 
-      // Check if window.nostr (Nostr browser extension) is available
-      if (!window.nostr) {
-        throw new Error('No Nostr browser extension found. Please install a NIP-07 compatible extension.');
+      // Try to use nostr-login library if available
+      const NostrLogin = typeof require !== 'undefined' ? require('nostr-login') : null;
+      let nostrProvider = null;
+      
+      // Try nostr-login first
+      if (NostrLogin) {
+        try {
+          console.log("Using nostr-login in Nostr31120Service");
+          nostrProvider = new NostrLogin();
+        } catch (nostrLoginError) {
+          console.error('NostrLogin error:', nostrLoginError);
+          // Fall back to window.nostr
+        }
       }
       
-      // Get user's public key using the extension
+      // Fall back to window.nostr if nostr-login is not available
+      if (!nostrProvider && window.nostr) {
+        nostrProvider = window.nostr;
+      }
+      
+      // Check if we have a Nostr provider
+      if (!nostrProvider) {
+        throw new Error('No Nostr provider found. Authentication with nostr-login was unsuccessful.');
+      }
+      
+      // Get user's public key using the Nostr provider
       let userPubkey: string;
       try {
-        userPubkey = await window.nostr!.getPublicKey();
+        userPubkey = await nostrProvider.getPublicKey();
         if (!userPubkey) {
-          throw new Error('Failed to get public key from Nostr extension');
+          throw new Error('Failed to get public key from Nostr provider');
         }
       } catch (error) {
-        console.error('Error getting public key from Nostr extension:', error);
-        throw new Error('Failed to get your public key. Please make sure your Nostr extension is working.');
+        console.error('Error getting public key from Nostr provider:', error);
+        throw new Error('Failed to get your public key. Authentication with nostr-login was unsuccessful.');
       }
       
       // Generate or use a provided server pubkey
@@ -269,14 +289,14 @@ export class Nostr31120Service {
         content: content || 'HTTP-over-Nostr server',
       };
       
-      // Sign the event using the browser extension
+      // Sign the event using the Nostr provider
       let signedEvent: NostrEvent;
       try {
-        signedEvent = await window.nostr!.signEvent(unsignedEvent);
-        console.log('Event signed successfully with Nostr extension');
+        signedEvent = await nostrProvider.signEvent(unsignedEvent);
+        console.log('Event signed successfully with Nostr provider');
       } catch (error) {
-        console.error('Error signing event with Nostr extension:', error);
-        throw new Error('Failed to sign the event with your Nostr extension');
+        console.error('Error signing event with Nostr provider:', error);
+        throw new Error('Failed to sign the event. Authentication with nostr-login was unsuccessful.');
       }
       
       // Publish to relay
@@ -362,14 +382,39 @@ export class Nostr31120Service {
         content: content || 'HTTP-over-Nostr server',
       };
       
-      // Sign the event using the browser extension
+      // Sign the event using the Nostr provider
       let signedEvent: NostrEvent;
       try {
-        signedEvent = await window.nostr!.signEvent(unsignedEvent);
-        console.log('Event signed successfully with Nostr extension');
+        // Try to use nostr-login library if available
+        const NostrLogin = typeof require !== 'undefined' ? require('nostr-login') : null;
+        let nostrProvider = null;
+        
+        // Try nostr-login first
+        if (NostrLogin) {
+          try {
+            console.log("Using nostr-login in processEventWithServerKey");
+            nostrProvider = new NostrLogin();
+          } catch (nostrLoginError) {
+            console.error('NostrLogin error:', nostrLoginError);
+            // Fall back to window.nostr
+          }
+        }
+        
+        // Fall back to window.nostr if nostr-login is not available
+        if (!nostrProvider && window.nostr) {
+          nostrProvider = window.nostr;
+        }
+        
+        // Check if we have a Nostr provider
+        if (!nostrProvider) {
+          throw new Error('No Nostr provider found. Authentication with nostr-login was unsuccessful.');
+        }
+        
+        signedEvent = await nostrProvider.signEvent(unsignedEvent);
+        console.log('Event signed successfully with Nostr provider');
       } catch (error) {
-        console.error('Error signing event with Nostr extension:', error);
-        throw new Error('Failed to sign the event with your Nostr extension');
+        console.error('Error signing event with Nostr provider:', error);
+        throw new Error('Failed to sign the event. Authentication with nostr-login was unsuccessful.');
       }
       
       // Publish to relay
diff --git a/package-lock.json b/package-lock.json
index 1941a34..6d2095e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -17,7 +17,6 @@
       "version": "5.0.1",
       "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
       "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
-      "license": "MIT",
       "engines": {
         "node": ">=8"
       }
@@ -26,7 +25,6 @@
       "version": "4.3.0",
       "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
       "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-      "license": "MIT",
       "dependencies": {
         "color-convert": "^2.0.1"
       },
@@ -41,7 +39,6 @@
       "version": "5.3.1",
       "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
       "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
-      "license": "MIT",
       "engines": {
         "node": ">=6"
       }
@@ -50,7 +47,6 @@
       "version": "6.0.0",
       "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
       "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
-      "license": "ISC",
       "dependencies": {
         "string-width": "^4.2.0",
         "strip-ansi": "^6.0.0",
@@ -61,7 +57,6 @@
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
       "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-      "license": "MIT",
       "dependencies": {
         "color-name": "~1.1.4"
       },
@@ -72,14 +67,12 @@
     "node_modules/color-name": {
       "version": "1.1.4",
       "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-      "license": "MIT"
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
     },
     "node_modules/decamelize": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
       "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
-      "license": "MIT",
       "engines": {
         "node": ">=0.10.0"
       }
@@ -87,20 +80,17 @@
     "node_modules/dijkstrajs": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz",
-      "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==",
-      "license": "MIT"
+      "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA=="
     },
     "node_modules/emoji-regex": {
       "version": "8.0.0",
       "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
-      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
-      "license": "MIT"
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
     },
     "node_modules/find-up": {
       "version": "4.1.0",
       "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
       "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
-      "license": "MIT",
       "dependencies": {
         "locate-path": "^5.0.0",
         "path-exists": "^4.0.0"
@@ -113,7 +103,6 @@
       "version": "2.0.5",
       "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
       "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
-      "license": "ISC",
       "engines": {
         "node": "6.* || 8.* || >= 10.*"
       }
@@ -122,7 +111,6 @@
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
       "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
-      "license": "MIT",
       "engines": {
         "node": ">=8"
       }
@@ -130,14 +118,12 @@
     "node_modules/jsqr": {
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/jsqr/-/jsqr-1.4.0.tgz",
-      "integrity": "sha512-dxLob7q65Xg2DvstYkRpkYtmKm2sPJ9oFhrhmudT1dZvNFFTlroai3AWSpLey/w5vMcLBXRgOJsbXpdN9HzU/A==",
-      "license": "Apache-2.0"
+      "integrity": "sha512-dxLob7q65Xg2DvstYkRpkYtmKm2sPJ9oFhrhmudT1dZvNFFTlroai3AWSpLey/w5vMcLBXRgOJsbXpdN9HzU/A=="
     },
     "node_modules/locate-path": {
       "version": "5.0.0",
       "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
       "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
-      "license": "MIT",
       "dependencies": {
         "p-locate": "^4.1.0"
       },
@@ -149,7 +135,6 @@
       "version": "2.3.0",
       "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
       "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
-      "license": "MIT",
       "dependencies": {
         "p-try": "^2.0.0"
       },
@@ -164,7 +149,6 @@
       "version": "4.1.0",
       "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
       "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
-      "license": "MIT",
       "dependencies": {
         "p-limit": "^2.2.0"
       },
@@ -176,7 +160,6 @@
       "version": "2.2.0",
       "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
       "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
-      "license": "MIT",
       "engines": {
         "node": ">=6"
       }
@@ -185,7 +168,6 @@
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
       "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
-      "license": "MIT",
       "engines": {
         "node": ">=8"
       }
@@ -194,7 +176,6 @@
       "version": "5.0.0",
       "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz",
       "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==",
-      "license": "MIT",
       "engines": {
         "node": ">=10.13.0"
       }
@@ -203,7 +184,6 @@
       "version": "1.5.4",
       "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.4.tgz",
       "integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==",
-      "license": "MIT",
       "dependencies": {
         "dijkstrajs": "^1.0.1",
         "pngjs": "^5.0.0",
@@ -220,7 +200,6 @@
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
       "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
-      "license": "MIT",
       "engines": {
         "node": ">=0.10.0"
       }
@@ -228,20 +207,17 @@
     "node_modules/require-main-filename": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
-      "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
-      "license": "ISC"
+      "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="
     },
     "node_modules/set-blocking": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
-      "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
-      "license": "ISC"
+      "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="
     },
     "node_modules/string-width": {
       "version": "4.2.3",
       "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
       "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
-      "license": "MIT",
       "dependencies": {
         "emoji-regex": "^8.0.0",
         "is-fullwidth-code-point": "^3.0.0",
@@ -255,7 +231,6 @@
       "version": "6.0.1",
       "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
       "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
-      "license": "MIT",
       "dependencies": {
         "ansi-regex": "^5.0.1"
       },
@@ -266,14 +241,12 @@
     "node_modules/which-module": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz",
-      "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==",
-      "license": "ISC"
+      "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ=="
     },
     "node_modules/wrap-ansi": {
       "version": "6.2.0",
       "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
       "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
-      "license": "MIT",
       "dependencies": {
         "ansi-styles": "^4.0.0",
         "string-width": "^4.1.0",
@@ -286,14 +259,12 @@
     "node_modules/y18n": {
       "version": "4.0.3",
       "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
-      "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
-      "license": "ISC"
+      "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ=="
     },
     "node_modules/yargs": {
       "version": "15.4.1",
       "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
       "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
-      "license": "MIT",
       "dependencies": {
         "cliui": "^6.0.0",
         "decamelize": "^1.2.0",
@@ -315,7 +286,6 @@
       "version": "18.1.3",
       "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
       "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
-      "license": "ISC",
       "dependencies": {
         "camelcase": "^5.0.0",
         "decamelize": "^1.2.0"