diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp
index a3df6a3ced803cea339aa7df02542c3f5b4a0265..15edf270bd614d4ae9c1d13bcaa5293affe8c3fd 100644
--- a/indra/llui/llnotifications.cpp
+++ b/indra/llui/llnotifications.cpp
@@ -81,6 +81,7 @@ LLNotificationForm::FormButton::FormButton()
 
 LLNotificationForm::FormInput::FormInput()
 :	type("type"),
+	text("text"),
 	max_length_chars("max_length_chars"),
 	width("width", 0),
 	value("value")
@@ -404,7 +405,7 @@ LLNotificationTemplate::LLNotificationTemplate(const LLNotificationTemplate::Par
 		it != end_it;
 		++it)
 	{
-		mUniqueContext.push_back(it->key);
+		mUniqueContext.push_back(it->value);
 	}
 
 	mForm = LLNotificationFormPtr(new LLNotificationForm(p.name, p.form_ref.form));
@@ -719,13 +720,19 @@ bool LLNotification::isEquivalentTo(LLNotificationPtr that) const
 	{
 		const LLSD& these_substitutions = this->getSubstitutions();
 		const LLSD& those_substitutions = that->getSubstitutions();
+		const LLSD& this_payload = this->getPayload();
+		const LLSD& that_payload = that->getPayload();
 
 		// highlander bit sez there can only be one of these
 		for (std::vector<std::string>::const_iterator it = mTemplatep->mUniqueContext.begin(), end_it = mTemplatep->mUniqueContext.end();
 			it != end_it;
 			++it)
 		{
-			if (these_substitutions.get(*it).asString() != those_substitutions.get(*it).asString())
+			// if templates differ in either substitution strings or payload with the given field name
+			// then they are considered inequivalent
+			// use of get() avoids converting the LLSD value to a map as the [] operator would
+			if (these_substitutions.get(*it).asString() != those_substitutions.get(*it).asString()
+				|| this_payload.get(*it).asString() != that_payload.get(*it).asString())
 			{
 				return false;
 			}
diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h
index 524cff70e80143d5a5685999617b47893c937849..a607f52b97d43f204a5e5fa602c6de9f5254be32 100644
--- a/indra/llui/llnotifications.h
+++ b/indra/llui/llnotifications.h
@@ -195,6 +195,7 @@ class LLNotificationForm
 		Mandatory<std::string>	type;
 		Optional<S32>			width;
 		Optional<S32>			max_length_chars;
+		Optional<std::string>	text;
 
 		Optional<std::string>	value;
 		FormInput();
diff --git a/indra/llui/llnotificationtemplate.h b/indra/llui/llnotificationtemplate.h
index 6bc0d2aaffd358b3a3cd87746cd422f0a2eb294b..644d5c4d7480c6b8bb9fe50ec8fd7eb3bada7d89 100644
--- a/indra/llui/llnotificationtemplate.h
+++ b/indra/llui/llnotificationtemplate.h
@@ -74,11 +74,13 @@ struct LLNotificationTemplate
 
 	struct UniquenessContext : public LLInitParam::Block<UniquenessContext>
 	{
-		Mandatory<std::string>	key;
+		Mandatory<std::string>	value;
 
 		UniquenessContext()
-		:	key("key")
-		{}
+		:	value("value")
+		{
+			addSynonym(value, "key");
+		}
 		
 	};
 
@@ -88,7 +90,7 @@ struct LLNotificationTemplate
 		// this idiom allows 
 		// <notification unique="true">
 		// as well as
-		// <notification> <unique> <context key=""/> </unique>...
+		// <notification> <unique> <context></context> </unique>...
 		Optional<bool>			dummy_val;
 	public:
 		Multiple<UniquenessContext>	contexts;
@@ -232,8 +234,8 @@ struct LLNotificationTemplate
     // (used for things like progress indications, or repeating warnings
     // like "the grid is going down in N minutes")
     bool mUnique;
-    // if we want to be unique only if a certain part of the payload is constant
-    // specify the field names for the payload. The notification will only be
+    // if we want to be unique only if a certain part of the payload or substitutions args
+	// are constant specify the field names for the payload. The notification will only be
     // combined if all of the fields named in the context are identical in the
     // new and the old notification; otherwise, the notification will be
     // duplicated. This is to support suppressing duplicate offers from the same
diff --git a/indra/newview/llbrowsernotification.cpp b/indra/newview/llbrowsernotification.cpp
index d6a813d60806ddefbbed85abc3a20d0eddb506a0..633ef4f1cefb2452cf0851202bb1ff027d6cbaaf 100644
--- a/indra/newview/llbrowsernotification.cpp
+++ b/indra/newview/llbrowsernotification.cpp
@@ -29,8 +29,8 @@
 
 #include "llnotificationhandler.h"
 #include "llnotifications.h"
-#include "llfloaterreg.h"
 #include "llmediactrl.h"
+#include "llviewermedia.h"
 
 using namespace LLNotificationsUI;
 
diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp
index 0a5263d1ab4cbbf1a3db3e9359cc80b3708df3ce..edfc039036108107029df3168127de6e3c851805 100644
--- a/indra/newview/llmediactrl.cpp
+++ b/indra/newview/llmediactrl.cpp
@@ -54,6 +54,7 @@
 #include "llbutton.h"
 #include "llcheckboxctrl.h"
 #include "llnotifications.h"
+#include "lllineeditor.h"
 
 extern BOOL gRestoreGL;
 
@@ -69,7 +70,6 @@ LLMediaCtrl::Params::Params()
 	texture_height("texture_height", 1024),
 	caret_color("caret_color"),
 	initial_mime_type("initial_mime_type"),
-	media_id("media_id"),
 	trusted_content("trusted_content", false)
 {
 	tab_stop(false);
@@ -126,7 +126,7 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) :
 		setTextureSize(screen_width, screen_height);
 	}
 	
-	mMediaTextureID.generate();
+	mMediaTextureID = getKey();
 	
 	// We don't need to create the media source up front anymore unless we have a non-empty home URL to navigate to.
 	if(!mHomePageUrl.empty())
@@ -140,8 +140,6 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) :
 //	addChild( mBorder );
 }
 
