Hi All,
I am trying to decode base64 encoded string in apigee through below javascript in apigee, but it is giving me an error "Error: "atob" is not defined."
var jsonstr = context.getVariable("JWTToken"); var str = decoder(jsonstr); context.setVariable("context.targetResponse",str); function decoder(base64url) { try { //Convert base 64 url to base 64 var base64 = base64url.replace('-', '+').replace('_', '/'); //atob() is a built in JS function that decodes a base-64 encoded string var utf8 = atob(base64); //Then parse that into JSON var json = JSON.parse(utf8); //Then make that JSON look pretty var json_string = JSON.stringify(json, null, 4); } catch (err) { json_string = "Bad Section.\nError: " + err.message; } print(json_string); return json_string; }
Solved! Go to Solution.
do you have Apigee Edge SaaS? You can do what you want with the DecodeJWT policy. It's built-in.
If you do not have Apigee Edge SaaS, then you need something like this:
// jwtDecode.js function base64Decode(input) { // Takes a base 64 encoded string "input", strips any "=" or // "==" padding off it and converts its base 64 numerals into // regular integers (using a string as a lookup table). These // are then written out as 6-bit binary numbers and concatenated // together. The result is split into 8-bit sequences and these // are converted to string characters, which are concatenated // and output. // The index/character relationship in the following string acts // as a lookup table to convert from base 64 numerals to // Javascript integers var swaps = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", ob = "", output = "", tb = "", i, L; input = input.replace("=",""); // strip padding for (i=0, L = input.length; i < L; i++) { tb = swaps.indexOf(input.charAt(i)).toString(2); while (tb.length < 6) { // Add significant zeroes tb = "0"+tb; } while (tb.length > 6) { // Remove significant bits tb = tb.substring(1); } ob += tb; while (ob.length >= 8) { output += String.fromCharCode(parseInt(ob.substring(0,8),2)); ob = ob.substring(8); } } return output; } function decodeJwt(input){ var parts = input.split('.'), header, payload; if (parts.length !== 3) { return null; // not a valid JWT } header = base64Decode(parts[0]); header = header.replace(/\0/g, ''); //header = JSON.parse(header); payload = base64Decode(parts[1]); payload = payload.replace(/\0/g, ''); //payload = JSON.parse(payload); return { header: header, payload : payload, sig : parts[2] }; } var jsonstr = context.getVariable("JWTToken"); var result = decodeJwt(jsonstr); context.setVariable("context.targetResponse",result.payload);
As for why the atob() function is not available - the JavaScript callout does not have the full node runtime, nor does it have the browser runtime. It's a stripped down Rhino runtime. atob() is not included in that.
do you have Apigee Edge SaaS? You can do what you want with the DecodeJWT policy. It's built-in.
If you do not have Apigee Edge SaaS, then you need something like this:
// jwtDecode.js function base64Decode(input) { // Takes a base 64 encoded string "input", strips any "=" or // "==" padding off it and converts its base 64 numerals into // regular integers (using a string as a lookup table). These // are then written out as 6-bit binary numbers and concatenated // together. The result is split into 8-bit sequences and these // are converted to string characters, which are concatenated // and output. // The index/character relationship in the following string acts // as a lookup table to convert from base 64 numerals to // Javascript integers var swaps = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", ob = "", output = "", tb = "", i, L; input = input.replace("=",""); // strip padding for (i=0, L = input.length; i < L; i++) { tb = swaps.indexOf(input.charAt(i)).toString(2); while (tb.length < 6) { // Add significant zeroes tb = "0"+tb; } while (tb.length > 6) { // Remove significant bits tb = tb.substring(1); } ob += tb; while (ob.length >= 8) { output += String.fromCharCode(parseInt(ob.substring(0,8),2)); ob = ob.substring(8); } } return output; } function decodeJwt(input){ var parts = input.split('.'), header, payload; if (parts.length !== 3) { return null; // not a valid JWT } header = base64Decode(parts[0]); header = header.replace(/\0/g, ''); //header = JSON.parse(header); payload = base64Decode(parts[1]); payload = payload.replace(/\0/g, ''); //payload = JSON.parse(payload); return { header: header, payload : payload, sig : parts[2] }; } var jsonstr = context.getVariable("JWTToken"); var result = decodeJwt(jsonstr); context.setVariable("context.targetResponse",result.payload);
As for why the atob() function is not available - the JavaScript callout does not have the full node runtime, nor does it have the browser runtime. It's a stripped down Rhino runtime. atob() is not included in that.
Hi @Dino,
While running above javascript code, it is giving following error:
{"fault":{"faultstring":"Execution of JavaScript-1 failed with error: Javascript runtime error: \"TypeError: Cannot call method \"split\" of null. (JavaScript-1.js:45)\"","detail":{"errorcode":"steps.javascript.ScriptExecutionFailed"}}}
Yes - this error is telling you that you haven't set the context variable called JWTToken.
That code is a sample. You may need to modify it slightly for your environment.
Do you have the token in a context variable? What is the name of the variable?
Use that name in place of JWTToken in the line that reads:
var jsonstr = context.getVariable("JWTToken");
After setting the context variable, code worked.
Thanks for all your prompt responses 🙂
Regards
Saransh Tiwari
Thumbsup. Glad to help.
If anyone is looking for an answer in 2021, you can also use python. Just use the Python extension and here it goes:
import base64 def decode (encoded): decoded = base64.b64decode(encoded) return decoded encoded = flow.getVariable("your-reference-variable-here") decoded = decode(encoded)
You can use the "static function" in Apigee Message Templates to base64-decode anything that is a string:
<AssignMessage name="AM-DecodeBase64"> <AssignVariable> <Name>decoded</Name> <Template>{decodeBase64(encoded_value)}</Template> </AssignVariable> </AssignMessage>
This won't work if the encoded thing represents a byte stream that cannot be decoded into a UTF-8 string. For example, if it's a base64-encoded image or PDF. For that you need a different approach - a Java callout or....something else.