I'm using the window.atob('string')
function to decode a string from base64 to a string. Now I wonder, is there any way to check that 'string' is actually valid base64? I would like to be notified if the string is not base64 so I can perform a different action.
-
Is your question how to determine whether a string it is *valid* base64 – or whether you're looking at a string of base64 that has information encoded in it? That is a subtle difference – for the former there are a few excellent [answers](https://stackoverflow.com/a/35002237/1246547) below, for the latter, there is no deterministic answer (it's like asking if a sound is music or language). I'd therefore suggest to replace "in" with "valid" in your question title. – Philzen Jul 09 '22 at 15:18
13 Answers
Building on @anders-marzi-tornblad's answer, using the regex to make a simple true/false test for base64 validity is as easy as follows:
var base64regex = /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/;
base64regex.test("SomeStringObviouslyNotBase64Encoded..."); // FALSE
base64regex.test("U29tZVN0cmluZ09idmlvdXNseU5vdEJhc2U2NEVuY29kZWQ="); // TRUE
Update 2021
- Following the comments below it transpires this regex-based solution provides a more accurate check than simply
try
`ingatob
because the latter doesn't check for=
-padding. According to RFC4648=
-padding may only be ignored for base16-encoding or if the data length is known implicitely. - Regex-based solution also seems to be the fastest as hinted by kai. As jsperf seems flaky atm i made a new test on jsbench which confirms this.

- 3,945
- 30
- 46
-
-
@modernator - because '1234' is a string of length 4 - and therefore matches the first ([0-9a-zA-Z+/]{4})* part of the regex – joensson Sep 28 '17 at 06:59
-
-
1Doesn't work with f.i. the word "mindmaps" base64regex.test("mindmaps"); // return TRUE while FALSE was expected – cavo789 Nov 12 '18 at 13:47
-
1@cavo789 Still correct, because "mindmaps" is a valid base64 string... which you can easily verify yourself: `window.btoa("\u009a)Ý\u0099ªl")` – Philzen Jan 21 '19 at 01:18
-
`base64regex.test("SomeStringObviouslyNotBase64Encoded");` returns false, although this is can be decoded: `JJÚâ¾*.²\¢ÐZ±î¸w(uç`. I don't think you can validate base64 with regex, a try..catch solution would seem much more reliable. – undefined Feb 10 '21 at 08:56
-
1@undefined That's interesting, because technically it should throw an exception, as that is not a valid base64 string. A valid string would be "SomeStringObviouslyNotBase64Encoded=". Wondering if this an implementation weakness or working as designed? – Philzen Feb 10 '21 at 19:32
-
-
1Yes, `atob` is not a good options for testing if a string is base64-encoded, as it's too lax. It allows base64-encoded strings without the required `=` or `==` padding. Base64-encoded strings are supposed to have lengths on multiples of 4. – Anders Marzi Tornblad May 20 '21 at 15:34
-
@undefined So above comment clarifies the confusion and explains why testing with a regex is *at least* better than testing with `atob`. Not saying there isn't a better way and still keen to learn about one. – Philzen May 20 '21 at 19:55
-
@Philzen I personally do not know another method to decode base64 in JavaScript other than `atob` and this question is about JavaScript entirely – undefined May 21 '21 at 14:48
-
This gives Maximum call stack size exceeded on the validation of a 3MB image. – jcesarmobile Aug 22 '22 at 11:17
-
This matches any string of length 4 or its multiple, please check before you use this. – swateek Jul 14 '23 at 12:23
-
-
-
1@swateek Works for me: `base64regex.test('fuel') === true` as `fuel` is a perfectly valid encoded base64 string that decodes to `~ç¥`. I suspect you're looking for a function to tell if you're looking at an encoded or vanilla payload … but such a (non-AI based and fully deterministic) function does not exist, though i'd be delighted to be proven wrong. Still that'd be outside the scope of this thread, as the OP clearly asked for a method to tell if a string contains valid base64, which `fuel` according to RFC4648 is. – Philzen Jul 26 '23 at 17:01
If you want to check whether it can be decoded or not, you can simply try decoding it and see whether it failed:
try {
window.atob(str);
} catch(e) {
// something failed
// if you want to be specific and only catch the error which means
// the base 64 was invalid, then check for 'e.code === 5'.
// (because 'DOMException.INVALID_CHARACTER_ERR === 5')
}

- 151,816
- 78
- 307
- 352
-
3+1, nicer. (I can't find anything that says if it must throw an exception on failure; a reference link to that would be handy :) – Dave Newton Oct 22 '11 at 15:06
-
1@Dave Newton: It is suggested to be added to the HTML5 specification: http://lists.w3.org/Archives/Public/public-html-diffs/2011Feb/0005.html "Throws an INVALID_CHARACTER_ERR exception if the input string is not valid base64 data." – pimvdb Oct 22 '11 at 15:11
-
This would be a nice solution, but it doesn't seem to throw an exception upon a failed decode (at least not in Chrome). – Jonatan Oct 23 '11 at 21:08
-
1some things successfully decode that aren't base64, such as atob("krtest"); see Dan Smith's answer below for a complete method – jakraska Sep 30 '16 at 14:49
-
-
I'm not sure I like using exceptions for flow control, but it's a clever hack. :) – Anders Marzi Tornblad Sep 11 '18 at 15:04
-
`atob` is deprecated. see my answer below for a clean, modern day solution similar to this one. https://stackoverflow.com/a/76203291/441894 – Jason May 08 '23 at 18:23
This should do the trick.
function isBase64(str) {
if (str ==='' || str.trim() ===''){ return false; }
try {
return btoa(atob(str)) == str;
} catch (err) {
return false;
}
}

- 18,436
- 4
- 42
- 61

- 623
- 6
- 3
-
-
3Doesn't work. Somehow many other strings get pass this validation. – zhuhang.jasper Nov 27 '18 at 02:40
-
This doesn't work btoa(atob('test')) == 'test' returns true. The problem is that many plain strings are valide base64 although they are not base64 encoded. In which case the valid base64 plain string gets decoded to another non base64 string which can be encoded to the original plain string. Is there some inherent base64 structure we can test for that only works for bse64 encoded strings? – Marc van Nieuwenhuijzen May 09 '19 at 15:10
-
3
-
If str is null or undefined, the str.trim() kills js execution .. Put if (!str) return false; in the first line – Scholtz Jun 10 '21 at 10:19
-
1An empty string is a valid base64 encoding of an empty string. Why do you rule that out? – Barmar Oct 16 '21 at 05:21
If "valid" means "only has base64 chars in it" then check against /[A-Za-z0-9+/=]/
.
If "valid" means a "legal" base64-encoded string then you should check for the =
at the end.
If "valid" means it's something reasonable after decoding then it requires domain knowledge.

- 5,719
- 8
- 38
- 51

- 158,873
- 26
- 254
- 302
-
3
-
1Depends on the implementation.. usually the 63rd and 64th characters are chosen as + and /, but it may vary. Usually ends with one or two `=` characters as well, whichever is needed for an even number of characters. – Oct 22 '11 at 15:02
-
-
8Note some implementations of base64 do not required the padding. A check for '=' may not be sufficient http://en.wikipedia.org/wiki/Base64#Implementations_and_history – catalyst294 Feb 19 '15 at 21:56
-
23
I would use a regular expression for that. Try this one:
/^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/
Explanation:
^ # Start of input
([0-9a-zA-Z+/]{4})* # Groups of 4 valid characters decode
# to 24 bits of data for each group
( # Either ending with:
([0-9a-zA-Z+/]{2}==) # two valid characters followed by ==
| # , or
([0-9a-zA-Z+/]{3}=) # three valid characters followed by =
)? # , or nothing
$ # End of input

- 18,896
- 9
- 51
- 66
-
1
-
`SomeStringObviouslyNotBase64Encoded` tests FALSE, although it's valid base64: `atob("SomeStringObviouslyNotBase64Encoded")` returns `JJÚâ¾*.²\¢ÐZ±î¸w(uç`. Is it possible to improve this regex so that it is 100% accurate? – undefined Feb 10 '21 at 08:59
-
3Actually, it is `window.atob` that accepts strings that are not completely correct. Your example has exactly 35 characters, and should be padded with exactly one `=`. Quote from Wikipedia? *"...when the length of the unencoded input is not a multiple of three, the encoded output must have padding added so that its length is a multiple of four."* – Anders Marzi Tornblad Feb 10 '21 at 15:56
This method attempts to decode then encode and compare to the original. Could also be combined with the other answers for environments that throw on parsing errors. Its also possible to have a string that looks like valid base64 from a regex point of view but is not actual base64.
if(btoa(atob(str))==str){
//...
}

- 73
- 1
- 1
-
If `str` is not valid base64, `atob(str)` will throw an uncaught error. A try..catch solution would seem better. – undefined Feb 10 '21 at 09:01
-
Thanks for hint! Best idea (much better than just validate allowed chars for base64). My implementation in nodejs: https://stackoverflow.com/a/68286515/3826175 – mikep Jul 07 '21 at 12:56
This is how it's done in one of my favorite validation libs:
const notBase64 = /[^A-Z0-9+\/=]/i;
export default function isBase64(str) {
assertString(str); // remove this line and make sure you pass in a string
const len = str.length;
if (!len || len % 4 !== 0 || notBase64.test(str)) {
return false;
}
const firstPaddingChar = str.indexOf('=');
return firstPaddingChar === -1 ||
firstPaddingChar === len - 1 ||
(firstPaddingChar === len - 2 && str[len - 1] === '=');
}
https://github.com/chriso/validator.js/blob/master/src/lib/isBase64.js

- 24,652
- 10
- 111
- 109
-
-
@DaveNewton what do you mean? That = is not always there? This function doesn't require `=`. – Lukas Liesis Apr 08 '17 at 05:25
-
-
According to [RFC4648](https://datatracker.ietf.org/doc/html/rfc4648#section-5) `=`-padding may only be ignored for base16-encoding or if the data length is known implicitely. – Philzen May 20 '21 at 20:47
Implementation in nodejs (validates not just allowed chars but base64 string at all)
const validateBase64 = function(encoded1) {
var decoded1 = Buffer.from(encoded1, 'base64').toString('utf8');
var encoded2 = Buffer.from(decoded1, 'binary').toString('base64');
return encoded1 == encoded2;
}

- 5,880
- 2
- 30
- 37
For me, a string is likely an encoded base64 if:
- its length is divisible by 4
- uses
A-Z
a-z
0-9
+/=
- only uses
=
in the end (0-2 chars)
so the code would be
function isBase64(str)
{
return str.length % 4 == 0 && /^[A-Za-z0-9+/]+[=]{0,2}$/.test(str);
}

- 1,377
- 13
- 17
-
`isBase64("SomeStringObviouslyNotBase64Encoded")` returns FALSE although it's valid base64 – undefined Feb 10 '21 at 09:05
-
@undefined no, because you need to pad it with `=`, see [RFC here](https://datatracker.ietf.org/doc/html/rfc4648#section-4) a pad character is needed so that the content length is always divisible by 24 bit (or 4 characters of 64-base chars) – willnode Feb 18 '22 at 23:28
-
1In JavaScript, using (the now deprecated I believe) `atob` and `btoa` and as well the recommended `Buffer.from("...", "base64")` do not require padding with `=` as far as I know. I have seen many projects in which the padding `=` chars are removed for various reasons that are beyond me, and such strings nevertheless can be base64 decoded in JS without throwing an error. Your answer is to the point of the question, just leaving this here for any user that wants to check if a string can be decoded instead of checking whether it matches the actual RFC definition – undefined Feb 19 '22 at 22:03
I have tried the below answers but there are some issues.
var base64regex = /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/;
base64regex.test(value)
when using this it will be true with "BBBBB" capital letters. and also it will be true with "4444".
I added some code to work correctly for me.
function (value) {
var base64regex = /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/;
if (base64regex.test(value) && isNaN(value) && !/^[a-zA-Z]+$/.test(value)) {
return decodeURIComponent(escape(window.atob(value)));
}

- 51
- 4
Throwing my results into the fray here. In my case, there was a string that was not base64 but was valid base64 so it was getting decoded into gibberish. (i.e. yyyyyyyy is valid base64 according to the usual regex)
My testing resulted in checking first if the string was a valid base64 string using the regex others shared here and then decrypting it and testing if it was a valid ascii string since (in my case) I should only get ascii characters back. (This can probably be extended to include other characters that may not fall into ascii ranges.)
This is a bit of a mix of multiple answers.
let base64regex = /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/;
function isBase64(str) {
if (str ==='' || str.trim() ===''){ return false; }
try {
if (base64regex.test(str)) {
return /^[\x00-\x7F]*$/.test(atob(str));
} else {
return false
}
} catch (err) {
// catch
}
}
As always with my JavaScript answers, I have no idea what I am doing. So there might be a better way to write this out. But it works for my needs and covers the case when you have a string that isn't supposed to be base64 but is valid and still decrypts as base64.

- 31
- 1
- 5
Try the code below, where str is the string you want to check.
Buffer.from(str, 'base64').toString('base64') === str

- 11
- 1
-
This does not provide an answer to the question. Once you have sufficient [reputation](https://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](https://stackoverflow.com/help/privileges/comment); instead, [provide answers that don't require clarification from the asker](https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can-i-do-instead). - [From Review](/review/late-answers/34581417) – Erik Roznbeker Jun 27 '23 at 10:53
I know its late, but I tried to make it simple here;
function isBase64(encodedString) {
var regexBase64 = /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/;
return regexBase64.test(encodedString); // return TRUE if its base64 string.
}

- 2,000
- 1
- 26
- 34
-
`isBase64("SomeStringObviouslyNotBase64Encoded")` returns FALSE although it's valid base64 – undefined Feb 10 '21 at 09:05
-
Did you verify your that base64String on https://base64.guru/tools/validator as well?? – Arsman Ahmad Feb 10 '21 at 12:08
-
No, I verified that by running `atob("SomeStringObviouslyNotBase64Encoded")` in the browser console. The result is `JJÚâ¾*.²\¢ÐZ±î¸w(uç` (SO trims the spaces) – undefined Feb 10 '21 at 15:51
-
Verify your base64 string on the above given link to confirm if you have right string or not? – Arsman Ahmad Feb 11 '21 at 13:22
-
`The specified value is a valid Base64 string. To decode it, use the Base64 decoder.` – undefined Feb 11 '21 at 15:16