-////////////////////////////////////////////////////////////////////////////////
-// note: this is now a singleton and destruction happens via initClass() now
 LLMediaCtrl::~LLMediaCtrl()
 {
 
@@ -1037,7 +1035,7 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
 
 			LLNotification::Params notify_params;
 			notify_params.name = "PopupAttempt";
-			notify_params.payload = LLSD().with("target", target).with("url", url).with("uuid", uuid).with("media_id", getKey());
+			notify_params.payload = LLSD().with("target", target).with("url", url).with("uuid", uuid).with("media_id", mMediaTextureID);
 			notify_params.functor.function = boost::bind(&LLMediaCtrl::onPopup, this, _1, _2);
 
 			if (mTrusted)
@@ -1095,8 +1093,12 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
 
 		case MEDIA_EVENT_AUTH_REQUEST:
 		{
-			LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_AUTH_REQUEST, url " << self->getAuthURL() << ", realm " << self->getAuthRealm() << LL_ENDL;
-		}
+			LLNotification::Params auth_request_params;
+			auth_request_params.name = "AuthRequest";
+			auth_request_params.payload = LLSD().with("media_id", mMediaTextureID);
+			auth_request_params.functor.function = boost::bind(&LLMediaCtrl::onAuthSubmit, this, _1, _2);
+			LLNotifications::instance().add(auth_request_params);
+		};
 		break;
 	};
 
@@ -1122,9 +1124,21 @@ void LLMediaCtrl::onPopup(const LLSD& notification, const LLSD& response)
 		// Make sure the opening instance knows its window open request was denied, so it can clean things up.
 		LLViewerMedia::proxyWindowClosed(notification["payload"]["uuid"]);
 	}
+}
 
