diff --git a/librtmp/rtmp.c b/librtmp/rtmp.c
index 5ef3ae9..adcff1f 100644
--- a/librtmp/rtmp.c
+++ b/librtmp/rtmp.c
@@ -96,6 +96,7 @@ static int SendDeleteStream(RTMP *r, double dStreamId);
 static int SendFCSubscribe(RTMP *r, AVal *subscribepath);
 static int SendPlay(RTMP *r);
 static int SendBytesReceived(RTMP *r);
+static int SendUsherToken(RTMP *r, AVal *usherToken);
 
 #if 0				/* unused */
 static int SendBGHasStream(RTMP *r, double dId, AVal *playpath);
@@ -335,6 +336,7 @@ RTMP_SetupStream(RTMP *r,
 		 uint32_t swfSize,
 		 AVal *flashVer,
 		 AVal *subscribepath,
+		 AVal *usherToken,
 		 int dStart,
 		 int dStop, int bLiveStream, long int timeout)
 {
@@ -355,6 +357,8 @@ RTMP_SetupStream(RTMP *r,
     RTMP_Log(RTMP_LOGDEBUG, "auth     : %s", auth->av_val);
   if (subscribepath && subscribepath->av_val)
     RTMP_Log(RTMP_LOGDEBUG, "subscribepath : %s", subscribepath->av_val);
+  if (usherToken && usherToken->av_val)
+    RTMP_Log(RTMP_LOGDEBUG, "NetStream.Authenticate.UsherToken : %s", usherToken->av_val);
   if (flashVer && flashVer->av_val)
     RTMP_Log(RTMP_LOGDEBUG, "flashVer : %s", flashVer->av_val);
   if (dStart > 0)
@@ -420,6 +424,8 @@ RTMP_SetupStream(RTMP *r,
     r->Link.flashVer = RTMP_DefaultFlashVer;
   if (subscribepath && subscribepath->av_len)
     r->Link.subscribepath = *subscribepath;
+  if (usherToken && usherToken->av_len)
+    r->Link.usherToken = *usherToken;
   r->Link.seekTime = dStart;
   r->Link.stopTime = dStop;
   if (bLiveStream)
@@ -477,6 +483,8 @@ static struct urlopt {
   	"Stream is live, no seeking possible" },
   { AVC("subscribe"), OFF(Link.subscribepath), OPT_STR, 0,
   	"Stream to subscribe to" },
+  { AVC("jtv"), OFF(Link.usherToken),          OPT_STR, 0,
+  	"Justin.tv authentication token" },
   { AVC("token"),     OFF(Link.token),	       OPT_STR, 0,
   	"Key for SecureToken response" },
   { AVC("swfVfy"),    OFF(Link.lFlags),        OPT_BOOL, RTMP_LF_SWFV,
@@ -1641,6 +1649,39 @@ SendFCSubscribe(RTMP *r, AVal *subscribepath)
   return RTMP_SendPacket(r, &packet, TRUE);
 }
 
+//Justin.tv specific authentication
+static const AVal av_NetStream_Authenticate_UsherToken = AVC("NetStream.Authenticate.UsherToken"); //SAVC() isn't suitable for that
+
+static int
+SendUsherToken(RTMP *r, AVal *usherToken)
+{
+  RTMPPacket packet;
+  char pbuf[1024], *pend = pbuf + sizeof(pbuf);
+  char *enc;
+  packet.m_nChannel = 0x03;	/* control channel (invoke) */
+  packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
+  packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
+  packet.m_nTimeStamp = 0;
+  packet.m_nInfoField2 = 0;
+  packet.m_hasAbsTimestamp = 0;
+  packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
+
+  RTMP_Log(RTMP_LOGDEBUG, "UsherToken: %s", usherToken->av_val);
+  enc = packet.m_body;
+  enc = AMF_EncodeString(enc, pend, &av_NetStream_Authenticate_UsherToken);
+  enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
+  *enc++ = AMF_NULL;
+  enc = AMF_EncodeString(enc, pend, usherToken);
+
+  if (!enc)
+    return FALSE;
+
+  packet.m_nBodySize = enc - packet.m_body;
+
+  return RTMP_SendPacket(r, &packet, FALSE);
+}
+/******************************************/
+
 SAVC(releaseStream);
 
 static int
@@ -2364,6 +2405,9 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize)
 
 	  if (!(r->Link.protocol & RTMP_FEATURE_WRITE))
 	    {
+	      /* Authenticate on Justin.tv legacy servers before sending FCSubscribe */
+	      if (r->Link.usherToken.av_len)
+	        SendUsherToken(r, &r->Link.usherToken);
 	      /* Send the FCSubscribe if live stream or if subscribepath is set */
 	      if (r->Link.subscribepath.av_len)
 	        SendFCSubscribe(r, &r->Link.subscribepath);
diff --git a/librtmp/rtmp.h b/librtmp/rtmp.h
index 1ece207..6b2ae5b 100644
--- a/librtmp/rtmp.h
+++ b/librtmp/rtmp.h
@@ -155,6 +155,7 @@ extern "C"
     AVal auth;
     AVal flashVer;
     AVal subscribepath;
+    AVal usherToken;
     AVal token;
     AMFObject extras;
     int edepth;
@@ -297,6 +298,7 @@ extern "C"
 			uint32_t swfSize,
 			AVal *flashVer,
 			AVal *subscribepath,
+			AVal *usherToken,
 			int dStart,
 			int dStop, int bLiveStream, long int timeout);
 
diff --git a/rtmpdump.c b/rtmpdump.c
index c1cd95b..ec1de85 100644
--- a/rtmpdump.c
+++ b/rtmpdump.c
@@ -692,6 +692,8 @@ void usage(char *prog)
 	  RTMP_LogPrintf
 	    ("--token|-T key          Key for SecureToken response\n");
 	  RTMP_LogPrintf
+	    ("--jtv|-j JSON           Authentication token for Justin.tv legacy servers\n");
+	  RTMP_LogPrintf
 	    ("--hashes|-#             Display progress with hashes, not with the byte counter\n");
 	  RTMP_LogPrintf
 	    ("--buffer|-b             Buffer time in milliseconds (default: %lu)\n",
@@ -738,6 +740,7 @@ main(int argc, char **argv)
   AVal hostname = { 0, 0 };
   AVal playpath = { 0, 0 };
   AVal subscribepath = { 0, 0 };
+  AVal usherToken = { 0, 0 }; //Justin.tv auth token
   int port = -1;
   int protocol = RTMP_PROTOCOL_UNDEFINED;
   int retries = 0;
@@ -839,12 +842,13 @@ main(int argc, char **argv)
     {"debug", 0, NULL, 'z'},
     {"quiet", 0, NULL, 'q'},
     {"verbose", 0, NULL, 'V'},
+    {"jtv", 1, NULL, 'j'},
     {0, 0, 0, 0}
   };
 
   while ((opt =
 	  getopt_long(argc, argv,
-		      "hVveqzr:s:t:p:a:b:f:o:u:C:n:c:l:y:Ym:k:d:A:B:T:w:x:W:X:S:#",
+		      "hVveqzr:s:t:p:a:b:f:o:u:C:n:c:l:y:Ym:k:d:A:B:T:w:x:W:X:S:#j:",
 		      longopts, NULL)) != -1)
     {
       switch (opt)
@@ -1051,6 +1055,9 @@ main(int argc, char **argv)
 	case 'S':
 	  STR2AVAL(sockshost, optarg);
 	  break;
+    case 'j':
+      STR2AVAL(usherToken, optarg);
+      break;
 	default:
 	  RTMP_LogPrintf("unknown option: %c\n", opt);
 	  usage(argv[0]);
@@ -1167,7 +1174,7 @@ main(int argc, char **argv)
 
   RTMP_SetupStream(&rtmp, protocol, &hostname, port, &sockshost, &playpath,
 		   &tcUrl, &swfUrl, &pageUrl, &app, &auth, &swfHash, swfSize,
-		   &flashVer, &subscribepath, dSeek, dStopOffset, bLiveStream, timeout);
+		   &flashVer, &subscribepath, &usherToken, dSeek, dStopOffset, bLiveStream, timeout);
 
   /* Try to keep the stream moving if it pauses on us */
   if (!bLiveStream && !(protocol & RTMP_FEATURE_HTTP))
diff --git a/rtmpgw.c b/rtmpgw.c
index 10a99e8..ce7319a 100644
--- a/rtmpgw.c
+++ b/rtmpgw.c
@@ -95,6 +95,7 @@ typedef struct
   AVal flashVer;
   AVal token;
   AVal subscribepath;
+  AVal usherToken; //Justin.tv auth token
   AVal sockshost;
   AMFObject extras;
   int edepth;
@@ -552,7 +553,7 @@ void processTCPrequest(STREAMING_SERVER * server,	// server socket and state (ou
   RTMP_Init(&rtmp);
   RTMP_SetBufferMS(&rtmp, req.bufferTime);
   RTMP_SetupStream(&rtmp, req.protocol, &req.hostname, req.rtmpport, &req.sockshost,
-		   &req.playpath, &req.tcUrl, &req.swfUrl, &req.pageUrl, &req.app, &req.auth, &req.swfHash, req.swfSize, &req.flashVer, &req.subscribepath, dSeek, req.dStopOffset,
+		   &req.playpath, &req.tcUrl, &req.swfUrl, &req.pageUrl, &req.app, &req.auth, &req.swfHash, req.swfSize, &req.flashVer, &req.subscribepath, &req.usherToken, dSeek, req.dStopOffset,
 		   req.bLiveStream, req.timeout);
   /* backward compatibility, we always sent this as true before */
   if (req.auth.av_len)
@@ -953,6 +954,9 @@ ParseOption(char opt, char *arg, RTMP_REQUEST * req)
     case 'z':
       RTMP_debuglevel = RTMP_LOGALL;
       break;
+    case 'j':
+      STR2AVAL(req->usherToken, arg);
+      break;
     default:
       RTMP_LogPrintf("unknown option: %c, arg: %s\n", opt, arg);
       return FALSE;
@@ -1023,6 +1027,7 @@ main(int argc, char **argv)
     {"debug", 0, NULL, 'z'},
     {"quiet", 0, NULL, 'q'},
     {"verbose", 0, NULL, 'V'},
+    {"jtv", 1, NULL, 'j'},
     {0, 0, 0, 0}
   };
 
@@ -1035,7 +1040,7 @@ main(int argc, char **argv)
 
   while ((opt =
 	  getopt_long(argc, argv,
-		      "hvqVzr:s:t:p:a:f:u:n:c:l:y:m:d:D:A:B:T:g:w:x:W:X:S:", longopts,
+		      "hvqVzr:s:t:p:a:f:u:n:c:l:y:m:d:D:A:B:T:g:w:x:W:X:S:j:", longopts,
 		      NULL)) != -1)
     {
       switch (opt)
@@ -1095,6 +1100,8 @@ main(int argc, char **argv)
 	    ("--stop|-B num           Stop at num seconds into stream\n");
 	  RTMP_LogPrintf
 	    ("--token|-T key          Key for SecureToken response\n");
+      RTMP_LogPrintf
+	    ("--jtv|-j JSON           Authentication token for Justin.tv legacy servers\n");
 	  RTMP_LogPrintf
 	    ("--buffer|-b             Buffer time in milliseconds (default: %lu)\n\n",
 	     defaultRTMPRequest.bufferTime);
diff --git a/rtmpsrv.c b/rtmpsrv.c
index f1b6c66..cf52bfa 100644
--- a/rtmpsrv.c
+++ b/rtmpsrv.c
@@ -116,6 +116,7 @@ typedef struct
   AVal swfHash;
   AVal flashVer;
   AVal subscribepath;
+  AVal usherToken;
   uint32_t swfSize;
 
   uint32_t dStartOffset;