Is it possible to Base64 Encode a string?

… so that I can use it for authorization header?

1 Like

I would recommend doing this once in advance and storing the encoded item in Scriptable - you could use Workflow/Shortcuts to do that (there’s an action for it) - I don’t remember seeing a way to do that in Scriptable itself, and from memory I don’t think there’s a native way to do so in JavaScript.

1 Like

No, this can get a bit tricky in JavaScript. I’ve thought about making an API for encoding/decoding a base 64 string. I’m just not sure where to put such APIs. Maybe introduce something called “StringUtils”?

StringUtils.toBase64(“automators”)
StringUtils.fromBase64(“YXV0b21hdG9ycw==”)
1 Like

There is btoa() (and atob()) which I believe are native Javascript, but they are typically deployed tied to a browser window object … which we don’t have an equivalent for in Scriptable.

Could that be incorporated somehow to save creating something brand new?

1 Like

The API could be exposed as btoa() and atob() and maybe that’s a good idea. My main concern is that when adding many of these global functions, it will start to clutter the documentation.

2 Likes

If it’s key to successful use of your app you really should include these two. And naming them btoa and atob says you need to replicate their existing parameters and returned results.

In the interim, this code from How to Encode and Decode Strings with Base64 in JavaScript - from Scotch.io seems to work well in a few quick tests I did.

// Create Base64 Object
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}}

// Define the string
var string = 'Hello World!';

// Encode the String
var encodedString = Base64.encode(string);
console.log(encodedString); // Outputs: "SGVsbG8gV29ybGQh"

// Decode the String
var decodedString = Base64.decode(encodedString);
console.log(decodedString); // Outputs: "Hello World!"
2 Likes

Just had the same problem. Any update on this?

Maybe put them in a “Browser” namespace? That will make it clear to web devs at least. There are some other good helpers like de/encodeURI/Component that would be nice to add if not already available.

decodeURI, encodeURI, encodeURIComponent and decodeURIComponent should be available already. I’m still considering adding atob and btoa and think I’ve figured out an approach to add them as top-level functions without cluttering the documentation.

In the mean time, note that base 64 conversions is in fact supported by the Data API.

2 Likes

Good enough for me… Thanks!

I’m considering adding the following as global level functions to minimize this issue. Please let me know your thoughts on this approach.

function atob(str) {
  return Data.fromString(str).toBase64String()
}

function btoa(str) {
  return Data.fromBase64String(str).toRawString()
}
3 Likes

Thank you for implementing this.

1 Like

Is this broken now?

const apiKey1 = Data.fromString(username + ":" + password).toBase64String()
const apiKey2 = atob(username + ":" + password)

The first line executes fine, but the second one fails:

TypeError: null is not an object (evaluating 'Data.fromBase64String(str).toRawString')

(Looks like atob is now executing btoa?)

Have you noted this in the beta builds?

1 Like

I did see it sometime ago, but apparently forgot about it… Thank you for reminding me!

Checked some external documentation; looks like I indeed need to use btoa to create a base-64 encoded ASCII string.