+void LLMediaCtrl::onAuthSubmit(const LLSD& notification, const LLSD& response)
+{
+	if (response["ok"])
+	{
+		mMediaSource->getMediaPlugin()->sendAuthResponse(true, response["username"], response["password"]);
+	}
+	else
+	{
+		mMediaSource->getMediaPlugin()->sendAuthResponse(false, "", "");
+	}
 }
 
+
 void LLMediaCtrl::onCloseNotification()
 {
 	LLNotifications::instance().cancel(mCurNotification);
@@ -1145,15 +1159,20 @@ void LLMediaCtrl::onClickNotificationButton(const std::string& name)
 {
 	if (!mCurNotification) return;
 
-	LLSD response = mCurNotification->getResponseTemplate();
-	response[name] = true;
+	mCurNotificationResponse[name] = true;
 
-	mCurNotification->respond(response); 
+	mCurNotification->respond(mCurNotificationResponse);
+}
+
+void LLMediaCtrl::onEnterNotificationText(LLUICtrl* ctrl, const std::string& name)
+{
+	mCurNotificationResponse[name] = ctrl->getValue().asString();
 }
 
 void LLMediaCtrl::showNotification(LLNotificationPtr notify)
 {
 	mCurNotification = notify;
+	mCurNotificationResponse = notify->getResponseTemplate();
 
 	// add popup here
 	LLSD payload = notify->getPayload();
@@ -1206,12 +1225,30 @@ void LLMediaCtrl::showNotification(LLNotificationPtr notify)
 
 			cur_x = button->getRect().mRight + FORM_PADDING_HORIZONTAL;
 		}
+		else if (form_element["type"].asString() == "text")
+		{
+			LLTextBox::Params label_p;
+			label_p.name = form_element["name"].asString() + "_label";
+			label_p.rect = LLRect(cur_x, form_elements.getRect().getHeight() - FORM_PADDING_VERTICAL, cur_x + 120, FORM_PADDING_VERTICAL);
+			label_p.initial_value = form_element["text"];
+			LLTextBox* textbox = LLUICtrlFactory::create<LLTextBox>(label_p);
+			textbox->reshapeToFitText();
+			form_elements.addChild(textbox);
+			cur_x = textbox->getRect().mRight + FORM_PADDING_HORIZONTAL;
+
+			LLLineEditor::Params line_p;
+			line_p.name = form_element["name"];
+			line_p.commit_callback.function = boost::bind(&LLMediaCtrl::onEnterNotificationText, this, _1, form_element["name"].asString());
+			line_p.commit_on_focus_lost = true;
+			line_p.rect = LLRect(cur_x, form_elements.getRect().getHeight() - FORM_PADDING_VERTICAL, cur_x + 120, FORM_PADDING_VERTICAL);
+
+			LLLineEditor* line_editor = LLUICtrlFactory::create<LLLineEditor>(line_p);
+			form_elements.addChild(line_editor);
+			cur_x = line_editor->getRect().mRight + FORM_PADDING_HORIZONTAL;
+		}
 	}
 
-
 	form_elements.reshape(cur_x, form_elements.getRect().getHeight());
-
-	//LLWeb::loadURL(payload["url"], payload["target"]);
 }
 
 void LLMediaCtrl::hideNotification()
diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h
index 65dfbbff7864732ad2df9a2523b5198f6671aaee..5b18099c7679dce49f44d415307ec1d1e1e22cd8 100644
--- a/indra/newview/llmediactrl.h
+++ b/indra/newview/llmediactrl.h
@@ -61,7 +61,6 @@ class LLMediaCtrl :
 		Optional<LLUIColor>		caret_color;
 
 		Optional<std::string>	initial_mime_type;
-		Optional<std::string>	media_id;
 		
 		Params();
 	};
@@ -167,8 +166,10 @@ class LLMediaCtrl :
 	private:
 		void onVisibilityChange ( const LLSD& new_visibility );
 		void onPopup(const LLSD& notification, const LLSD& response);
+		void onAuthSubmit(const LLSD& notification, const LLSD& response);
 		void onCloseNotification();
 		void onClickNotificationButton(const std::string& name);
