Issue Generating Valid SAS Token for Azure Service Bus Using Postman - Receiving 401 SubCode=40103 Error

David Blaszyk 0 Reputation points
2025-09-18T11:29:23.2866667+00:00

I am experiencing persistent issues when attempting to generate and use a SAS token for Azure Service Bus via Postman. The token generation script runs without errors in Postman's pre-request script, but when sending a POST request to the /messages endpoint, I receive a 401 SubCode=40103: Invalid authorization token signature response. This occurs on a newly created namespace, while the same script works on an older namespace.

Steps to Reproduce:

  1. Set up environment variables in Postman for namespace, shared access key name, shared access key, and entity path (a queue).
  2. Use a pre-request script to generate the SAS token using CryptoJS.HmacSHA256, with proper URI encoding, newline in string-to-sign, and base64 parsing of the key.
  3. Send a POST request to https://{namespace}.servicebus.windows.net/{queue}/messages with Authorization: {{sasToken}} and Content-Type: application/json, body {"body": "test message"}.
  4. Observe the 401 SubCode=40103 error.

What I've Tried:

  • Verified the SAS token generation with newline in string-to-sign, base64 key parsing, and 1-hour TTL with buffer.
  • Ensured TLS 1.2 in Postman settings.
  • Used entity URI for sr parameter in the token.
  • Tested with a temporary queue and namespace-level policy with Send rights.
  • Confirmed key length (44 chars) and parsed bytes (32).
  • The script logs show successful token creation, but the request fails.

Environment:

  • Postman Desktop App (latest version as of September 18, 2025).
  • Azure Service Bus Standard tier.
  • REST API endpoint for sending messages.

Requested Assistance: Please advise if SAS tokens for REST API are still supported in 2025, or if there's a deprecation affecting new namespaces. If supported, what configuration issues could cause this 401 SubCode=40103 error, and how can I resolve it? Any recommended alternate methods for authentication in Postman would be helpful. Thank you for your support.I am experiencing persistent issues when attempting to generate and use a SAS token for Azure Service Bus via Postman. The token generation script runs without errors in Postman's pre-request script, but when sending a POST request to the /messages endpoint, I receive a 401 SubCode=40103: Invalid authorization token signature response. This occurs on a newly created namespace, while the same script works on an older namespace.

Steps to Reproduce:

  1. Set up environment variables in Postman for namespace, shared access key name, shared access key, and entity path (a queue).
  2. Use a pre-request script to generate the SAS token using CryptoJS.HmacSHA256, with proper URI encoding, newline in string-to-sign, and base64 parsing of the key.
  3. Send a POST request to https://{namespace}.servicebus.windows.net/{queue}/messages with Authorization: {{sasToken}} and Content-Type: application/json, body {"body": "test message"}.
  4. Observe the 401 SubCode=40103 error.

What I've Tried:

  • Verified the SAS token generation with newline in string-to-sign, base64 key parsing, and 1-hour TTL with buffer.
  • Ensured TLS 1.2 in Postman settings.
  • Used entity URI for sr parameter in the token.
  • Tested with a temporary queue and namespace-level policy with Send rights.
  • Confirmed key length (44 chars) and parsed bytes (32).
  • The script logs show successful token creation, but the request fails.

Environment:

  • Postman Desktop App (latest version as of September 18, 2025).
  • Azure Service Bus Standard tier.
  • REST API endpoint for sending messages.

Requested Assistance: Please advise if SAS tokens for REST API are still supported in 2025, or if there's a deprecation affecting new namespaces. If supported, what configuration issues could cause this 401 SubCode=40103 error, and how can I resolve it? Any recommended alternate methods for authentication in Postman would be helpful. Thank you for your support.

Azure Service Bus
Azure Service Bus
An Azure service that provides cloud messaging as a service and hybrid integration.
{count} votes

1 answer

