Skip to main content
Solved

Base64 conversion


Forum|alt.badge.img+12

Hi everyone !

I am trying to authenticate a request using Basic Auth.
I then need to base64-encode my logins.
(could encode them manually and then insert but would prefer to keep that logic in the code)

I didn’t found how to achieve this “natively” without rewriting the entire encoding function.
btoa() does not seems to work :confused:

Can anyone help me on this ?

Thanks

Best answer by kuovonne

Even though I get the squiggly underlines under btoa, the code runs just fine when I use it.

There are enough times when squiggly red underlines appear for working code, that if the logic makes sense to me and the code runs, I ignore the squiggly red underlines.

View original
Did this topic help you find an answer to your question?

18 replies

Forum|alt.badge.img+19
  • Inspiring
  • 3264 replies
  • November 3, 2020

Can’t really say what the issue is without seeing the scripting context. Is this in a Script Block? Scrip automation? Custom App? External script accessing via the Airtable API?

If you want to learn more, you have to share the details.


Forum|alt.badge.img+12
Bill_French wrote:

Can’t really say what the issue is without seeing the scripting context. Is this in a Script Block? Scrip automation? Custom App? External script accessing via the Airtable API?

If you want to learn more, you have to share the details.


Thank you for your reply.

I am trying to fetch from a Script Block.

Florian


Forum|alt.badge.img+19
  • Inspiring
  • 3264 replies
  • November 3, 2020

Okay - that’s helpful, but not likely enough to comment more than generally. Without seeing exactly what you’re trying to run through a base64 encoding process, we’re still in the dark.

Given that Script Blocks are everyday javascript, btoa() should work just fine unless there are some strange characters in the string being encoded…

btoa() accepts a “string” where each character represents an 8-bit byte – if you pass a string containing characters that can’t be represented in 8 bits, it will probably break. This isn’t a problem if you’re actually treating the string as a byte array, but if you’re trying to do something else then you’ll have to encode it first.


Forum|alt.badge.img+12
Bill_French wrote:

Okay - that’s helpful, but not likely enough to comment more than generally. Without seeing exactly what you’re trying to run through a base64 encoding process, we’re still in the dark.

Given that Script Blocks are everyday javascript, btoa() should work just fine unless there are some strange characters in the string being encoded…

btoa() accepts a “string” where each character represents an 8-bit byte – if you pass a string containing characters that can’t be represented in 8 bits, it will probably break. This isn’t a problem if you’re actually treating the string as a byte array, but if you’re trying to do something else then you’ll have to encode it first.


Actually, btoa() function is not found.

Tried window.btoa() as well with no success.
I don’t really know how this function is supposed to work in the context of Airtable Script Block.

It should probably be something else than window but can’t find what.


kuovonne
Forum|alt.badge.img+27
  • Brainy
  • 6002 replies
  • Answer
  • November 3, 2020

Even though I get the squiggly underlines under btoa, the code runs just fine when I use it.

There are enough times when squiggly red underlines appear for working code, that if the logic makes sense to me and the code runs, I ignore the squiggly red underlines.


Forum|alt.badge.img+19
  • Inspiring
  • 3264 replies
  • November 3, 2020
Florian_Verdon2 wrote:

Actually, btoa() function is not found.

Tried window.btoa() as well with no success.
I don’t really know how this function is supposed to work in the context of Airtable Script Block.

It should probably be something else than window but can’t find what.


Hmm… works fine for me:

Script…

output.markdown('## BtoA() Test');

output.markdown('### User/Password');
let pw = "bfg:123456";
output.inspect(pw);

output.markdown('### Base64 of User/Password');
let b64 = btoa(pw);
output.inspect(b64);

Forum|alt.badge.img+12

Ok thank you, I didn’t try to run it…
I am not used to run the code when editor shows an error :grinning_face_with_sweat:

Thank you !


kuovonne
Forum|alt.badge.img+27
  • Brainy
  • 6002 replies
  • November 3, 2020

