Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Alexander Garcia
Alexander Garcia

Posted on • Edited on

     

From Cookie strings into usable JavaScript

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.
// 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'
Enter fullscreen modeExit fullscreen mode

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

constoAuthCookieObject=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))})}),{});
Enter fullscreen modeExit fullscreen mode

Part 1 Breakdown

1) We create a variable fromdocument.cookie

2) We split each cookie string

// 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']
Enter fullscreen modeExit fullscreen mode

3) We map each cookie to a new array of arrays by splitting on the '='

// 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']]
Enter fullscreen modeExit fullscreen mode

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.

// String before decodeURIComponent is calledconstnonDecoded='%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 calledconstdecoded='{: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}'
Enter fullscreen modeExit fullscreen mode

Part 2 of Creating our Cookie ObjectformatOurCookie function

functionformatOurCookie(unformattedCookieString){returnunformattedCookieString// 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 endingconstformattedValue=val.replaceAll('++00:00','').replaceAll('+','')// Return's the accumulator and the key|value pair with a usable JavaScript Date objectreturn{...obj,[key]:newDate(formattedValue)}},{})}
Enter fullscreen modeExit fullscreen mode

Part 2 of Breakdown offormatOurCookie function

1) Take theunformattedCookieString parameter which will be adecodeURIComponent 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}']
Enter fullscreen modeExit fullscreen mode

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.

// 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'
Enter fullscreen modeExit fullscreen mode

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']
Enter fullscreen modeExit fullscreen mode

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'
Enter fullscreen modeExit fullscreen mode

4) Return the accumulator and coerce the above string into a usable JavaScript Date

TL/DR

constoAuthCookieObject=document.cookie.split(';').map(cookie=>cookie.split('=')).reduce((_,[cookieKey,cookieValue])=>({...(cookieKey.includes('info_token')&&{...formatOAuthCookie(decodeURIComponent(cookieValue))})}),{});functionformatOurCookie(unformattedCookieString){returnunformattedCookieString.split(',+:').reduce((obj,cookieVal)=>{const[key,val]=cookieVal.replace(/{:|}/g,'').split('=>')constformattedValue=val.replaceAll('++00:00','').replaceAll('+','')return{...obj,[key]:newDate(formattedValue)}},{})}
Enter fullscreen modeExit fullscreen mode

Hopefully some of you found that useful. Cheers! 🎉

Top comments(2)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss
CollapseExpand
 
ahmad_butt_faa7e5cc876ea7 profile image
Ahmad
.Net and React dev :) Founder ofDev + Design + Business Collaboration Platform:https://www.iwannagoapp.com
  • Location
    Toronto
  • Joined

thanks for sharing the code! interesting use case with multiple cookies..any specific reason why if you dont mind me asking?

CollapseExpand
 
asg5704 profile image
Alexander Garcia
  • Location
    Columbia, MD
  • Education
    Bachelors
  • Work
    Lead Frontend Engineer at Oddball
  • Joined

Sure. On our project we have multiple cookies being set for OAuth with most of them being httpOnly cookies (meaning they aren't accessible to JavaScript). We decided to store the token's expiration in a cookie available in JavaScript so that we could reduce the number of network requests and only call a silent refresh request when needed.

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

  • Location
    Columbia, MD
  • Education
    Bachelors
  • Work
    Lead Frontend Engineer at Oddball
  • Joined

More fromAlexander Garcia

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp