1

I am trying to do Spotify Authentication using Client(React) and Server, the logging in works for a second then the page refreshes immediately after logging in and logs the user out. Anyone knows where might be the problem?

Here is my code:

server.js:

require('dotenv').config();
const express = require('express');
const cors = require('cors');
const SpotifyWebApi = require('spotify-web-api-node');


const app = express();

app.use(cors()) // to handle the cross-origin requests
app.use(express.json()); // to parse JSON bodies

const port = process.env.PORT || 8000;

const credentials = {
  clientId: process.env.CLIENT_ID,
  clientSecret: process.env.CLIENT_SECRET,
  redirectUri: process.env.REDIRECT_URI || "http://localhost:3000"
};

app.post('/refresh', (req, res) => {
  const refreshToken = req.body.refreshToken;
  // console.log("Hii");
  let spotifyApi = new spotifyWebApi({
    clientId: process.env.CLIENT_ID,
    clientSecret: process.env.CLIENT_SECRET,
    redirectUri: process.env.REDIRECT_URI,
    refreshToken,
  });

  spotifyApi
    .refreshAccessToken()
    .then((data) => {
      // console.log(data.body);
      res.json({
          accessToken: data.body.access_token,
          expiresIn: data.body.expires_in,
      })

    })
    .catch((err) => {
      console.log(err);
      res.sendStatus(400);
    });
});


app.post('/login', (req,res) => {
  // Get the "code" value posted from the client-side and get the user data from the spotify api 
  let spotifyApi = new spotifyWebApi(credentials)
  const code = req.body.code

  spotifyApi.authorizationCodeGrant(code).then((data) => {

      // Returning the User's Data in the json formate  
      res.json({
          accessToken : data.body.access_token,
          refreshToken : data.body.refresh_token,
          expiresIn : data.body.expires_in
      }) 
  })
  .catch((err) => {
      console.log(err);
      res.sendStatus(400)
  })

})

app.listen(port, () => {
  console.log(`Example app listening at http://localhost:${port}`)
})

Client side: useAuth.js:

import React from 'react';
import { useEffect, useState } from 'react';
import axios from "axios"


export default function useAuth(code) {
    const [accessToken, setAccessToken] = useState();
    const [refreshToken, setRefreshToken] = useState();
    const [expiresIn, setExpiresIn] = useState();

    useEffect(() => {
        
        axios
            .post("/login", {code})
            .then((res) => {

                window.history.pushState({}, null, "/");

                console.log(res.data);
                setAccessToken(res.data.accessToken);
                setRefreshToken(res.data.refreshToken);
                setExpiresIn(res.data.expiresIn);
            })
            .catch(() => {
                window.location = "/";
            });

    }, [code]);

    useEffect(() => {
        if (!refreshToken || !expiresIn) {
            return;
        }

        let interval = setInterval(() => {
            axios
                .post("/refresh", {refreshToken})
                .then((res) => {
                    setAccessToken(res.data.accessToken);
                    setExpiresIn(res.data.expiresIn);
                })
                .catch(() => {
                    window.location = "/";
                });
        }, (expiresIn - 60) * 1000);

        return () => clearInterval(interval)
    }, [refreshToken, expiresIn]);

    return accessToken;
}

spotifyConfig.js:

const authEndpoint = "https://accounts.spotify.com/authorize";
const redirectUri = "http://localhost:3000";
const clientId = "ea28d4ba34f34b44b59c640052c6e098";

const scopes = [
  "streaming",
  "playlist-modify-public",
  "ugc-image-upload",
  "user-read-email",
  "user-read-private",
  "user-read-currently-playing",
  "user-read-recently-played",
  "user-read-playback-state",
  "user-modify-playback-state"
];

export const loginUrl = `${authEndpoint}?client_id=${clientId}&response_type=code&redirect_uri=${redirectUri}&scope=${scopes.join(
  "%20"
)}&show_dialog=true`;

App.js:

import './App.css';
import Dashboard from './pages/Dashboard';
import Login from './components/Login';


const code = new URLSearchParams(window.location.search).get('code')
function App() {
  
  return (
    <div>
    {code ? <Dashboard code={code}/> : <Login/>}
    
    </div>
  );
}

export default App;

this page appears a second then logs out Dashboard.js:

import React, {useEffect} from 'react';
import useAuth from '../useAuth';
import SpotifyWebApi from "spotify-web-api-node";


const spotifyApi = new SpotifyWebApi({
    clientId: "ea28d4ba34f34b44b59c640052c6e098",
});

export default function Dashboard({code}) {
    const accessToken = useAuth(code);

    useEffect(() => {
        
        if (!accessToken) return;

        spotifyApi.setAccessToken(accessToken);

        spotifyApi.getMe().then(data => {
            console.log(data);
        })
    }, []);

    return (
        <div>
            This is the home page 
        </div>
    )
}

Login.js:

import React from 'react';
import { loginUrl } from '../spotifyConfig';

export default function Login() {
    
    return (
        <div>
            <a href={loginUrl}>
                <button>LOGIN WITH SPOTIFY</button>
            </a>

            <div className="links">
                <p>
                    ⚠ When joining or creating a Queue, open Spotify to be able to queue up tracks
                </p>
            </div>
        </div>
    )
}
Rahaf
  • 23
  • 3

2 Answers2

0

I experienced a similar issue. Here are a few steps that helped me to resolve it and many of the subsequent issues I encountered.

  1. Run your IDE's debugger and set break points for your /login request. Also, check whether your environment variables are getting set as you intend (if running VSCode you can learn how to set this up here). In particular, make sure your credentials clientId: process.env.CLIENT_ID, clientSecret: process.env.CLIENT_SECRET, redirectUri: process.env.REDIRECT_URI are correct. If your environment variables are not being loaded you won't be able to create a new SpotifyWebApi instance (check out dotenv file is not loading environment variables). Another easy way to check if this is the problem is to hard code your values temporarily.

  2. Test your server /login endpoint independently before running the client to see whether the endpoint is returning 400 or another error when executing requests to Spotify.

  3. Make sure you keep your devtools console open in your browser so you can identify any failed requests you're making to the Spotify API and consider setting devtools to preserve logs in case the page refreshing is deleting them. enter image description here

  4. If you are running both your client and server from inside VSCode, try instead running them both in new shells outside of VSCode.

henry sneed
  • 356
  • 4
  • 14
0

I was having a similar issue, having followed this tutorial, and then this YouTube tutorial.

What I realised was that my App component was being rendered twice, which was causing everything to be called twice, including the login endpoint. I was able to verify this using console.log in the endpoint and seeing if the log appeared twice. As the same Spotify code was being used twice in SpotifyWebApi.authorizationCodeGrant, this was what was causing the error.

I was able to trace the issue to the React.StrictMode being enabled, which must have happened when using the create-react-app command. Verify whether the tags appear in your index.js file. For more information, check this StackOverflow answer: My React Component is rendering twice because of Strict Mode

Harrishun
  • 33
  • 7