Just a followup note, while btoa() works for me in Scripting app (despite the squiggly red underline), it does not work for me in an automation action script.


Forum|alt.badge.img+19
  • Inspiring
  • 3264 replies
  • November 3, 2020
kuovonne wrote:

Just a followup note, while btoa() works for me in Scripting app (despite the squiggly red underline), it does not work for me in an automation action script.


This is why I was so careful to understand the scripting context. This is a possible out on the script action side.


Forum|alt.badge.img+18
  • Inspiring
  • 251 replies
  • November 3, 2020
Florian_Verdon2 wrote:

Actually, btoa() function is not found.

Tried window.btoa() as well with no success.
I don’t really know how this function is supposed to work in the context of Airtable Script Block.

It should probably be something else than window but can’t find what.


-App

But it seems well reading this thread that window. prefix is neither necessary nor globalThis. prefix !

oLπ


Forum|alt.badge.img
  • New Participant
  • 1 reply
  • December 2, 2022

When I tried to do this in 2022, I am getting a ReferenceError. Is there an updated recommendation on how to accomplish this? My implementation is similar to the below.

console.log(btoa("STRING_TO_ENCODE"))


Karlstens
Forum|alt.badge.img+20
  • Inspiring
  • 601 replies
  • February 3, 2023

... and in 2023 btoa() is still not supported within a Scripting Automation? 🤨 Most frustrating!


Forum|alt.badge.img+2
  • New Participant
  • 3 replies
  • February 15, 2023

For Scripting Automation, here's a solution that works well for me.

function getBambooToken(client) { let tokenizedString = <API_key> + ":x" return btoa(tokenizedString) } function btoa(token) { var Base64={_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(e){var t="";var n,r,i,s,o,u,a;var f=0;e=Base64._utf8_encode(e);while(f<e.length){n=e.charCodeAt(f++);r=e.charCodeAt(f++);i=e.charCodeAt(f++);s=n>>2;o=(n&3)<<4|r>>4;u=(r&15)<<2|i>>6;a=i&63;if(isNaN(r)){u=a=64}else if(isNaN(i)){a=64}t=t+this._keyStr.charAt(s)+this._keyStr.charAt(o)+this._keyStr.charAt(u)+this._keyStr.charAt(a)}return t},decode:function(e){var t="";var n,r,i;var s,o,u,a;var f=0;e=e.replace(/[^A-Za-z0-9\+\/\=]/g,"");while(f<e.length){s=this._keyStr.indexOf(e.charAt(f++));o=this._keyStr.indexOf(e.charAt(f++));u=this._keyStr.indexOf(e.charAt(f++));a=this._keyStr.indexOf(e.charAt(f++));n=s<<2|o>>4;r=(o&15)<<4|u>>2;i=(u&3)<<6|a;t=t+String.fromCharCode(n);if(u!=64){t=t+String.fromCharCode(r)}if(a!=64){t=t+String.fromCharCode(i)}}t=Base64._utf8_decode(t);return t},_utf8_encode:function(e){e=e.replace(/\r\n/g,"\n");var t="";for(var n=0;n<e.length;n++){var r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r)}else if(r>127&&r<2048){t+=String.fromCharCode(r>>6|192);t+=String.fromCharCode(r&63|128)}else{t+=String.fromCharCode(r>>12|224);t+=String.fromCharCode(r>>6&63|128);t+=String.fromCharCode(r&63|128)}}return t},_utf8_decode:function(e){var t="";var n=0;var r=c1=c2=0;while(n<e.length){r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r);n++}else if(r>191&&r<224){c2=e.charCodeAt(n+1);t+=String.fromCharCode((r&31)<<6|c2&63);n+=2}else{c2=e.charCodeAt(n+1);c3=e.charCodeAt(n+2);t+=String.fromCharCode((r&15)<<12|(c2&63)<<6|c3&63);n+=3}}return t}} return Base64.encode(token) }

 