+		void onEnterNotificationText(LLUICtrl* ctrl, const std::string& name);
 		void onClickIgnore(LLUICtrl* ctrl);
 
 		const S32 mTextureDepthBytes;
@@ -194,6 +195,7 @@ class LLMediaCtrl :
 		S32 mTextureHeight;
 		bool mClearCache;
 		boost::shared_ptr<class LLNotification> mCurNotification;
+		LLSD mCurNotificationResponse;
 };
 
 #endif // LL_LLMediaCtrl_H
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index bcac6533e6138a4ef47fb4b19a78a77fa1a9e1b4..9df4ba2ea219c1e07ffcd5959f4243b9f674b2a7 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -2903,7 +2903,6 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla
 			LL_DEBUGS("Media") << "MEDIA_EVENT_CLICK_LINK_NOFOLLOW, uri is: " << plugin->getClickURL() << LL_ENDL; 
 			std::string url = plugin->getClickURL();
 			LLURLDispatcher::dispatch(url, NULL, mTrustedBrowser);
-
 		}
 		break;
 		case MEDIA_EVENT_CLICK_LINK_HREF:
@@ -3060,10 +3059,9 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla
 		case LLViewerMediaObserver::MEDIA_EVENT_AUTH_REQUEST:
 		{
 			llinfos <<  "MEDIA_EVENT_AUTH_REQUEST, url " << plugin->getAuthURL() << ", realm " << plugin->getAuthRealm() << LL_ENDL;
-			
-			// TODO: open an auth dialog that will call this when complete
-			plugin->sendAuthResponse(false, "", "");
+			//plugin->sendAuthResponse(false, "", "");
 		}
