'Azure Cognitive token is denied with axios within Azure Functions

  • Goal: Develop an Azure Function that translates body text through a Translator Azure resource

  • Issue: When I test this function locally by running npm run start and trigger my function with a HTTP POST and { "text": "こんにちは元気ですか?" } as the body, I have a 401 code. The function is not able to retrieve an access token from the API endpoint https://westeurope.api.cognitive.microsoft.com/sts/v1.0/issueToken

  • Code:

module.exports = async function (context, req) {

    const axios = require("axios");
    const qs = require("qs");

    if (req.body && req.body.text) {   
        try {
            // CONSTANTS
            const TRANSLATOR_KEY = "<MY-TRANSLATOR-KEY>";
            const TRANSLATOR_API_VERSION = "3.0";
            const TRANSLATOR_FROM_LANG = "ja";
            const TRANSLATOR_TO_LANG = "en";
            const TRANSLATOR_ENDPOINT = `https://api.cognitive.microsofttranslator.com/translate?api-version=${TRANSLATOR_API_VERSION}&from=${TRANSLATOR_FROM_LANG}&to=${TRANSLATOR_TO_LANG}`;
            const TOKEN_URL = "https://westeurope.api.cognitive.microsoft.com/sts/v1.0/issueToken";
            const TEXT_TO_TRANSLATE = [{"Text": req.body.text}];    

            let tokenResponse = await axios.post(TOKEN_URL, {
                headers: {
                        "Ocp-Apim-Subscription-Key": TRANSLATOR_KEY
                    }
                }
            )
            let translationResponse = await axios.post(TRANSLATOR_ENDPOINT,
                TEXT_TO_TRANSLATE, {
                    headers: {
                        "Content-type": "application/json",
                        "Authorization": `Bearer ${tokenResponse}`
                    }
                }
            )
            console.log(translationResponse);
            let textTranslated = translationResponse[0].translations[0].text;
            context.res = {
                status: 200,
                body: {
                    "message": "Success!",
                    "res": textTranslated
                }
            }

        }
        catch (error) {
            console.log(error);
            context.res = {
                status: 400,
                body: "Error with Translator resource"
            }
        }
    } else {
        context.res = {
            status: 400,
            body: "This HTTP triggered function executed successfully. Pass a text in the request body!"
        }
    }
}
  • Error: Here is the long error I receive with console.log(error) when testing my Azure function locally:
