From Cookie strings into usable JavaScript
Tags: javascript, es6
Published: 2022-06-17 20:31:50

---
title: From Cookie strings into usable JavaScript
published: true
description: Parsing Cookie strings and transforming them into usable JavaScript
tags: javascript, es6
# cover_image: https://direct_url_to_image.jpg
# Use a ratio of 100:42 for best results.
---

## Background
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.

## Assumptions
I assume that the reader is knowledgable on using .split, .map, and .reduce array methods.

## The Problem
Our Backend is built using Ruby on Rails and the problem I was facing when the response cookies were set were: 
1. Multiple cookies were stored for the Frontend
2. Both the access token expiration and refresh token expiration are stored as a Ruby hash in an encoded string.

```javascript
// 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'
```

## Requirements
From here I had a few requirements of my own to ensure the session management work as I expected
- An object with both the access token & refresh token expirations
- Having the expirations be usable JavaScript dates


## Part 1 of the Creating Our Cookie Object
```javascript
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))
    })
  }), {});
```

## Part 1 Breakdown
1) We create a variable from `document.cookie`

2) We split each cookie string
```javascript
// 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']
```

3) We map each cookie to a new array of arrays by splitting on the '='
```javascript
// 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']
]
```

4) We reduce to a single usable object by destructing the cookie's key|value pair if it matches our 'info_token' and call another function with the value being interpreted as a decodedURIComponent string.
```javascript
// 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}'
```

## Part 2 of Creating our Cookie Object `formatOurCookie` function

```javascript
function 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)
      }
  }, {})
}

```

## Part 2 of Breakdown of `formatOurCookie` function
1) Take the `unformattedCookieString` 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
```javascript
// 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}'
]
```

2) Use the .reduce method to loop through the split array with the goal being to reduce it into a single object.

3) We want to destructure the key|value pairs by

  a. First removing all instances of `:{` and `}` from the string.
  ```javascript
// 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
```javascript
// 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`
```javascript
// original
'Fri,+17+Jun+2022+16:11:58.265440745+UTC++00:00'
// formatted
'Fri, 17 Jun 2022 16:11:58.265440745 UTC'
```
4) Return the accumulator and coerce the above string into a usable JavaScript Date

## TL/DR
```javascript
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! 🎉