+		break;
 		
 		case LLViewerMediaObserver::MEDIA_EVENT_CLOSE_REQUEST:
 		{
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index a0fd0a13ccea2a0e24b830aaba974e6f3353e785..190418e38452efb105d8b37c6bbf17476413e4bf 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -4983,7 +4983,7 @@ If you want to view streaming media on parcels that support it you should go to
    type="notify">
 No Media Plugin was found to handle the "[MIME_TYPE]" mime type.  Media of this type will be unavailable.
     <unique>
-      <context key="[MIME_TYPE]"/>
+      <context>MIME_TYPE</context>
     </unique>
 
   </notification>
@@ -5885,7 +5885,7 @@ You may only select up to [MAX_SELECT] items from this list.
 [NAME] is inviting you to a Voice Chat call.
 Click Accept to join the call or Decline to decline the invitation. Click Block to block this caller.
     <unique>
-      <context key="NAME"/>
+      <context>NAME</context>
     </unique>
     <form name="form">
       <button
@@ -5934,8 +5934,8 @@ Click Accept to join the call or Decline to decline the invitation. Click Block
 [NAME] has joined a Voice Chat call with the group [GROUP].
 Click Accept to join the call or Decline to decline the invitation. Click Block to block this caller.
     <unique>
-      <context key="NAME"/>
-      <context key="GROUP"/>
+      <context>NAME</context>
+      <context>GROUP</context>
     </unique>
     <form name="form">
       <button
@@ -5960,7 +5960,7 @@ Click Accept to join the call or Decline to decline the invitation. Click Block
 [NAME] has joined a voice chat call with a conference chat.
 Click Accept to join the call or Decline to decline the invitation. Click Block to block this caller.
     <unique>
-      <context key="NAME"/>
+      <context>NAME</context>
     </unique>
     <form name="form">
       <button
@@ -5985,7 +5985,7 @@ Click Accept to join the call or Decline to decline the invitation. Click Block
 [NAME] is inviting you to a conference chat.
 Click Accept to join the chat or Decline to decline the invitation. Click Block to block this caller.
     <unique>
-      <context key="NAME"/>
+      <context>NAME</context>
     </unique>
     <form name="form">
       <button
@@ -6009,7 +6009,7 @@ Click Accept to join the chat or Decline to decline the invitation. Click Block
    type="notifytip">
 The voice call you are trying to join, [VOICE_CHANNEL_NAME], has reached maximum capacity. Please try again later.
     <unique>
-      <context key="VOICE_CHANNEL_NAME"/>
+      <context>VOICE_CHANNEL_NAME</context>
     </unique>
   </notification>
 
@@ -6027,7 +6027,7 @@ We&apos;re sorry.  This area has reached maximum capacity for voice conversation
    type="notifytip">
 You have been disconnected from [VOICE_CHANNEL_NAME].  You will now be reconnected to Nearby Voice Chat.
     <unique>
-      <context key="VOICE_CHANNEL_NAME"/>
+      <context>VOICE_CHANNEL_NAME</context>
     </unique>
   </notification>
 
@@ -6037,7 +6037,7 @@ You have been disconnected from [VOICE_CHANNEL_NAME].  You will now be reconnect
    type="notifytip">
 [VOICE_CHANNEL_NAME] has ended the call.  You will now be reconnected to Nearby Voice Chat.
     <unique>
-      <context key="VOICE_CHANNEL_NAME"/>
+      <context>VOICE_CHANNEL_NAME</context>
     </unique>
   </notification>
 
@@ -6047,7 +6047,7 @@ You have been disconnected from [VOICE_CHANNEL_NAME].  You will now be reconnect
    type="notifytip">
 [VOICE_CHANNEL_NAME] has declined your call.  You will now be reconnected to Nearby Voice Chat.
     <unique>
-      <context key="VOICE_CHANNEL_NAME"/>
+      <context>VOICE_CHANNEL_NAME</context>
     </unique>
   </notification>
 
@@ -6057,7 +6057,7 @@ You have been disconnected from [VOICE_CHANNEL_NAME].  You will now be reconnect
    type="notifytip">
 [VOICE_CHANNEL_NAME] is not available to take your call.  You will now be reconnected to Nearby Voice Chat.
     <unique>
-      <context key="VOICE_CHANNEL_NAME"/>
+      <context>VOICE_CHANNEL_NAME</context>
     </unique>
   </notification>
 
@@ -6067,7 +6067,7 @@ You have been disconnected from [VOICE_CHANNEL_NAME].  You will now be reconnect
    type="notifytip">
 Failed to connect to [VOICE_CHANNEL_NAME], please try again later.  You will now be reconnected to Nearby Voice Chat.
     <unique>
-      <context key="VOICE_CHANNEL_NAME"/>
+      <context>VOICE_CHANNEL_NAME</context>
     </unique>
   </notification>
 
@@ -6150,7 +6150,7 @@ Cannot enter parcel, you are not on the access list.
    type="notifytip">
 You do not have permission to connect to voice chat for [VOICE_CHANNEL_NAME].
     <unique>
-      <context key="VOICE_CHANNEL_NAME"/>
+      <context>VOICE_CHANNEL_NAME</context>
     </unique>
   </notification>
 
@@ -6160,7 +6160,7 @@ You do not have permission to connect to voice chat for [VOICE_CHANNEL_NAME].
    type="notifytip">
 An error has occurred while trying to connect to voice chat for [VOICE_CHANNEL_NAME].  Please try again later.
     <unique>
-      <context key="VOICE_CHANNEL_NAME"/>
+      <context>VOICE_CHANNEL_NAME</context>
     </unique>
   </notification>
 
@@ -6548,6 +6548,23 @@ Mute everyone?
     </form>
   </notification>
 
+  <notification
+  name="AuthRequest"
+  type="browser">
+    Enter user name and password to continue.
+    <form name="form">
+      <input name="username" type="text" text="User Name"/>
+      <input name="password" type="text" text="Password"/>
+      <button default="true"
+              index="0"
+              name="ok"
+              text="Submit"/>
+      <button index="1"
+              name="cancel"
+              text="Cancel"/>
+    </form>
+  </notification>
+
   
   <global name="UnsupportedCPU">
 - Your CPU speed does not meet the minimum requirements.