ServiceBus REST API + PeekLock/Delete : Invalid authorization token audience

Thangavel Daniel Tamilarasan 271 Reputation points
2022-02-17T16:27:34.21+00:00

Hi

I have been using ServiceBus Rest API (PeekLock/Delete) method to retrieve messages form service bus queue. Everything works good when I have scheduled the run per second.

The SAS token has validity for a week.

However when I try to poll continuously with parallel requests (instantly/parallel) using one SAS token , some of my requests failed with "HTTP/1.1 401 SubCode=40104: Invalid authorization token audience". For eg out of 10 requests - 7 succeeds, 3 fails using same SAS token.

This is the same behaviour with PeekLock / Delete method. It's just 10 instant requests , not 1000's. I tried to look into the logs for SerivceBus namesapce , nothing about the failed requests.

Help me fix this , I need to constantly poll the queue using rest API- may be 100-2000 consecutive polls.

Below is sample request & response HTTP traces.´

Request

POST /q_xxxx/messages/head HTTP/1.1
Authorization: SharedAccessSignature sr=xxx.servicebus.windows.net&sig=123456789&se=1645540339&skn=ReadAccess
ContentType: application/atom+xml;type=entry;charset=utf-8
Connection: Keep-Alive
SUBJECT: NOT_SET
TRACKID: 000000000010.0007
Content-Length: 823
Host:xxx.servicebus.windows.net
User-Agent: Apache-HttpClient/4.5.13 (Java/11.0.13)
Accept-Encoding: gzip,deflate

Failed Response:
HTTP/1.1 401 SubCode=40104: Invalid authorization token audience
Content-Length: 0
Server: Microsoft-HTTPAPI/2.0
Strict-Transport-Security: max-age=31536000
Date: Thu, 17 Feb 2022 11:57:15 GMT
Azure Service Bus
Azure Service Bus
An Azure service that provides cloud messaging as a service and hybrid integration.
617 questions
0 comments No comments
{count} votes

2 answers

Sort by: Most helpful
  1. MayankBargali-MSFT 70,226 Reputation points
    2022-02-21T05:09:31.457+00:00

    @Thangavel Daniel Tamilarasan As per the error HTTP/1.1 401 SubCode=40104: Invalid authorization token audience your request failed as the audience was invalid for the SAS token. The reason could be that when you generate the stringToSign with the resourceUri along with the keyName and key then it will only target to a particular audience that is at the entity level (queue/topic/subscription) but you might be using this SAS token for other queues/topic/subscription for which it is invalid or you are performing other operation (like send etc.) and your SAS token doesn't have that permission for that operation. I will suggest you to verify if this is not the case in your scenario.

    private static string createToken(string resourceUri, string keyName, string key)  
    {  
        TimeSpan sinceEpoch = DateTime.UtcNow - new DateTime(1970, 1, 1);  
        var week = 60 * 60 * 24 * 7;  
        var expiry = Convert.ToString((int)sinceEpoch.TotalSeconds + week);  
        string stringToSign = HttpUtility.UrlEncode(resourceUri) + "\n" + expiry;  
        using (var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(key)))  
        {  
            var signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));  
            var sasToken = String.Format(CultureInfo.InvariantCulture, "SharedAccessSignature sr={0}&sig={1}&se={2}&skn={3}", HttpUtility.UrlEncode(resourceUri), HttpUtility.UrlEncode(signature), expiry, keyName);  
            return sasToken;  
        }  
    }  
    

    If you have generated the token correctly for the right entity and operation then I will suggest you to share your sample code to reproduce the issue so I can review it at my end. I have used the above code that only has send permission for a particular queue.

    0 comments No comments

  2. Thangavel Daniel Tamilarasan 271 Reputation points
    2022-02-22T10:23:12.707+00:00

    Hi @MayankBargali-MSFT

    Thanks for your response.

    I understand the SAS token scope is limited to particular audience. In our case , the key is queue specific not the namespace, And the SAS token generated does work to poll the queue successfully in case of individual request (like One request per second). Where as when we perform continuous/instant polling using the same token - the success & failure is random. For eg: Out of 10 parallel request , 7 will succeed and 3 will fail with HTTP/1.1 401 SubCode=40104: Invalid authorization token audience.

    It's the same SAS token which succeed & fail - while continuously polling the same queue. Please find the code we use to generate the SAS token.

    import java.io.UnsupportedEncodingException;  
    import java.net.URLEncoder;  
    import java.security.InvalidKeyException;  
    import java.security.NoSuchAlgorithmException;  
    import java.util.Base64;  
    import java.util.Base64.Encoder;  
    import javax.crypto.Mac;  
    import javax.crypto.spec.SecretKeySpec;  
    import java.util.*;  
      
    public class GenerateSASToken {  
      
    public static void main(String[] args) {  
    	System.out.println("******* Generate SAS token for Azure Service BUS *******");  
    	System.out.println(GetSASToken(args[0], args[1], args[2]));  
    	}  
      
    private static String GetSASToken(String resourceUri, String keyName, String key)  
      {  
          long epoch = System.currentTimeMillis()/1000L;  
          int week = 60*60*24*7;  
          String expiry = Long.toString(epoch + week);  
      
          String sasToken = null;  
          try {  
              String stringToSign = URLEncoder.encode(resourceUri, "UTF-8") + "\n" + expiry;  
              String signature = getHMAC256(key, stringToSign);  
              sasToken = "SharedAccessSignature sr=" + URLEncoder.encode(resourceUri, "UTF-8") +"&sig=" +  
                      URLEncoder.encode(signature, "UTF-8") + "&se=" + expiry + "&skn=" + keyName;  
          } catch (UnsupportedEncodingException e) {  
      
              e.printStackTrace();  
          }  
      
          return sasToken;  
      }  
      
      
    public static String getHMAC256(String key, String input) {  
        Mac sha256_HMAC = null;  
        String hash = null;  
        try {  
            sha256_HMAC = Mac.getInstance("HmacSHA256");  
            SecretKeySpec secret_key = new SecretKeySpec(key.getBytes(), "HmacSHA256");  
            sha256_HMAC.init(secret_key);  
            Encoder encoder = Base64.getEncoder();  
      
            hash = new String(encoder.encode(sha256_HMAC.doFinal(input.getBytes("UTF-8"))));  
      
        } catch (InvalidKeyException e) {  
            e.printStackTrace();  
        } catch (NoSuchAlgorithmException e) {  
            e.printStackTrace();  
        } catch (IllegalStateException e) {  
            e.printStackTrace();  
        } catch (UnsupportedEncodingException e) {  
            e.printStackTrace();  
        }  
      
        return hash;  
    }  
      
    }  
    
    
      
    

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.