Forum|alt.badge.img+2
  • New Participant
  • 2 replies
  • April 14, 2023
apg314 wrote:

For Scripting Automation, here's a solution that works well for me.

function getBambooToken(client) { let tokenizedString = <API_key> + ":x" return btoa(tokenizedString) } function btoa(token) { var Base64={_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(e){var t="";var n,r,i,s,o,u,a;var f=0;e=Base64._utf8_encode(e);while(f<e.length){n=e.charCodeAt(f++);r=e.charCodeAt(f++);i=e.charCodeAt(f++);s=n>>2;o=(n&3)<<4|r>>4;u=(r&15)<<2|i>>6;a=i&63;if(isNaN(r)){u=a=64}else if(isNaN(i)){a=64}t=t+this._keyStr.charAt(s)+this._keyStr.charAt(o)+this._keyStr.charAt(u)+this._keyStr.charAt(a)}return t},decode:function(e){var t="";var n,r,i;var s,o,u,a;var f=0;e=e.replace(/[^A-Za-z0-9\+\/\=]/g,"");while(f<e.length){s=this._keyStr.indexOf(e.charAt(f++));o=this._keyStr.indexOf(e.charAt(f++));u=this._keyStr.indexOf(e.charAt(f++));a=this._keyStr.indexOf(e.charAt(f++));n=s<<2|o>>4;r=(o&15)<<4|u>>2;i=(u&3)<<6|a;t=t+String.fromCharCode(n);if(u!=64){t=t+String.fromCharCode(r)}if(a!=64){t=t+String.fromCharCode(i)}}t=Base64._utf8_decode(t);return t},_utf8_encode:function(e){e=e.replace(/\r\n/g,"\n");var t="";for(var n=0;n<e.length;n++){var r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r)}else if(r>127&&r<2048){t+=String.fromCharCode(r>>6|192);t+=String.fromCharCode(r&63|128)}else{t+=String.fromCharCode(r>>12|224);t+=String.fromCharCode(r>>6&63|128);t+=String.fromCharCode(r&63|128)}}return t},_utf8_decode:function(e){var t="";var n=0;var r=c1=c2=0;while(n<e.length){r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r);n++}else if(r>191&&r<224){c2=e.charCodeAt(n+1);t+=String.fromCharCode((r&31)<<6|c2&63);n+=2}else{c2=e.charCodeAt(n+1);c3=e.charCodeAt(n+2);t+=String.fromCharCode((r&15)<<12|(c2&63)<<6|c3&63);n+=3}}return t}} return Base64.encode(token) }

 


Hi All!

Based on @apg314 i came up with this automated scrip that copy one value and past it i othe place in Base 64:

 

 

function btoa(token) {
  var Base64={_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(e){var t="";var n,r,i,s,o,u,a;var f=0;e=Base64._utf8_encode(e);while(f<e.length){n=e.charCodeAt(f++);r=e.charCodeAt(f++);i=e.charCodeAt(f++);s=n>>2;o=(n&3)<<4|r>>4;u=(r&15)<<2|i>>6;a=i&63;if(isNaN(r)){u=a=64}else if(isNaN(i)){a=64}t=t+this._keyStr.charAt(s)+this._keyStr.charAt(o)+this._keyStr.charAt(u)+this._keyStr.charAt(a)}return t},decode:function(e){var t="";var n,r,i;var s,o,u,a;var f=0;e=e.replace(/[^A-Za-z0-9\+\/\=]/g,"");while(f<e.length){s=this._keyStr.indexOf(e.charAt(f++));o=this._keyStr.indexOf(e.charAt(f++));u=this._keyStr.indexOf(e.charAt(f++));a=this._keyStr.indexOf(e.charAt(f++));n=s<<2|o>>4;r=(o&15)<<4|u>>2;i=(u&3)<<6|a;t=t+String.fromCharCode(n);if(u!=64){t=t+String.fromCharCode(r)}if(a!=64){t=t+String.fromCharCode(i)}}t=Base64._utf8_decode(t);return t},_utf8_encode:function(e){e=e.replace(/\r\n/g,"\n");var t="";for(var n=0;n<e.length;n++){var r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r)}else if(r>127&&r<2048){t+=String.fromCharCode(r>>6|192);t+=String.fromCharCode(r&63|128)}else{t+=String.fromCharCode(r>>12|224);t+=String.fromCharCode(r>>6&63|128);t+=String.fromCharCode(r&63|128)}}return t},_utf8_decode:function(e){var t="";var n=0;var r=c1=c2=0;while(n<e.length){r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r);n++}else if(r>191&&r<224){c2=e.charCodeAt(n+1);t+=String.fromCharCode((r&31)<<6|c2&63);n+=2}else{c2=e.charCodeAt(n+1);c3=e.charCodeAt(n+2);t+=String.fromCharCode((r&15)<<12|(c2&63)<<6|c3&63);n+=3}}return t}}
  return Base64.encode(token)
}
// Query for every record in "table1" field1copy
let table = base.getTable("table1");

