title: Receiving Unauthorized Access Error on RenewToken Periodically with Azure Service Bus Queue Listener
body: <p>I am receiving a <strong>Microsoft.Azure.ServiceBus.ServiceBusException</strong> (message below with sensitive information removed) periodically in my queue receiver. The SAS key has send/listen access and the error seems inconsequential as processing continues as normal. However, the message is creating a signal to noise problem in my dashboards (receiving 10-70 errors per day). Any ideas on why this is happening? The listener is running in an Azure App Service, but I don't think that matters. I have adjusted my retry logic to use a RetryExponential with a 1 second to 1 minute backoff with 5 retries.</p>
  
  <p><a href="https://github.com/Azure/azure-sdk-for-net/issues/11619" rel="nofollow noreferrer">Request for guidance from SDK developers</a></p>
  
  <p><strong>Packages</strong></p>
  
  <p><code>Net Core 3.1</code></p>
  
  <p><code>Microsoft.Azure.ServiceBus, Version=4.1.3.0, Culture=neutral, PublicKeyToken=7e34167dcc6d6d8c</code></p>
  
  <p><strong>Error Message</strong></p>
  
  <blockquote>
    <p>The link 'xxx;xxx:xxx:xxx:source(address:xxx):xxx' is force detached. Code: RenewToken. Details: Unauthorized access. 'Listen' claim(s) are required to perform this operation. Resource: 'sb://xxx.servicebus.windows.net/xxx'.. TrackingId:xxx, SystemTracker:xxx, Timestamp:2020-04-27T09:36:04 The link 'xxx;xxx:xxx:xxx:source(address:xxx):xxx' is force detached. Code: RenewToken. Details: Unauthorized access. 'Listen' claim(s) are required to perform this operation. Resource: 'sb://xxx.servicebus.windows.net/xxx'.. TrackingId:xxx, SystemTracker:xxx, Timestamp:2020-04-27T09:36:04 </p>
  </blockquote>
  
  <p><strong>Source</strong></p>
  
  <pre><code>internal delegate TClient ClientFactory&lt;out TClient&gt;(string connectionString, string entityPath,
      RetryPolicy retryPolicy);
  
  internal delegate Task OnMessageCallback&lt;in TMessage&gt;(TMessage message,
      CancellationToken cancellationToken = default) where TMessage : ICorrelative;
  
  internal sealed class ReceiverClientWrapper&lt;TMessage&gt; : IReceiverClientWrapper&lt;TMessage&gt;
      where TMessage : ICorrelative
  {
      // ReSharper disable once StaticMemberInGenericType
      private static readonly Regex TransientConnectionErrorRegex =
          new Regex(
              @"(The link '([a-f0-9-]+);([0-9]*:)*source\(address:([a-z0-9_]+)\):([a-z0-9_]+)' is force detached. Code: RenewToken. Details: Unauthorized access. 'Listen' claim\(s\) are required to perform this operation. Resource: 'sb:\/\/([a-z0-9-_.\/]+)'.. TrackingId:([a-z0-9_]+), SystemTracker:([a-z0-9]+), Timestamp:([0-9]{4}(-[0-9]{2}){2}T([0-9]{2}:){2}[0-9]{2}) )+",
              RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.IgnoreCase);
  
      private readonly IReceiverClient _receiverClient;
      private readonly IMessageConverter&lt;TMessage&gt; _messageConverter;
      private readonly ILogger _logger;
      private readonly int _maximumConcurrency;
  
      public ReceiverClientWrapper(IReceiverClient receiverClient, IMessageConverter&lt;TMessage&gt; messageConverter,
          ILogger logger, int maximumConcurrency)
      {
          _receiverClient = receiverClient;
          _messageConverter = messageConverter;
          _logger = logger;
          _maximumConcurrency = maximumConcurrency;
      }
  
      public Task SubscribeAsync(OnMessageCallback&lt;TMessage&gt; onMessageCallback,
          OnFailureCallback onFailureCallback, CancellationToken cancellationToken = default)
      {
          var messageHandlerOptions = CreateMessageHandlerOptions(onFailureCallback, cancellationToken);
  
          async Task Handler(Message message, CancellationToken token)
          {
              var convertedMessage = _messageConverter.Convert(message);
  
              await onMessageCallback(convertedMessage, cancellationToken);
              await _receiverClient.CompleteAsync(message.SystemProperties.LockToken);
          }
  
          _receiverClient.RegisterMessageHandler(Handler, messageHandlerOptions);
  
          return Task.CompletedTask;
      }
  
      private MessageHandlerOptions CreateMessageHandlerOptions(OnFailureCallback onFailureCallback,
          CancellationToken cancellationToken)
      {
          async Task HandleExceptionAsync(ExceptionReceivedEventArgs arguments)
          {
              var exception = arguments.Exception;
  
              if (TransientConnectionErrorRegex.IsMatch(exception.Message))
              {
                  _logger.LogWarning(exception, @"Transient connectivity error occurred");
  
                  return;
              }
  
              await onFailureCallback(exception, cancellationToken);
          }
  
          return new MessageHandlerOptions(HandleExceptionAsync)
          {
              AutoComplete = false,
              MaxConcurrentCalls = _maximumConcurrency
          };
      }
  
      public async ValueTask DisposeAsync()
      {
          await _receiverClient.CloseAsync();
      }
  }
  
  internal sealed class SenderClientWrapper&lt;TMessage&gt; : ISenderClientWrapper&lt;TMessage&gt; where TMessage : ICorrelative
  {
      private readonly ISenderClient _senderClient;
      private readonly IMessageConverter&lt;TMessage&gt; _messageConverter;
  
      public SenderClientWrapper(ISenderClient senderClient, IMessageConverter&lt;TMessage&gt; messageConverter)
      {
          _senderClient = senderClient;
          _messageConverter = messageConverter;
      }
  
      public Task SendAsync(TMessage message, CancellationToken cancellationToken = default)
      {
          var internalMessage = _messageConverter.Convert(message);
  
          return _senderClient.SendAsync(internalMessage);
      }
  
      public Task SendAsync(IEnumerable&lt;TMessage&gt; messages, CancellationToken cancellationToken = default)
      {
          var internalMessages = messages
              .Select(_messageConverter.Convert)
              .ToImmutableArray();
  
          return _senderClient.SendAsync(internalMessages);
      }
  
      public async ValueTask DisposeAsync()
      {
          await _senderClient.CloseAsync();
      }
  }
  
  internal abstract class AbstractClientWrapperFactory
  {
      private const int MaximumRetryCount = 5;
      private static readonly TimeSpan MinimumRetryBackOff = TimeSpan.FromSeconds(1);
      private static readonly TimeSpan MaximumRetryBackOff = TimeSpan.FromMinutes(1);
  
      protected AbstractClientWrapperFactory(IOptions&lt;MessageBusConfiguration&gt; options)
      {
          Options = options;
      }
  
      protected IOptions&lt;MessageBusConfiguration&gt; Options { get; }
  
      protected static string GetEntityPath&lt;TMessage&gt;() where TMessage : class
      {
          var messageAttribute = typeof(TMessage).GetCustomAttribute&lt;AbstractMessageAttribute&gt;();
  
          if (messageAttribute == null)
          {
              throw new ArgumentException($@"Message requires {nameof(AbstractMessageAttribute)}");
          }
  
          return messageAttribute.EntityName;
      }
  
      protected TClient CreateClientEntity&lt;TMessage, TClient&gt;(ClientFactory&lt;TClient&gt; clientFactory)
          where TMessage : class
      {
          var entityPath = GetEntityPath&lt;TMessage&gt;();
          var retryPolicy = CreateRetryPolicy();
  
          return clientFactory(Options.Value.ConnectionString, entityPath, retryPolicy);
      }
  
      protected static IQueueClient QueueClientFactory(string connectionString, string entityPath,
          RetryPolicy retryPolicy)
      {
          return new QueueClient(connectionString, entityPath, retryPolicy: retryPolicy);
      }
  
      private static RetryPolicy CreateRetryPolicy()
      {
          return new RetryExponential(MinimumRetryBackOff, MaximumRetryBackOff, MaximumRetryCount);
      }
  }
  
  internal sealed class SenderClientWrapperFactory : AbstractClientWrapperFactory, ISenderClientWrapperFactory
  {
      private readonly IMessageConverterFactory _messageConverterFactory;
  
      public SenderClientWrapperFactory(IMessageConverterFactory messageConverterFactory,
          IOptions&lt;MessageBusConfiguration&gt; options) : base(options)
      {
          _messageConverterFactory = messageConverterFactory;
      }
  
      public ISenderClientWrapper&lt;TEvent&gt; CreateTopicClient&lt;TEvent&gt;() where TEvent : class, IEvent
      {
          return CreateWrapper&lt;TEvent, ITopicClient&gt;(TopicClientFactory);
      }
  
      public ISenderClientWrapper&lt;TRequest&gt; CreateQueueClient&lt;TRequest&gt;() where TRequest : class, IRequest
      {
          return CreateWrapper&lt;TRequest, IQueueClient&gt;(QueueClientFactory);
      }
  
      private ISenderClientWrapper&lt;TMessage&gt; CreateWrapper&lt;TMessage, TClient&gt;(ClientFactory&lt;TClient&gt; clientFactory)
          where TMessage : class, ICorrelative
          where TClient : ISenderClient
      {
          var clientEntity = CreateClientEntity&lt;TMessage, TClient&gt;(clientFactory);
          var messageConverter = _messageConverterFactory.Create&lt;TMessage&gt;();
  
          return new SenderClientWrapper&lt;TMessage&gt;(clientEntity, messageConverter);
      }
  
      private static ITopicClient TopicClientFactory(string connectionString, string entityPath,
          RetryPolicy retryPolicy)
      {
          return new TopicClient(connectionString, entityPath, retryPolicy);
      }
  }
  
  internal sealed class ReceiverClientWrapperFactory : AbstractClientWrapperFactory, IReceiverClientWrapperFactory
  {
      private readonly IMessageConverterFactory _messageConverterFactory;
      private readonly ILogger&lt;ReceiverClientWrapperFactory&gt; _logger;
  
      public ReceiverClientWrapperFactory(IOptions&lt;MessageBusConfiguration&gt; options,
          IMessageConverterFactory messageConverterFactory,
          ILogger&lt;ReceiverClientWrapperFactory&gt; logger) : base(options)
      {
          _messageConverterFactory = messageConverterFactory;
          _logger = logger;
      }
  
      public IReceiverClientWrapper&lt;TEvent&gt; CreateTopicClient&lt;TEvent&gt;() where TEvent : class, IEvent
      {
          return CreateReceiverClientWrapper&lt;TEvent, ISubscriptionClient&gt;(SubscriptionClientFactory);
      }
  
      public IReceiverClientWrapper&lt;TRequest&gt; CreateQueueClient&lt;TRequest&gt;() where TRequest : class, IRequest
      {
          return CreateReceiverClientWrapper&lt;TRequest, IQueueClient&gt;(QueueClientFactory);
      }
  
      private IReceiverClientWrapper&lt;TMessage&gt; CreateReceiverClientWrapper&lt;TMessage, TClient&gt;(
          ClientFactory&lt;TClient&gt; clientFactory)
          where TMessage : class, ICorrelative
          where TClient : IReceiverClient
      {
          var clientEntity = CreateClientEntity&lt;TMessage, TClient&gt;(clientFactory);
          var messageConverter = _messageConverterFactory.Create&lt;TMessage&gt;();
  
          return new ReceiverClientWrapper&lt;TMessage&gt;(clientEntity, messageConverter, _logger,
              Options.Value.MaximumConcurrency);
      }
  
      private ISubscriptionClient SubscriptionClientFactory(string connectionString, string entityPath,
          RetryPolicy retryPolicy)
      {
          return new SubscriptionClient(connectionString, entityPath, Options.Value.SubscriberName,
              retryPolicy: retryPolicy);
      }
  }
  
  internal sealed class RequestService&lt;TRequest&gt; : IRequestService&lt;TRequest&gt; where TRequest : class, IRequest
  {
      private readonly Lazy&lt;ISenderClientWrapper&lt;TRequest&gt;&gt; _senderClient;
      private readonly Lazy&lt;IReceiverClientWrapper&lt;TRequest&gt;&gt; _receiverClient;
  
      public RequestService(ISenderClientWrapperFactory senderClientWrapperFactory,
          IReceiverClientWrapperFactory receiverClientWrapperFactory)
      {
          _senderClient =
              new Lazy&lt;ISenderClientWrapper&lt;TRequest&gt;&gt;(senderClientWrapperFactory.CreateQueueClient&lt;TRequest&gt;,
                  LazyThreadSafetyMode.PublicationOnly);
  
          _receiverClient
              = new Lazy&lt;IReceiverClientWrapper&lt;TRequest&gt;&gt;(receiverClientWrapperFactory.CreateQueueClient&lt;TRequest&gt;,
                  LazyThreadSafetyMode.PublicationOnly);
      }
  
      public Task PublishRequestAsync(TRequest requestMessage, CancellationToken cancellationToken = default)
      {
          return _senderClient.Value.SendAsync(requestMessage, cancellationToken);
      }
  
      public Task PublishRequestAsync(IEnumerable&lt;TRequest&gt; requestMessages,
          CancellationToken cancellationToken = default)
      {
          return _senderClient.Value.SendAsync(requestMessages, cancellationToken);
      }
  
      public Task SubscribeAsync(OnRequestCallback&lt;TRequest&gt; onRequestCallback, OnFailureCallback onFailureCallback,
          CancellationToken cancellationToken = default)
      {
          return _receiverClient
              .Value
              .SubscribeAsync((message, token) =&gt; onRequestCallback(message, cancellationToken), onFailureCallback,
                  cancellationToken);
      }
  
      public async ValueTask DisposeAsync()
      {
          if (_senderClient.IsValueCreated)
          {
              await _senderClient.Value.DisposeAsync();
          }
  
          if (_receiverClient.IsValueCreated)
          {
              await _receiverClient.Value.DisposeAsync();
          }
      }
  
      public Task ThrowIfNotReadyAsync(CancellationToken cancellationToken = default)
      {
          return _senderClient.Value.SendAsync(ImmutableArray&lt;TRequest&gt;.Empty, cancellationToken);
      }
  }
  </code></pre>