Base64 string encoding in Airtable script editor without btoa() function

I need to create API requests from within Airtable’s scripting environment. The API endpoint I’m working with needs an Authorization header that includes a Base64 encoded version of my credentials in the format api:USERNAME:API_TOKEN.

The problem is that btoa() isn’t available in Airtable’s environment. I found a custom Base64 implementation online and tried using it:

var EncodingHelper = {
  charset: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
  
  convertToBase64: function(input) {
    var output = "";
    var char1, char2, char3, enc1, enc2, enc3, enc4;
    var index = 0;
    
    input = EncodingHelper.processUtf8(input);
    
    while (index < input.length) {
      char1 = input.charCodeAt(index++);
      char2 = input.charCodeAt(index++);
      char3 = input.charCodeAt(index++);
      
      enc1 = char1 >> 2;
      enc2 = ((char1 & 3) << 4) | (char2 >> 4);
      enc3 = ((char2 & 15) << 2) | (char3 >> 6);
      enc4 = char3 & 63;
      
      if (isNaN(char2)) {
        enc3 = enc4 = 64;
      } else if (isNaN(char3)) {
        enc4 = 64;
      }
      
      output += this.charset.charAt(enc1) + this.charset.charAt(enc2) + 
                this.charset.charAt(enc3) + this.charset.charAt(enc4);
    }
    
    return output;
  },
  
  processUtf8: function(text) {
    text = text.replace(/\r\n/g, "\n");
    var result = "";
    
    for (var i = 0; i < text.length; i++) {
      var code = text.charCodeAt(i);
      if (code < 128) {
        result += String.fromCharCode(code);
      } else if (code > 127 && code < 2048) {
        result += String.fromCharCode((code >> 6) | 192);
        result += String.fromCharCode((code & 63) | 128);
      } else {
        result += String.fromCharCode((code >> 12) | 224);
        result += String.fromCharCode(((code >> 6) & 63) | 128);
        result += String.fromCharCode((code & 63) | 128);
      }
    }
    return result;
  }
};

const credentials = 'MY_USER:MY_TOKEN';
var encodedCredentials = EncodingHelper.convertToBase64(credentials);

let apiResponse = await fetch('https://example-api.com/data', {
    method: 'GET',
    headers: {
        'Authorization': 'Basic ' + encodedCredentials
    }
});

But I’m still getting 401 errors. I even tested the encoding locally with btoa() and used that result directly, but same issue. Any ideas what might be wrong with my Base64 encoding approach in Airtable?

Your Base64 implementation looks solid, but that 401 screams auth issue, not encoding. Double-check your API endpoint format - some services want api:username:token while others just need username:token. Make sure your credentials haven’t expired too. I got burned by trailing whitespace in my token string before, so trim those credentials first. If the same encoded string works outside Airtable but fails inside, you might have network restrictions or the API’s treating requests from Airtable’s servers differently. Log the exact Authorization header value to console and see what’s actually getting sent.

the base64 looks good. just make sure your creds format is right - some apis need username:password, others may want apikey: or apikey:token. log the encoded string to verify it matches what you expect. likely a format issue, not an encoding one.

Had this exact problem last month with an Airtable third-party API. Your Base64 function’s fine - I used something similar. The issue was my API token had special characters that didn’t play nice with UTF-8 processing. Try skipping the processUtf8 function entirely if your credentials are basic ASCII (they usually are). Also check if your API wants the Basic auth format as Basic username:password or needs that api: prefix you mentioned. Some APIs are picky about case sensitivity in headers. One more thing - test your token in Postman or curl first to make sure it’s valid, because expired tokens give the same 401 response.

Check if your API needs URL encoding before Base64 encoding. I hit this issue with a client integration - their docs weren’t clear about it.

Log the raw credentials string before encoding to catch invisible characters or weird spacing. Copy-pasting from docs sometimes adds hidden chars.

I noticed something - your format shows api:USERNAME:API_TOKEN but your code uses MY_USER:MY_TOKEN. Some APIs are picky about that api: prefix. Try hardcoding it: const credentials = 'api:MY_USER:MY_TOKEN';

Still stuck? Temporarily hardcode a working Base64 value from outside Airtable. If that works, it’s your encoding. If not, it’s auth config or API endpoint problems.