Here is how I did it in JavaScript. Global variable like you mentioned:
var access_token = null;
My url looks something like this for example: https://...home.jsp#access_token=BQAXe5JQOV_xZmAukmw6G430lreF......rQByzZMcOIF2q2aszujN0wzV7pIxA4viMbQD6s&token_type=Bearer&expires_in=3600&state=vURQeVAoZqwYm4dC
After Spotify redirects the user to the uri you specified on the dashboard, I parse the url for the hash containing the access token like so:
var hash = window.location.hash.substring(1);
var accessString = hash.indexOf("&");
/* 13 because that bypasses 'access_token' string */
access_token = hash.substring(13, accessString);
console.log("Access Token: " + access_token);
Which the output is:
Access Token: BQAXe5JQOV_xZmAukmw6G430lreF...........rQByzZMcOIF2q2aszujN0wzV7pIxA4viMbQD6s
I save this access token in the sessionStorage just in case the user navigates away from the page and the url does not contain the access_token. I am assuming this is the implicit grant flow since you want to use pure JavaScript. Just make sure to re obtain a access token every hour since they expire.
Addendum
I can show you how to obtain the token and use it in an example.
I have a button on a .html page that once clicked calls a function called implicitGrantFlow() in a JavaScript file called
Test.js
function implicitGrantFlow() {
/* If access token has been assigned in the past and is not expired, no request required. */
if (sessionStorage.getItem("accessToken") !== null &&
sessionStorage.getItem("tokenTimeStamp") !== null &&
upTokenTime < tokenExpireSec) {
var timeLeft = (tokenExpireSec - upTokenTime);
console.log("Token still valid: " + Math.floor(timeLeft / 60) + " minutes left.");
/* Navigate to the home page. */
$(location).attr('href', "home.jsp");
} else {
console.log("Token expired or never found, getting new token.");
$.ajax({
url: auth_url,
type: 'GET',
contentType: 'application/json',
data: {
client_id: client_id,
redirect_uri: redirect_uri,
scope: scopes,
response_type: response_type_token,
state: state
}
}).done(function callback(response) {
/* Redirect user to home page */
console.log("COULD THIS BE A SUCCESS?");
$(location).attr('href', this.url);
}).fail(function (error) {
/* Since we cannot modify the server, we will always fail. */
console.log("ERROR HAPPENED: " + error.status);
console.log(this.url);
$(location).attr('href', this.url);
});
}
What I am doing is checking if the access_token info I stored in the sessionStorage is null. I used time since Epoch to generate when the token was created and when it ideally should expire. If these parameters are satisfied then I do not make another call.
Else, I make a call to get an access token, which on success will redirect me to my uri as I mentioned in my previous write up (you'll see I have the redirect in the .fail section. This is due to me not having permission on my school server to setup settings to bypass the CORS related issues preventing my call from being successful even though the redirect url I create is fine.).
Then when my whitelist uri gets loaded (which redirects to my home page) I utilize my <body>
tag.
home.jsp
<body onload="getAccessToken()">
Here in my tag I have it call this function once the page loads. This calls the function getAccessTokens().
/**
* The bread and butter to calling the API. This function will be called once the
* user is redirected to the home page on success and without rejecting the terms
* we are demanding. Once through, this function parses the url for the access token
* and then stores it to be used later or when navigating away from the home page.
*/
function getAccessToken() {
access_token = sessionStorage.getItem("accessToken");
if (access_token === null) {
if (window.location.hash) {
console.log('Getting Access Token');
var hash = window.location.hash.substring(1);
var accessString = hash.indexOf("&");
/* 13 because that bypasses 'access_token' string */
access_token = hash.substring(13, accessString);
console.log("Access Token: " + access_token);
/* If first visit or regaining token, store it in session. */
if (typeof(Storage) !== "undefined") {
/* Store the access token */
sessionStorage.setItem("accessToken", access_token); // store token.
/* To see if we need a new token later. */
sessionStorage.setItem("tokenTimeStamp", secondsSinceEpoch);
/* Token expire time */
sessionStorage.setItem("tokenExpireStamp", secondsSinceEpoch + 3600);
console.log("Access Token Time Stamp: "
+ sessionStorage.getItem("tokenTimeStamp")
+ " seconds\nOR: " + dateNowMS + "\nToken expires at: "
+ sessionStorage.getItem("tokenExpireStamp"));
} else {
alert("Your browser does not support web storage...\nPlease try another browser.");
}
} else {
console.log('URL has no hash; no access token');
}
} else if (upTokenTime >= tokenExpireSec) {
console.log("Getting a new acess token...Redirecting");
/* Remove session vars so we dont have to check in implicitGrantFlow */
sessionStorage.clear();
$(location).attr('href', 'index.html'); // Get another access token, redirect back.
} else {
var timeLeft = (tokenExpireSec - upTokenTime);
console.log("Token still valid: " + Math.floor(timeLeft / 60) + " minutes left.");
}
Here I am storing the token in session storage once I obtain the access token from the url. I use the process mentioned in my earlier post but here is the full JavaScript. If it is still unclear after the comments please let me know.
Now that we have our access token obtained and stored we can now make an api call. Here is how I do it (and have been using qQuery, an example of getting a user's top tracks).
Example api call
/**
* Function will get the user's top tracks depending on the limit and offset
* specified in addition to the time_range specified in JSON format.
* @param time_range short/medium/long range the specifies how long ago.
* @param offset Where the indexing of top tracks starts.
* @param limit How many tracks at a time we can fetch (50 max.)
*/
function getUserTopTracks(time_range, offset, limit) {
$.get({
url: 'https://api.spotify.com/v1/me/top/tracks',
headers: {
'Authorization': 'Bearer ' + access_token,
},
data: {
limit: limit, // This is how many tracks to show (50 max @ a time).
offset: offset, // 0 = top of list, increase to get more tracks.
time_range: time_range // short/medium/long_term time ranges.
},
success: function (response) {
/* Get the items from the response (The limit) tracks. */
res = JSON.parse(JSON.stringify(response.items));
/* Get all the track details in the json */
for (i = 0; i < res.length; i++) {
console.log("Track: " + res[i]);
}
},
fail: function () {
console.log("getUserTopTracks(): api call failed!");
}
});
The parameter time_range is specified as "long_term" to get the user's top tracks since the beginning (read more on Spotify's docs for more info) in addition to offset being 0 to start at the beginning and limit being equal to 50 since that is the max fetch per call.
On success I have my response variable 'response' and I then want the root of parsing to start from the 'items' section to make parsing easier (you do not have to do this, you can simply just use response.xxx.items.xxx). I then print to the console the response.
This is the basic things you can do and how you decide to handle the data or store it is up to you. I am not an expert, I only start learning web programming this past semester and a lot of the practices I am doing might be wrong or incorrect.