0

I'm new to React native and Expo, but started to write my own app on it, with the same backend i used with my Cordova app.

Unfortunately i hit a roadblock trying to recreate the btoa() function from browsers, that i use to authenticate users with Basic authorization.

No matter what i try, i can't seem to get the same result as i did with btoa. I tried researching the subject, but i can't find a solid answer what's the difference between Base64.encode() and btoa().

I know i'm doing something wrong. When i try out the post request with Postman, i get the correct Basic auth token with it. But when i do it in code with base64 encoding(tried multiple libraries), the result differs. Example:

test@test.com:asdasd

in postman: "dGVzdEB0ZXN0LmNvbTphc2Rhc2Rhc2Q="

in app(to utf8, then base64): "W29iamVjdCBBcnJheUJ1ZmZlcl0="

Relevant part of my code:

const utf8_enc = utf8.encode(email+':'+password);
const b64_enc = base64.encode(utf8_enc);
console.log(b64_enc);

Used libraries:

Base64- https://www.npmjs.com/package/base-64

UTF8 - https://github.com/mathiasbynens/utf8.js

Please tell me why are the two different, and how can i recreate the Postman version.

Thank you!

  • Two questions, 1) Is that the correct string from postman? When I test my example code, I get `dGVzdEB0ZXN0LmNvbTphc2Rhc2Q=` when using `btoa()`. 2) Why are you using `utf8.encode()` prior to `base64.encode()`? My understanding of `btoa` is that it's just a Base64 encoding of a string, so you only need `base64.encode()'. – Michael Cheng Mar 22 '18 at 16:01

1 Answers1

-1

Ok, I see what's happening now. If you follow the docs for that utf8 package, it won't import correctly in React Native. You can see that it's not imported correctly by trying to access decode() or version as both will give you undefined. I think the reason is because they don't support es2015 modules (see this rejected PR). This package will however work fine in Node.js or in the browser.

Oddly enough, you do have access to encode() when you import. It just doesn't do what you think it does. When you attempt to use encode(), all it actually returns is the string: [object ArrayBuffer]. In fact, no matter what string you pass to it, it'll always return the same result. Now if you use btoa() on this string (with or without UTF-8 conversion since there's no difference in this case), you will see that you get that same output in the browser: W29iamVjdCBBcnJheUJ1ZmZlcl0=

So, how to get around this?

If all you expect are extended ASCII strings, then you don't need to encode it in UTF-8 as they will all be within the valid character set. So you can just do:

 base64.encode(email+':'+password);

However, if you anticipate supporting all Unicode characters, then you have a few options to convert that string:

  1. Fork the utf8 package to have it support modules/exporting.
  2. Copy paste the entirety of the utf8 source and put it in your own local library and export the functions.
  3. Write your own UTF-8 encoder/decoder using the method suggested here which itself is from the MDN Documentation.

So there's a reference to a solution, here is the relevant encode part of the code from the MDN documentation turned into a function:

function utf8encode(str) {
  return encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function(
    match,
    p1
  ) {
    return String.fromCharCode(parseInt(p1, 16));
  });
}
Michael Cheng
  • 9,644
  • 6
  • 46
  • 48
  • I'm using utf-8, because that is what's written in the base64 documentation. Removing the utf8 conversion, gives the same result with this example. I actually found that answer, that's why i'm using base64, but it doesn't give the same result as btoa() in browsers, that's why i'm so confused. – Ferenc Dobó Mar 22 '18 at 16:41
  • @FerencDobó Ok, figured it out. I only looked at the simple example in their docs and just assumed UTF-8 would do something strange to plain ASCII strings. Very wrong about that, but your comment led me to figure out what was really going on. Thanks. – Michael Cheng Mar 22 '18 at 18:55
  • 1
    Thank you for your time put in. In the end i figured out that i passed the email and password incorrectly, rendering them into one object. But i figured this out, because you said you get the same results always, which i had as well, even without the utf-8 conversion. – Ferenc Dobó Mar 23 '18 at 15:28