Sort by: Most helpful
  1. David Blaszyk 0 Reputation points
    2025-09-24T01:45:44.1233333+00:00

    Here is a complete solution that allows one to use Postman environment variables, put this in a Package library within Postman:

    // acornsoft-unit-testing.js
    // Custom Postman library for Acornsoft unit testing utilities
    // Includes SAS token generation for Azure Service Bus
    
    const CryptoJS = require('crypto-js');
    
    /**
     * Parses an Azure Service Bus connection string into its components.
     * @param {string} connStr - The connection string
     * @returns {object} - { endpoint, keyName, keyValue }
     */
    function parseConnectionString(connStr) {
        const parts = (connStr || '').split(';').filter(Boolean);
        const map = {};
        for (const p of parts) {
            const idx = p.indexOf('=');
            if (idx > -1) {
                const key = p.substring(0, idx);
                const val = p.substring(idx + 1); // Preserve '=' padding
                map[key] = val;
            }
        }
        return {
            endpoint: (map.Endpoint || '').trim(),
            keyName: (map.SharedAccessKeyName || '').trim(),
            keyValue: (map.SharedAccessKey || '').trim()
        };
    }
    
    /**
     * Derives the resource URI for SAS signing.
     * @param {string} requestUrl - The request URL
     * @param {string} namespace - Namespace
     * @param {string} entityPath - Entity path
     * @returns {string} - Resource URI
     */
    function deriveResource(requestUrl, namespace, entityPath) {
        if (requestUrl) {
            const base = requestUrl.split('?')[0].replace(/\/$/, '').replace(/\/messages$/, '');
            if (base) return base;
        }
        return `https://${namespace}/${entityPath}`;
    }
    
    /**
     * Generates a Service Bus SAS token.
     * @param {string} resource - Resource URI
     * @param {string} keyName - Key name
     * @param {string} keyValue - Key value
     * @param {number} ttl - TTL
     * @returns {string} - SAS token
     */
    function generateSasToken(resource, keyName, keyValue, ttl = Math.round(Date.now() / 1000) + 60 * 60 * 24 * 7) {
        const encodedResource = encodeURIComponent(resource);
        const stringToSign = `${encodedResource}\n${ttl}`;
        const sig = CryptoJS.HmacSHA256(stringToSign, keyValue).toString(CryptoJS.enc.Base64);
        return `SharedAccessSignature sr=${encodedResource}&sig=${encodeURIComponent(sig)}&se=${ttl}&skn=${keyName}`;
    }
    
    /**
     * Generates SAS from connection string.
     * @param {string} connStr - Connection string
     * @param {string} requestUrl - Request URL
     * @param {string} entityPath - Entity path
     * @param {number} ttl - TTL
     * @returns {string|null} - SAS token
     */
    function generateFromConnectionString(connStr, requestUrl, entityPath, ttl) {
        const { endpoint, keyName, keyValue } = parseConnectionString(connStr);
        if (!endpoint || !keyName || !keyValue) return null;
    
        const namespace = endpoint.replace('sb://', '').replace(/\/$/, '');
        const resource = deriveResource(requestUrl, namespace, entityPath);
        if (!resource) return null;
    
        return generateSasToken(resource, keyName, keyValue, ttl);
    }
    
    /**
     * Sets up Postman variables and generates SAS token for Service Bus requests.
     * This function parses the connection string, sets serviceBusNamespace and entityPath variables,
     * and generates the SAS token using the request URL.
     * @param {string} connStr - Connection string
     * @param {string} entityPath - Entity path (optional, will be set as variable)
     * @param {number} ttl - TTL (optional)
     * @returns {string|null} - SAS token
     */
    function setupAndGenerateSas(connStr, entityPath, ttl) {
        if (!connStr) return null;
    
        // Parse connection string
        const { endpoint, keyName, keyValue } = parseConnectionString(connStr);
        if (!endpoint || !keyName || !keyValue) return null;
    
        // Extract namespace
        const namespace = endpoint.replace('sb://', '').replace('.servicebus.windows.net/', '').replace(/\/$/, '');
    
        // Set variables for URL resolution
        pm.variables.set('serviceBusNamespace', namespace);
        if (entityPath) {
            pm.variables.set('entityPath', entityPath);
        }
    
        // Generate SAS using resolved request URL
        const requestUrl = resolvePostmanVariables(pm.request.url.toString());
        return generateFromConnectionString(connStr, requestUrl, entityPath || pm.variables.get('entityPath'), ttl);
    }
    
    /**
     * Resolves Postman variables in a URL string.
     * @param {string} url - URL with {{variables}}
     * @returns {string} - URL with variables resolved
     */
    function resolvePostmanVariables(url) {
        return url.replace(/\{\{([^}]+)\}\}/g, (match, varName) => {
            const value = pm.variables.get(varName) || pm.environment.get(varName) || pm.globals.get(varName);
            return value || match; // Keep as-is if not found
        });
    }
    
    // Export functions
    module.exports = {
        parseConnectionString,
        deriveResource,
        generateSasToken,
        generateFromConnectionString,
        setupAndGenerateSas,
        resolvePostmanVariables
    };
    

    To use in a request here is an example how to leverage this library, which requires you to define (2) variables in Postman:

    serviceBusConnectionString = "
    entityPath = "someTopic" (or) "someQueue"
    
    

    Put this in the POST Request.

    
    // Load the library
    const someLib = pm.require('@acornsoft365/acornsoft-unit-testing');
    
    // Get inputs from Postman variables
    const connStr = pm.variables.get('serviceBusConnectionString');
    const entityPath = pm.variables.get('entityPath');
    const requestUrl = pm.request.url.toString();
    
    // Generate SAS token
    const sasToken = someLib.generateFromConnectionString(connStr, requestUrl, entityPath);
    
    if (sasToken) {
        pm.environment.set('sasToken', sasToken);
        console.log('SAS token generated successfully');
    } else {
        console.error('Failed to generate SAS token');
    }
    
    
    0 comments No comments

Your answer

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