-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
126 lines (106 loc) · 4.07 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
const express = require('express');
const path = require('path');
const app = express();
const axios = require('axios');
const querystring = require('query-string'); //Built in node module to parse and stringify query strings
const { error } = require('console');
require('dotenv').config();
const CLIENT_ID = process.env.CLIENT_ID;
const CLIENT_SECRET = process.env.CLIENT_SECRET;
const REDIRECT_URI = process.env.REDIRECT_URI;
const FRONTEND_URI = process.env.FRONTEND_URI;
const PORT = process.env.PORT || 8888;
const stateKey = 'spotify_auth_state';
// Priority serve any static files.
app.use(express.static(path.resolve(__dirname, './client/build')));
/**
* Generates a random string containing numbers and letters
* @param {number} length The length of the string
* @return {string} The generated string
*/
// This func is to protect against cross-site request forgery
const generateRandomString = length => {
let text = '';
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (let i = 0; i < length; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
};
/* ROUTES */
//Request auth to access data from spotify
app.get('/login', (req,res) => {
const state = generateRandomString(16);
res.cookie(stateKey, state);
const scope = ['user-read-private', 'user-read-email', 'user-top-read',].join(' '); //list of spotify's pre-defined auth scopes.
const queryParams = querystring.stringify({
client_id: CLIENT_ID,
response_type: 'code',
redirect_uri: REDIRECT_URI,
state,
scope,
});
res.redirect(`https://accounts.spotify.com/authorize?${queryParams}`);
});
//use Auth code to request access token, spotify confirms validity of auth code, then responds with access token and refresh token
app.get('/callback', (req,res) => {
const code = req.query.code || null; //store the value of our authorization code which we got from the code query param in the code variable.
axios({
method: 'post',
url: 'https://accounts.spotify.com/api/token',
data: querystring.stringify({
grant_type: 'authorization_code',
code,
redirect_uri: REDIRECT_URI,
}),
headers:{
'content-type': 'application/x-www-form-urlencoded',
Authorization: `Basic ${new Buffer.from(`${CLIENT_ID}:${CLIENT_SECRET}`).toString('base64')}`,
},
})
.then(response => { //spotify web api confirms validity of access token, then responds with the requested data
if(response.status === 200){
const {access_token, refresh_token, expires_in} = response.data;
const queryParams = querystring.stringify({
access_token,
refresh_token,
expires_in,
});
res.redirect(`${FRONTEND_URI}/?${queryParams}`);
} else {
res.redirect(`/?${querystring.stringify({error: 'invalid_token'})}`);
}
})
.catch(error => {
res.send(error);
});
});
/* Route handler to handle requesting a new access token with our refresh token behind the scenes */
app.get('/refresh_token', (req,res) => {
const {refresh_token} = req.query;
axios({
method: 'post',
url: 'https://accounts.spotify.com/api/token',
data: querystring.stringify({
grant_type: 'refresh_token',
refresh_token: refresh_token
}),
headers: {
'content-type': 'application/x-www-form-urlencoded',
Authorization: `Basic ${new Buffer.from(`${CLIENT_ID}:${CLIENT_SECRET}`).toString('base64')}`,
},
})
.then(response => {
res.send(response.data);
})
.catch(error => {
res.send(error);
});
});
// All remaining requests return the React app, so it can handle routing.
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, './client/build', 'index.html'));
});
app.listen(PORT, () => {
console.log(`Express app listening at http://localhost:${PORT}`);
});