Alexander Garcia
Parsing Cookie strings and transforming them into usable JavaScript because backend engineers were busy
Alexander Garcia is an effective JavaScript Engineer who crafts stunning web experiences.
Alexander Garcia is a meticulous Web Architect who creates scalable, maintainable web solutions.
Alexander Garcia is a passionate Software Consultant who develops extendable, fault-tolerant code.
Alexander Garcia is a detail-oriented Web Developer who builds user-friendly websites.
Alexander Garcia is a passionate Lead Software Engineer who builds user-friendly experiences.
Alexander Garcia is a trailblazing UI Engineer who develops pixel-perfect code and design.
Hello all, this will be a slightly in-depth post that I hope helps some developers out there.
We are using OAuth and one of the ways we are using session management on the Front-end is by providing cookies of each of the Access Token and Refresh Token expiration dates.
I assume that the reader is knowledgable on using .split, .map, and .reduce array methods.
Our Backend is built using Ruby on Rails and the problem I was facing when the response cookies were set were:
// document.cookie "FLIPPER_ID=flipper_on; token_info=%7B%3Aaccess_token_expiration%3D%3EFri%2C+17+Jun+2022+16%3A11%3A58.265440745+UTC+%2B00%3A00%2C+%3Arefresh_token_expiration%3D%3EFri%2C+17+Jun+2022+16%3A36%3A58.147084176+UTC+%2B00%3A00%7D";
From here I had a few requirements of my own to ensure the session management work as I expected
const oAuthCookieObject = document.cookie // Creates an array of each cookie .split(";") // Maps the cookies to <key>=<value> pairs .map((cookie) => cookie.split("=")) /* Reduces it down to a single object of our access token and refresh tokens by checking if our cookieKey includes the 'info_token' value we are looking for */ .reduce( (_, [cookieKey, cookieValue]) => ({ ...(cookieKey.includes("info_token") && { ...formatOurCookie(decodeURIComponent(cookieValue)), }), }), {} );
document.cookie// original string "FLIPPER_ID=flipper_on; info_token="[ // after .split ("FLIPPER_ID=flipper_on", "info_token=%7B%3Aaccess_token_expiration%3D%3EFri%2C+17+Jun+2022+16%3A11%3A58.265440745+UTC+%2B00%3A00%2C+%3Arefresh_token_expiration%3D%3EFri%2C+17+Jun+2022+16%3A36%3A58.147084176+UTC+%2B00%3A00%7D") ];
// original array after .split [ 'FLIPPER_ID=flipper_on', 'info_token=%7B%3Aaccess_token_expiration%3D%3EFri%2C+17+Jun+2022+16%3A11%3A58.265440745+UTC+%2B00%3A00%2C+%3Arefresh_token_expiration%3D%3EFri%2C+17+Jun+2022+16%3A36%3A58.147084176+UTC+%2B00%3A00%7D' ] // after we use .map [ ['FLIPPER_ID', 'flipper_on'] ['info_token', ['%7B%3Aaccess_token_expiration%3D%3EFri%2C+17+Jun+2022+16%3A11%3A58.265440745+UTC+%2B00%3A00%2C+%3Arefresh_token_expiration%3D%3EFri%2C+17+Jun+2022+16%3A36%3A58.147084176+UTC+%2B00%3A00%7D'] ]
// String before decodeURIComponent is called const nonDecoded = "%7B%3Aaccess_token_expiration%3D%3EFri%2C+17+Jun+2022+16%3A11%3A58.265440745+UTC+%2B00%3A00%2C+%3Arefresh_token_expiration%3D%3EFri%2C+17+Jun+2022+16%3A36%3A58.147084176+UTC+%2B00%3A00%7D"; // String after decodedURIComponent is called const decoded = "{:access_token_expiration=>Fri,+17+Jun+2022+16:11:58.265440745+UTC++00:00,+:refresh_token_expiration=>Fri,+17+Jun+2022+16:36:58.147084176+UTC++00:00}";
formatOurCookie functionfunction formatOurCookie(unformattedCookieString) { return ( unformattedCookieString // Creates an array by splitting on ',+:' to get the access token and refresh token .split(",+:") .reduce((obj, cookieVal) => { // Destructure the key|value pair of the token's name and its expiration date and uses Regex to remove {: and } const [key, val] = cookieVal.replace(/{:|}/g, "").split("=>"); // Update the value by replacing the '+' with spaces and removing the UTC timezone ending const formattedValue = val .replaceAll("++00:00", "") .replaceAll("+", " "); // Return's the accumulator and the key|value pair with a usable JavaScript Date object return { ...obj, [key]: new Date(formattedValue), }; }, {}) ); }
formatOurCookie functionunformattedCookieString parameter which will be a decodeURIComponent string and use the split method on ',+:' to get the access_token_expiration and the refresh_token_expiration into an array// original string "{:access_token_expiration=>Fri,+17+Jun+2022+16:11:58.265440745+UTC++00:00,+:refresh_token_expiration=>Fri,+17+Jun+2022+16:36:58.147084176+UTC++00:00}"[ // array split on the `',+:'` ("{:access_token_expiration=>Fri,+17+Jun+2022+16:11:58.265440745+UTC++00:00", "refresh_token_expiration=>Fri,+17+Jun+2022+16:36:58.147084176+UTC++00:00}") ];
Use the .reduce method to loop through the split array with the goal being to reduce it into a single object.
We want to destructure the key|value pairs by
a. First removing all instances of :{ and } from the string.
// original (removes `:{`) "{:access_token_expiration=>Fri,+17+Jun+2022+16:11:58.265440745+UTC++00:00"; // after removes `:{` "access_token_expiration=>Fri,+17+Jun+2022+16:11:58.265440745+UTC++00:00"; // after removes `}` "refresh_token_expiration=>Fri,+17+Jun+2022+16:36:58.147084176+UTC++00:00";
b. Then by splitting the string on the => using the .split method
// original "access_token_expiration=>Fri,+17+Jun+2022+16:11:58.265440745+UTC++00:00"[ // transformed ("access_token_expiration", "Fri,+17+Jun+2022+16:11:58.265440745+UTC++00:00") ];
c. Format the key's value into a usable format by replacing the + with a single space and removing the ++00:00
// original "Fri,+17+Jun+2022+16:11:58.265440745+UTC++00:00"; // formatted "Fri, 17 Jun 2022 16:11:58.265440745 UTC";
const oAuthCookieObject = document.cookie .split(";") .map((cookie) => cookie.split("=")) .reduce( (_, [cookieKey, cookieValue]) => ({ ...(cookieKey.includes("info_token") && { ...formatOAuthCookie(decodeURIComponent(cookieValue)), }), }), {} ); function formatOurCookie(unformattedCookieString) { return unformattedCookieString.split(",+:").reduce((obj, cookieVal) => { const [key, val] = cookieVal.replace(/{:|}/g, "").split("=>"); const formattedValue = val.replaceAll("++00:00", "").replaceAll("+", " "); return { ...obj, [key]: new Date(formattedValue), }; }, {}); }
Hopefully some of you found that useful. Cheers! 🎉