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.
@dchiesa1 DecodeJWT fails to decode for unsignedJWT. I get the following error "Invalid JWS header: The algorithm "alg" header parameter must be for signatures" from trace
correct. The JWT policies in Apigee, including DecodeJWT, do not work (should not work) with unsigned JWT, or JWT with alg="none".
You can "manually" decode such a JWT using JavaScript code if you wish.