New Jan 5, 2025

Spotify OAuth with React not working properly

Libraries, Frameworks, etc. All from Newest questions tagged reactjs - Stack Overflow View Spotify OAuth with React not working properly on stackoverflow.com

I am new to React in general and am trying to build a simple application. I want to build an application where users can sign in using their Spotify Account. I have the following files:

App.js:

import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom';
import './App.css';
import OAuthSignInPage from './components/oauth';
import Callback from './components/callback';
import Welcome from './components/Welcome';
import Options from './components/Options';
import Header from './components/Header';
import { AuthProvider, useAuth } from './hooks/useAuth';

const ProtectedRoute = ({ children }) => { const { user } = useAuth(); if (!user) { return <Navigate to="/" />; } return children; };

function App() { return ( <Router> <AuthProvider> <div className="App"> <Header /> <div className="content"> <Routes> <Route path="/" element={<OAuthSignInPage />} /> <Route path="/callback" element={<Callback />} /> <Route path="/welcome" element={ <ProtectedRoute> <Welcome /> </ProtectedRoute> } /> <Route path="/options" element={ <ProtectedRoute> <Options /> </ProtectedRoute> } /> </Routes> </div> </div> </AuthProvider> </Router> ); }

export default App;

oauth.js

import * as React from 'react';
import { AppProvider } from '@toolpad/core/AppProvider';
import { SignInPage } from '@toolpad/core/SignInPage';
import { useTheme } from '@mui/material/styles';
import { useAuth } from "../hooks/useAuth";
import { useNavigate } from 'react-router-dom';

const providers = [ { id: 'spotify', name: 'Spotify' } ];

const signIn = async (provider) => {

if (provider.id === 'spotify') { // Redirect to Spotify login const clientId = process.env.REACT_APP_SPOTIFY_CLIENT_ID; const redirectUri = encodeURIComponent(${window.location.origin}/callback); const scope = 'user-read-private user-read-email user-top-read'; const spotifyAuthUrl = https://accounts.spotify.com/authorize?client_id=${clientId}&amp;response_type=code&amp;redirect_uri=${redirectUri}&amp;scope=${scope};

window.location.href = spotifyAuthUrl; return new Promise(() => {}); // Promise won't resolve due to redirect }

return { error: 'Invalid provider' }; };

export default function OAuthSignInPage() { const { user } = useAuth(); const navigate = useNavigate();

React.useEffect(() => { if (user) { navigate('/options'); } }, [user, navigate]);

const theme = useTheme(); return ( <AppProvider theme={theme}> <SignInPage signIn={signIn} providers={providers} /> </AppProvider> ); }

protectedRoute.js:

import { Navigate } from "react-router-dom";
import { useAuth } from "../hooks/useAuth";

export const ProtectedRoute = ({ children }) => { const { user } = useAuth(); if (!user) { // user is not authenticated return <Navigate to="/" />; } return children; };

Callback.js

import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
import { useAuth } from '../hooks/useAuth';

function Callback() { const { login } = useAuth(); const location = useLocation();

useEffect(() => { const code = new URLSearchParams(location.search).get('code'); if (code) { login({ code }); } }, [location, login]);

// No need for loading state since login handles navigation return null; }

export default Callback;

useAuth.jsx

import { createContext, useContext, useMemo } from "react";
import { useNavigate } from "react-router-dom";
import { useLocalStorage } from "./useLocalStorage";
const AuthContext = createContext();

export const AuthProvider = ({ children }) => { const [user, setUser] = useLocalStorage("code", null); const navigate = useNavigate();

// call this function when you want to authenticate the user const login = async (data) => { setUser(data); };

// call this function to sign out logged in user const logout = () => { setUser(null); navigate("/", { replace: true }); };

const value = useMemo( () => ({ user, login, logout, }), [user] ); return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>; };

export const useAuth = () => { return useContext(AuthContext); };

Now the issue is, the OAuth part is working fine. I can login and Spotify is calling my /callback endpoint with the code. But the redirection is not working properly. After login it's going to the /options route but it is a blank component. The error is:

Cannot update a component (`AuthProvider`) while rendering a different component (`Callback`). To locate the bad setState() call inside `Callback`, follow the stack trace as described in https://react.dev/link/setstate-in-render

And this error is being called in an infinite loop.

I just can't figure out how to solve this. One more thing is when I manually type in the URL /welcome after login, it works. Help would be really appreciated.

Scroll to top