let tableQuery = await table.selectRecordsAsync();

for(let tableRec of tableQuery.records) {
    b64 = btoa(tableRec.getCellValue("Field1copy"));
    
        // Insert records in "field2paste" table1
await table.updateRecordAsync(tableRec, {
            "Field2paste" : b64,
        });
}
 
 
Hope it is useful for someone.




Forum|alt.badge.img+2
  • New Participant
  • 1 reply
  • April 14, 2023
Yourapp wrote:

Hi All!

Based on @apg314 i came up with this automated scrip that copy one value and past it i othe place in Base 64:

 

 

function btoa(token) {
  var Base64={_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(e){var t="";var n,r,i,s,o,u,a;var f=0;e=Base64._utf8_encode(e);while(f<e.length){n=e.charCodeAt(f++);r=e.charCodeAt(f++);i=e.charCodeAt(f++);s=n>>2;o=(n&3)<<4|r>>4;u=(r&15)<<2|i>>6;a=i&63;if(isNaN(r)){u=a=64}else if(isNaN(i)){a=64}t=t+this._keyStr.charAt(s)+this._keyStr.charAt(o)+this._keyStr.charAt(u)+this._keyStr.charAt(a)}return t},decode:function(e){var t="";var n,r,i;var s,o,u,a;var f=0;e=e.replace(/[^A-Za-z0-9\+\/\=]/g,"");while(f<e.length){s=this._keyStr.indexOf(e.charAt(f++));o=this._keyStr.indexOf(e.charAt(f++));u=this._keyStr.indexOf(e.charAt(f++));a=this._keyStr.indexOf(e.charAt(f++));n=s<<2|o>>4;r=(o&15)<<4|u>>2;i=(u&3)<<6|a;t=t+String.fromCharCode(n);if(u!=64){t=t+String.fromCharCode(r)}if(a!=64){t=t+String.fromCharCode(i)}}t=Base64._utf8_decode(t);return t},_utf8_encode:function(e){e=e.replace(/\r\n/g,"\n");var t="";for(var n=0;n<e.length;n++){var r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r)}else if(r>127&&r<2048){t+=String.fromCharCode(r>>6|192);t+=String.fromCharCode(r&63|128)}else{t+=String.fromCharCode(r>>12|224);t+=String.fromCharCode(r>>6&63|128);t+=String.fromCharCode(r&63|128)}}return t},_utf8_decode:function(e){var t="";var n=0;var r=c1=c2=0;while(n<e.length){r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r);n++}else if(r>191&&r<224){c2=e.charCodeAt(n+1);t+=String.fromCharCode((r&31)<<6|c2&63);n+=2}else{c2=e.charCodeAt(n+1);c3=e.charCodeAt(n+2);t+=String.fromCharCode((r&15)<<12|(c2&63)<<6|c3&63);n+=3}}return t}}
  return Base64.encode(token)
}
// Query for every record in "table1" field1copy
let table = base.getTable("table1");

