Using Local Storage to Persist Login State
Learn how to use local storage to let users log in and log out
This lesson preview is part of the Build a Spotify Connected App course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.
Get unlimited access to Build a Spotify Connected App, plus 70+ \newline books, guides and courses with the \newline Pro subscription.

[00:00 - 00:16] Okay, so in the last module, we successfully passed Spotify auth tokens from our node server to our React app with URL query parameters. In this lesson, we're going to set up a way for our React app to remember those tokens when they're no longer in the URL.
[00:17 - 00:27] First, we'll move our query-param logic from our app.js file to a separate file to keep all Spotify-related logic in one place. It's good practice in projects like this to separate concerns.
[00:28 - 00:35] We don't want our app.js file to store any query-param-related logic. All it needs to know about is whether there is a valid token or not.
[00:36 - 00:53] So let's create a Spotify.js file in the search directory of our React app. Then we can take the query-param logic in our use-effect hook and move that to that file.
[00:54 - 01:05] We'll say get access token and we'll create a function here to store that logic . And we'll have it return the access token.
[01:06 - 01:24] And then below, we'll say export const access token and have it return the value of that function. And then we can refactor our app.js file to import this access token and use a use-state hook to keep track of it.
[01:25 - 01:42] So first, we'll go to our app.js file and then we will import that access token variable. Then we can get rid of everything in this use-effect hook and then up here we 'll say use-state.
[01:43 - 01:52] Then we'll call this token and set token. And then we'll have the initial value of token as null.
[01:53 - 02:06] And then we'll import use-state up here with use-effect. And then all we have to do in our use-effect hook is set token and set it to the access token variable we imported above.
[02:07 - 02:17] Now we can use this token-state variable to conditionally render the login button or a logged-in state with a ternary in our template. So let's get rid of some of this stuff.
[02:18 - 02:33] And here we'll say if there is no token then we want to render the login button . If there is one we can just say h1 logged in.
[02:34 - 03:03] Alright so since there is a access token query parameter in the URL this function is returning a access token which we import here and then we use that token state variable that we set in our use-effect hook and then we render logged in. Now although we're able to let users log in to Spotify and grab the access token from the URL we still have a little problem.
[03:04 - 03:21] Our React app is only aware of the Spotify access token when it's stored as a queer parram on the URL meaning if we visit plain localhost 3000 we'll see the login button but not a logged-in state. We don't want our users to have to go through the login flow every time they visit the app.
[03:22 - 03:33] So how do we fix this problem? We can store our tokens in local storage, a mechanism of the web storage API that lets us store key value pairs in the browser.
[03:34 - 03:47] And local storage is really similar to session storage but there is a key difference between the two. Session storage only stores data for the duration of the page session while local storage stores data even after the browser is closed.
[03:48 - 04:02] So in simpler terms local storage will let us store data in the browser for a particular domain and persist it even when the user closes the tab or navigates away from our app. When marking with local storage browser dev tools are super helpful.
[04:03 - 04:12] In Chrome you can find all items that are currently stored in local storage in the application tab. From here you can update or delete items as you wish.
[04:13 - 04:26] Currently I don't have any local storage items set in localhost 3000 so it'll be empty. So before we dive in to trying to use local storage to store our access tokens we'll first make a game plan.
[04:27 - 04:54] So first when a user first visits our app we'll prompt them to login to Spotify with the login link and then store the access token and refresh token from the resulting URL query perams in local storage. Then since we know that Spotify's access token will eventually expire after 36 00 seconds or one hour we'll preemptively store a timestamp in local storage to keep track of when the tokens currently in use were stored.
[04:55 - 05:15] Then the next time we need to use an access token to make a request to the Spotify API we'll first check if there is a timestamp and access token stored in local storage. If there is we'll check if the token is still valid by determining if the amount of time that has elapsed between the timestamp being set and now is greater than one hour.
[05:16 - 05:32] If the access token is still valid we'll simply use that for our API request. If the access token has expired we'll use the refresh token we stored in local storage to request a new access token from Spotify behind the scenes using our express apps refresh token endpoint.
[05:33 - 05:43] When we receive the new token we'll store it in local storage along with our updated timestamp. In a nutshell our app will store four items in local storage.
[05:44 - 06:04] The Spotify access token, the refresh token, the access token expire time which is 3600 tokens and the timestamp of when the access token currently in use was fetched and stored. Whenever our app needs to send a request to the Spotify API with an access token we'll use the access token we stored in local storage.
[06:05 - 06:23] In the case the token has expired we'll refresh it in the background using our refresh token from local storage. Alright so first let's update the callback wrap handler in our express app to also include the expires in value and the query params of the redirect URL so we can work with it in our react app.
[06:24 - 06:53] So all we have to do up here is add expires in, get rid of this console log and add it to our query.stringify function. And while we're in here we can also come down to our else block and update this case to redirect with an error query param in case the response doesn't come back with a 200 status.
[06:54 - 07:05] Next we're going to update our get access token function in the Spotify.js file . We'll start by declaring some constants at the top.
[07:06 - 07:20] So the local storage keys map is an easy way for us to refer to the keys we're going to use for each key value pair in local storage. Similarly the local storage values map is an easy way for us to refer to the values currently set in local storage.
[07:21 - 07:38] We do that by using the window.localstorage.getItem method. Next we can update the get access token function to store tokens in local storage the first time a user logs in as well as pull the tokens from local storage the next time they're available.
[07:39 - 07:52] Alright so this code snippet will be available in the manuscript below but let 's walk through it a little bit. So the first thing at the top of this function is all of our query param logic.
[07:53 - 08:26] So we're just grabbing the query params off of our URL window.location.search and we're using our local storage keys as a way to accurately grab those tokens from local storage. And here we are checking if there is an error in the query params of our URL which if you look back at our callback, right handler in our express app we pass an error query param if there's something wrong.
[08:27 - 08:36] And if that error query param is present or the token has expired we will add this function above. So hang tight.
[08:37 - 08:57] So if there's an error or it's an expired or there is an access token in our local storage but it's undefined we will refresh the token and this is another functional add above. Otherwise if there is a valid access token in local storage we're just going to use that.
[08:58 - 09:23] Otherwise if we get all the way down here if there is no access token in local storage and there is a token in the URL query params this means that the user is logging in for the very first time. So we add the query param values to local storage along with the timestamp and use that token from the query params we return it.
[09:24 - 09:44] In any case none of these cases are met then we will just return false. Look that local storage stores everything as strings so we need to make sure we 're explicitly checking for policy values which is why we do all of these undefined checks in our conditionals.
[09:45 - 10:01] So the next thing we can do is add this has token expired function to our spot ify.js file. So above get access token here I'll just add this has token expired function.
[10:02 - 10:23] So this function is just a little utility function that uses the timestamp stored in local storage to check if the amount of time elapsed since the timestamp is greater than the access tokens expire time which is 3600 seconds or one hour. If it is then we can assume that the token has expired and we need to fetch a new one.
[10:24 - 10:47] The other function that we added down here in our get access token function is refresh token so let's add that above as well. This function is a little more complicated than the other functions we have written so far because it's asynchronous due to the call to the refresh token endpoint in our express app.
[10:48 - 11:04] And here let's make sure to import Axios at the top of our file. So in this function first we check to make sure that we have a refresh token we can use.
[11:05 - 11:22] If we don't we're out of luck and the only thing we can do is log the user out. Since our app will be unusable otherwise we can await the JSON response from our refresh token endpoint and then use that response data to update our local storage values.
[11:23 - 11:36] Then once we've retrieved a new token and updated all of our values in local storage we can reload the page so our updates can be reflected. All of this logic is wrapped in a try catch so we can gracefully handle errors as they occur.
[11:37 - 11:52] Now the last function we need to add in here to round out our get access token function and all of its helper functions is log out. So up above let's add that function.
[11:53 - 12:10] All this function does is loop through all of the local storage items that we 've set and removes them. Then it reloads the page to make sure our UI is updated and it goes back to the state with the login button by just setting the window location to the window location.org.
[12:11 - 12:46] Cool, so let's head back to our UI and add a logout button to make sure this works. We'll add the logout function to our list of imports from the Spotify file and then down in our template in our logged in state we can add a button with an on click function that just runs logout when you click it and then we'll just say logout and to make sure React is happy we'll just add a fragment tag here.
[12:47 - 13:02] Now let's hit login to Spotify in local host 3000. We can see that we have our logged in state and our logout button and our local storage items have been stored here and if we hit logout awesome.
[13:03 - 13:08] Our local storage items have been removed and now we see the login to Spotify link.