title: 401 error accessing Cloudant from IBM Cloud Function
body: <p>I have created a Cloudant service and credentials (1) along with a database and a couple of documents. I want to access that database from an IBM Cloud Function so created a function to do that. I tested the function by adding the copied and pasted credentials from (1) into the "Invoke with credentials" box (along with the and the db name and a valid docid). The function seems to take all that info correctly but I get a 401 error... any help would be massively appreciated!</p>
  
  <pre><code>{
    "error": {
      "description": "couch returned 401",
      "errid": "non_200",
      "error": "unauthorized",
      "headers": {
        "cache-control": "must-revalidate",
        "content-type": "application/json",
        "date": "Sat, 30 May 2020 16:37:25 GMT",
        "statusCode": 401,
        "strict-transport-security": "max-age=31536000",
        "uri": "xxxxxxx",
        "via": "1.1 lb1.bm-cc-eu-gb-04 (Glum/1.89.6)",
        "www-authenticate": "Basic realm=\"Cloudant Private Database\"",
        "x-cloudant-action": "cloudantnosqldb.any-document.read",
        "x-cloudant-backend": "bm-cc-eu-gb-04",
        "x-cloudant-request-class": "lookup",
        "x-content-type-options": "nosniff",
        "x-couch-request-id": "03e7fe91bb"
      },
      "message": "_reader access is required for this request",
      "name": "Error",
      "reason": "_reader access is required for this request",
      "request": {
        "headers": {
          "accept": "application/json",
          "content-type": "application/json"
        },
        "method": "GET",
        "uri": "xxxxx"
      },
      "scope": "couch",
      "stack": "Error: _reader access is required for this request\n    at Object.clientCallback (/node_modules/@cloudant/cloudant/node_modules/nano/lib/nano.js:151:15)\n    at Request._callback (/node_modules/@cloudant/cloudant/lib/clientutils.js:162:11)\n    at Request.self.callback (/node_modules/request/request.js:185:22)\n    at Request.emit (events.js:198:13)\n    at Request.self._source.emit (/node_modules/@cloudant/cloudant/lib/eventrelay.js:78:21)\n    at Request.&lt;anonymous&gt; (/node_modules/request/request.js:1161:10)\n    at Request.emit (events.js:198:13)\n    at Request.self._source.emit (/node_modules/@cloudant/cloudant/lib/eventrelay.js:78:21)\n    at IncomingMessage.&lt;anonymous&gt; (/node_modules/request/request.js:1083:12)",
      "statusCode": 401
    }
  }
  </code></pre>
  
  <p>The function code is as follows:</p>
  
  <pre><code>/**
   * Read a document in Cloudant database:
   * https://docs.cloudant.com/document.html#read
   **/
  
  function main(message) {
  
      var cloudantOrError = getCloudantAccount(message);
      if (typeof cloudantOrError !== 'object') {
          return Promise.reject(cloudantOrError);
      }
      var cloudant = cloudantOrError;
  
      var dbName = message.dbname;
      var docId = message.docid || message.id;
      var params = {};
  
      if (!dbName) {
          return Promise.reject('dbname is required.');
      }
      if (!docId) {
          return Promise.reject('docid is required.');
      }
      var cloudantDb = cloudant.use(dbName);
  
      if (typeof message.params === 'object') {
          params = message.params;
      } else if (typeof message.params === 'string') {
          try {
              params = JSON.parse(message.params);
          } catch (e) {
              return Promise.reject('params field cannot be parsed. Ensure it is valid JSON.');
          }
      }
  
      return readDocument(cloudantDb, docId, params);
  }
  
  function readDocument(cloudantDb, docId, params) {
      return new Promise(function (resolve, reject) {
          cloudantDb.get(docId, params, function (error, response) {
              if (!error) {
                  resolve(response);
              } else {
                  console.error('error', error);
                  reject(error);
              }
          });
      });
  }
  
  function getCloudantAccount(params) {
  
      var Cloudant = require('@cloudant/cloudant');
      var cloudant;
  
      if (!params.iamApiKey &amp;&amp; params.url) {
          cloudant = Cloudant(params.url);
      } else {
          checkForBXCreds(params);
  
          if (!params.host) {
              return 'Cloudant account host is required.';
          }
  
          if (!params.iamApiKey) {
              if (!params.username || !params.password) {
                  return 'You must specify parameter/s of iamApiKey or username/password';
              }
          }
  
          var protocol = params.protocol || 'https';
          if (params.iamApiKey) {
              var dbURL = `${protocol}://${params.host}`;
              if (params.port) {
                  dbURL += ':' + params.port;
              }
              cloudant = new Cloudant({
                  url: dbURL,
                  plugins: {iamauth: {iamApiKey: params.iamApiKey, iamTokenUrl: params.iamUrl}}
              });
          } else {
              var url = `${protocol}://${params.username}:${params.password}@${params.host}`;
              if (params.port) {
                  url += ':' + params.port;
              }
              cloudant = Cloudant(url);
          }
      }
      return cloudant;
  }
  
  function checkForBXCreds(params) {
  
      if (params.__bx_creds &amp;&amp; (params.__bx_creds.cloudantnosqldb || params.__bx_creds.cloudantNoSQLDB)) {
          var cloudantCreds = params.__bx_creds.cloudantnosqldb || params.__bx_creds.cloudantNoSQLDB;
  
          if (!params.host) {
              params.host = cloudantCreds.host || (cloudantCreds.username + '.cloudant.com');
          }
          if (!params.iamApiKey &amp;&amp; !cloudantCreds.apikey) {
              if (!params.username) {
                  params.username = cloudantCreds.username;
              }
              if (!params.password) {
                  params.password = cloudantCreds.password;
              }
          } else if (!params.iamApiKey) {
              params.iamApiKey = cloudantCreds.apikey;
          }
      }
  
  }
  </code></pre>