Host lock lease acquired by instance ID '0000000000000000000000009D5DC6ED'.
Executing 'Functions.textTranslation' (Reason='This function was programmatically called via the host APIs.', Id=bcf9ca1c-ea58-4282-acfe-d066167bd5a1)
Error: Request failed with status code 401
    at createError (C:\Users\Administrator\Desktop\AzureTranslate\node_modules\axios\lib\core\createError.js:16:15)
    at settle (C:\Users\Administrator\Desktop\AzureTranslate\node_modules\axios\lib\core\settle.js:17:12)
    at IncomingMessage.handleStreamEnd (C:\Users\Administrator\Desktop\AzureTranslate\node_modules\axios\lib\adapters\http.js:322:11)
    at IncomingMessage.emit (events.js:387:35)
    at endReadableNT (internal/streams/readable.js:1317:12)
    at processTicksAndRejections (internal/process/task_queues.js:82:21) {
  config: {
    transitional: {
      silentJSONParsing: true,
      forcedJSONParsing: true,
      clarifyTimeoutError: false
    },
    adapter: [Function: httpAdapter],
    transformRequest: ],
    transformResponse: ],
    timeout: 0,
    xsrfCookieName: 'XSRF-TOKEN',
    xsrfHeaderName: 'X-XSRF-TOKEN',
    maxContentLength: -1,
    maxBodyLength: -1,
    validateStatus: [Function: validateStatus],
    headers: {
      Accept: 'application/json, text/plain, */*',
      'Content-Type': 'application/json',
      'User-Agent': 'axios/0.26.1',
      'Content-Length': 76
    },
    method: 'post',
    url: 'https://westeurope.api.cognitive.microsoft.com/sts/v1.0/issueToken',
    data: '{"headers":{"Ocp-Apim-Subscription-Key":"<MY-TRANSLATOR-KEY>"}}'
  },
  request: <ref *1> ClientRequest {
    _events: {
      abort: [Function (anonymous)],
      aborted: [Function (anonymous)],
      connect: [Function (anonymous)],
      error: [Function (anonymous)],
Executed 'Functions.textTranslation' (Succeeded, Id=bcf9ca1c-ea58-4282-acfe-d066167bd5a1, Duration=689ms)
      socket: [Function (anonymous)],
      timeout: [Function (anonymous)],
      prefinish: [Function: requestOnPrefinish]
    },
    _eventsCount: 7,
    _maxListeners: undefined,
    outputData: [],
    outputSize: 0,
    writable: true,
    destroyed: false,
    _last: true,
    chunkedEncoding: false,
    shouldKeepAlive: false,
    _defaultKeepAlive: true,
    useChunkedEncodingByDefault: true,
    sendDate: false,
    _removedConnection: false,
    _removedContLen: false,
    _removedTE: false,
    _contentLength: null,
    _hasBody: true,
    _trailer: '',
    finished: true,
    _headerSent: true,
    socket: TLSSocket {
      _tlsOptions: [Object],
      _secureEstablished: true,
      _securePending: false,
      _newSessionPending: false,
      _controlReleased: true,
      secureConnecting: false,
      _SNICallback: null,
      servername: 'westeurope.api.cognitive.microsoft.com',
      alpnProtocol: false,
      authorized: true,
      authorizationError: null,
      encrypted: true,
      _events: [Object: null prototype],
      _eventsCount: 10,
      connecting: false,
      _hadError: false,
      _parent: null,
      _host: 'westeurope.api.cognitive.microsoft.com',
      _readableState: [ReadableState],
      _maxListeners: undefined,
      _writableState: [WritableState],
      allowHalfOpen: false,
      _sockname: null,
      _pendingData: null,
      _pendingEncoding: '',
      server: undefined,
      _server: null,
      ssl: [TLSWrap],
      _requestCert: true,
      _rejectUnauthorized: true,
      parser: null,
      _httpMessage: [Circular *1],
      [Symbol(res)]: [TLSWrap],
      [Symbol(verified)]: true,
      [Symbol(pendingSession)]: null,
      [Symbol(async_id_symbol)]: 17,
      [Symbol(kHandle)]: [TLSWrap],
      [Symbol(kSetNoDelay)]: false,
      [Symbol(lastWriteQueueSize)]: 0,
      [Symbol(timeout)]: null,
      [Symbol(kBuffer)]: null,
      [Symbol(kBufferCb)]: null,
      [Symbol(kBufferGen)]: null,
      [Symbol(kCapture)]: false,
      [Symbol(kBytesRead)]: 0,
      [Symbol(kBytesWritten)]: 0,
      [Symbol(connect-options)]: [Object],
      [Symbol(RequestTimeout)]: undefined
    },
    _header: 'POST /sts/v1.0/issueToken HTTP/1.1\r\n' +
      'Accept: application/json, text/plain, */*\r\n' +
      'Content-Type: application/json\r\n' +
      'User-Agent: axios/0.26.1\r\n' +
      'Content-Length: 76\r\n' +
      'Host: westeurope.api.cognitive.microsoft.com\r\n' +
      'Connection: close\r\n' +
      '\r\n',
    _keepAliveTimeout: 0,
    _onPendingData: [Function: noopPendingOutput],
    agent: Agent {
      _events: [Object: null prototype],
      _eventsCount: 2,
      _maxListeners: undefined,
      defaultPort: 443,
      protocol: 'https:',
      options: [Object],
      requests: {},
      sockets: [Object],
      freeSockets: {},
      keepAliveMsecs: 1000,
      keepAlive: false,
      maxSockets: Infinity,
      maxFreeSockets: 256,
      scheduling: 'lifo',
      maxTotalSockets: Infinity,
      totalSocketCount: 1,
      maxCachedSessions: 100,
      _sessionCache: [Object],
      [Symbol(kCapture)]: false
    },
    socketPath: undefined,
    method: 'POST',
    maxHeaderSize: undefined,
    insecureHTTPParser: undefined,
    path: '/sts/v1.0/issueToken',
    _ended: true,
    res: IncomingMessage {
      _readableState: [ReadableState],
      _events: [Object: null prototype],
      _eventsCount: 4,
      _maxListeners: undefined,
      socket: [TLSSocket],
      httpVersionMajor: 1,
      httpVersionMinor: 1,
      httpVersion: '1.1',
      complete: true,
      headers: [Object],
      rawHeaders: [Array],
      trailers: {},
      rawTrailers: [],
      aborted: false,
      upgrade: false,
      url: '',
      method: null,
      statusCode: 401,
      statusMessage: 'Access Denied',
      client: [TLSSocket],
      _consuming: false,
      _dumped: false,
      req: [Circular *1],
      responseUrl: 'https://westeurope.api.cognitive.microsoft.com/sts/v1.0/issueToken',
      redirects: [],
      [Symbol(kCapture)]: false,
      [Symbol(RequestTimeout)]: undefined
    },
    aborted: false,
    timeoutCb: null,
    upgradeOrConnect: false,
    parser: null,
    maxHeadersCount: null,
    reusedSocket: false,
    host: 'westeurope.api.cognitive.microsoft.com',
    protocol: 'https:',
    _redirectable: Writable {
      _writableState: [WritableState],
      _events: [Object: null prototype],
      _eventsCount: 3,
      _maxListeners: undefined,
      _options: [Object],
      _ended: true,
      _ending: true,
      _redirectCount: 0,
      _redirects: [],
      _requestBodyLength: 76,
      _requestBodyBuffers: [],
      _onNativeResponse: [Function (anonymous)],
      _currentRequest: [Circular *1],
      _currentUrl: 'https://westeurope.api.cognitive.microsoft.com/sts/v1.0/issueToken',
      [Symbol(kCapture)]: false
    },
    [Symbol(kCapture)]: false,
    [Symbol(kNeedDrain)]: false,
    [Symbol(corked)]: 0,
    {
      accept: [Array],
      'content-type': [Array],
      'user-agent': [Array],
      'content-length': [Array],
      host: [Array]
    }
  },
  response: {
    status: 401,
    statusText: 'Access Denied',
    headers: {
      'content-length': '225',
      'content-type': 'application/json',
      'apim-request-id': '28ba7434-91d7-4d2e-86aa-d08f661cf81c',
      'strict-transport-security': 'max-age=31536000; includeSubDomains; preload',
      'x-content-type-options': 'nosniff',
      'www-authenticate': 'AzureApiManagementKey realm="https://westeurope.api.cognitive.microsoft.com/sts/v1.0",name="Ocp-Apim-Subscription-Key",type="header"',
      date: 'Fri, 08 Apr 2022 13:37:56 GMT',
      connection: 'close'
    },
    config: {
      transitional: [Object],
      adapter: [Function: httpAdapter],
      transformRequest: [Array],
      transformResponse: [Array],
      timeout: 0,
      xsrfCookieName: 'XSRF-TOKEN',
      xsrfHeaderName: 'X-XSRF-TOKEN',
      maxContentLength: -1,
      maxBodyLength: -1,
      validateStatus: [Function: validateStatus],
      headers: [Object],
      method: 'post',
      url: 'https://westeurope.api.cognitive.microsoft.com/sts/v1.0/issueToken',
      data: '{"headers":{"Ocp-Apim-Subscription-Key":"<MY-TRANSLATOR-KEY>"}}'
    },
    request: <ref *1> ClientRequest {
      _events: [Object: null prototype],
      _eventsCount: 7,
      _maxListeners: undefined,
      outputData: [],
      outputSize: 0,
      writable: true,
      destroyed: false,
      _last: true,
      chunkedEncoding: false,
      shouldKeepAlive: false,
      _defaultKeepAlive: true,
      useChunkedEncodingByDefault: true,
      sendDate: false,
      _removedConnection: false,
      _removedContLen: false,
      _removedTE: false,
      _contentLength: null,
      _hasBody: true,
      _trailer: '',
      finished: true,
      _headerSent: true,
      socket: [TLSSocket],
      _header: 'POST /sts/v1.0/issueToken HTTP/1.1\r\n' +
        'Accept: application/json, text/plain, */*\r\n' +
        'Content-Type: application/json\r\n' +
        'User-Agent: axios/0.26.1\r\n' +
        'Content-Length: 76\r\n' +
        'Host: westeurope.api.cognitive.microsoft.com\r\n' +
        'Connection: close\r\n' +
        '\r\n',
      _keepAliveTimeout: 0,
      _onPendingData: [Function: noopPendingOutput],
      agent: [Agent],
      socketPath: undefined,
      method: 'POST',
      maxHeaderSize: undefined,
      insecureHTTPParser: undefined,
      path: '/sts/v1.0/issueToken',
      _ended: true,
      res: [IncomingMessage],
      aborted: false,
      timeoutCb: null,
      upgradeOrConnect: false,
      parser: null,
      maxHeadersCount: null,
      reusedSocket: false,
      host: 'westeurope.api.cognitive.microsoft.com',
      protocol: 'https:',
      _redirectable: [Writable],
      [Symbol(kCapture)]: false,
      [Symbol(kNeedDrain)]: false,
      [Symbol(corked)]: 0,
      [Symbol(kOutHeaders)]: [Object: null prototype]
    },
    data: { error: }
  },
  isAxiosError: true,
  toJSON: [Function: toJSON]
}
  • Important note:
    1. It is not an encoding issue due to Japanese characters as I have the same issue by trying to translate English text to German
    2. Also not working when I deploy my Azure function to the cloud environment and test it online. It only returns a 200 OK code without any error.
    3. This process is perfectly working with Postman:
[
 {
   "translations": [
     {
       "text": "hello, how are you?"
       "to": "en"
     }
   ]
 }
]
  • Configuration:

    • Node: 14.17.3
    • npm: 6.14.13
    • Azure function: 3.0.X
    • Axios: 0.26.1
  • Questions:

    1. Why is there different behaviors between Postman and Axios?
    2. Is it due to CORS policy?

Thank you in advance for your help on this topic!



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source