let tableQuery = await table.selectRecordsAsync();

for(let tableRec of tableQuery.records) {
    b64 = btoa(tableRec.getCellValue("Field1copy"));
    
        // Insert records in "field2paste" table1
await table.updateRecordAsync(tableRec, {
            "Field2paste" : b64,
        });
}
 
 
Hope it is useful for someone.




This is exactly what I've been trying to solve.  This solution works brilliantly!

It does timeout before it gets to the end of my record set however. 😞

Script exceeded execution time limit of 30 seconds

 


Forum|alt.badge.img+2
  • New Participant
  • 2 replies
  • April 14, 2023
Jeffrey_A wrote:

This is exactly what I've been trying to solve.  This solution works brilliantly!

It does timeout before it gets to the end of my record set however. 😞

Script exceeded execution time limit of 30 seconds

 


Hi @Jeffrey_A! Does your record set have more then 50 record?

If so, it is need to implement a 50 run limit.

I did not do that on the script because i only run one line on each time the automatation runs.

I have that limit in others automatations, so it should work on this too.


Forum|alt.badge.img+4
Yourapp wrote:

Hi All!

Based on @apg314 i came up with this automated scrip that copy one value and past it i othe place in Base 64:

 

 

function btoa(token) {
  var Base64={_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(e){var t="";var n,r,i,s,o,u,a;var f=0;e=Base64._utf8_encode(e);while(f<e.length){n=e.charCodeAt(f++);r=e.charCodeAt(f++);i=e.charCodeAt(f++);s=n>>2;o=(n&3)<<4|r>>4;u=(r&15)<<2|i>>6;a=i&63;if(isNaN(r)){u=a=64}else if(isNaN(i)){a=64}t=t+this._keyStr.charAt(s)+this._keyStr.charAt(o)+this._keyStr.charAt(u)+this._keyStr.charAt(a)}return t},decode:function(e){var t="";var n,r,i;var s,o,u,a;var f=0;e=e.replace(/[^A-Za-z0-9\+\/\=]/g,"");while(f<e.length){s=this._keyStr.indexOf(e.charAt(f++));o=this._keyStr.indexOf(e.charAt(f++));u=this._keyStr.indexOf(e.charAt(f++));a=this._keyStr.indexOf(e.charAt(f++));n=s<<2|o>>4;r=(o&15)<<4|u>>2;i=(u&3)<<6|a;t=t+String.fromCharCode(n);if(u!=64){t=t+String.fromCharCode(r)}if(a!=64){t=t+String.fromCharCode(i)}}t=Base64._utf8_decode(t);return t},_utf8_encode:function(e){e=e.replace(/\r\n/g,"\n");var t="";for(var n=0;n<e.length;n++){var r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r)}else if(r>127&&r<2048){t+=String.fromCharCode(r>>6|192);t+=String.fromCharCode(r&63|128)}else{t+=String.fromCharCode(r>>12|224);t+=String.fromCharCode(r>>6&63|128);t+=String.fromCharCode(r&63|128)}}return t},_utf8_decode:function(e){var t="";var n=0;var r=c1=c2=0;while(n<e.length){r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r);n++}else if(r>191&&r<224){c2=e.charCodeAt(n+1);t+=String.fromCharCode((r&31)<<6|c2&63);n+=2}else{c2=e.charCodeAt(n+1);c3=e.charCodeAt(n+2);t+=String.fromCharCode((r&15)<<12|(c2&63)<<6|c3&63);n+=3}}return t}}
  return Base64.encode(token)
}
// Query for every record in "table1" field1copy
let table = base.getTable("table1");

let tableQuery = await table.selectRecordsAsync();

for(let tableRec of tableQuery.records) {
    b64 = btoa(tableRec.getCellValue("Field1copy"));
    
        // Insert records in "field2paste" table1
await table.updateRecordAsync(tableRec, {
            "Field2paste" : b64,
        });
}
 
 
Hope it is useful for someone.




For anyone looking to convert MapCache fields to latitude and longitude, the inverse holds:

cross posted from https://community.airtable.com/t5/other-questions/convert-address-list-to-geocode-latitude-and-longitude-through/td-p/27854

------

based on work done by @apg314 and @Yourapp  from this post,  https://community.airtable.com/t5/development-apis/base64-conversion/td-p/103578
I was able to modify the code for Base64 decoding rather than encoding. 

Just copy paste code below into a script block and execute to give you a JSON string which contains lat & long
It's a big JSON bundle so you need extra formula fields to strip out lat & long

eg Lat:   

MID( JSONOutput, FIND("Australia",JSONOutput)+17, 11)     
not 100% as decimals vary, but 2000 records had about 10 errors needing manual adjustment
-----

function btoa(token) {
var Base64={_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",decodeURI:function(e){var t="";var n,r,i,s,o,u,a;var f=0;e=Base64._utf8_encode(e);while(f<e.length){n=e.charCodeAt(f++);r=e.charCodeAt(f++);i=e.charCodeAt(f++);s=n>>2;o=(n&3)<<4|r>>4;u=(r&15)<<2|i>>6;a=i&63;if(isNaN(r)){u=a=64}else if(isNaN(i)){a=64}t=t+this._keyStr.charAt(s)+this._keyStr.charAt(o)+this._keyStr.charAt(u)+this._keyStr.charAt(a)}return t},decode:function(e){var t="";var n,r,i;var s,o,u,a;var f=0;e=e.replace(/[^A-Za-z0-9\+\/\=]/g,"");while(f<e.length){s=this._keyStr.indexOf(e.charAt(f++));o=this._keyStr.indexOf(e.charAt(f++));u=this._keyStr.indexOf(e.charAt(f++));a=this._keyStr.indexOf(e.charAt(f++));n=s<<2|o>>4;r=(o&15)<<4|u>>2;i=(u&3)<<6|a;t=t+String.fromCharCode(n);if(u!=64){t=t+String.fromCharCode(r)}if(a!=64){t=t+String.fromCharCode(i)}}t=Base64._utf8_decode(t);return t},_utf8_encode:function(e){e=e.replace(/\r\n/g,"\n");var t="";for(var n=0;n<e.length;n++){var r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r)}else if(r>127&&r<2048){t+=String.fromCharCode(r>>6|192);t+=String.fromCharCode(r&63|128)}else{t+=String.fromCharCode(r>>12|224);t+=String.fromCharCode(r>>6&63|128);t+=String.fromCharCode(r&63|128)}}return t},_utf8_decode:function(e){var t="";var n=0;var r=c1=c2=0;while(n<e.length){r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r);n++}else if(r>191&&r<224){c2=e.charCodeAt(n+1);t+=String.fromCharCode((r&31)<<6|c2&63);n+=2}else{c2=e.charCodeAt(n+1);c3=e.charCodeAt(n+2);t+=String.fromCharCode((r&15)<<12|(c2&63)<<6|c3&63);n+=3}}return t}}
return Base64.decode(token)
}


// Change this name to use a different table
let table = base.getTable("Company");

let tableQuery = await table.selectRecordsAsync();

for(let tableRec of tableQuery.records) {
b64 = btoa(tableRec.getCellValue("MapCache"));
 
// Insert records in "field2paste" table1
await table.updateRecordAsync(tableRec, {
"JSONOutput" : b64,
});
}

Forum|alt.badge.img+1
  • New Participant
  • 1 reply
  • November 3, 2024
Bill_French wrote:

This is why I was so careful to understand the scripting context. This is a possible out on the script action side.


so what is the solution to base64Encode an image url in automation script?


Reply