Spotify API and React

Hello. Hope y’all doing good. This going to be a little long post…

I’m building an app with spotify api using react. When trying to get the access token I get 400 error:

{“error”:“invalid_grant”,“error_description”:“Invalid authorization code”}

My headers look fine I guess…

const scope = ' user-read-private user-read-email'; const redirect_uri = "http://localhost:3000/login"; // Auth spotify account export async function spotifyAuthCodeFlow() { const verifier = generateCodeVerifier(62); const challenge = await generateCodeChallenge(verifier); localStorage.setItem("verifier", verifier); const params = new URLSearchParams({ client_id: client_id, response_type: "code", redirect_uri: redirect_uri, scope: scope, code_challenge_method: "S256", code_challenge: challenge, }); document.location = `https://accounts.spotify.com/authorize?${params.toString()}`; } // Parse the code after authO const params = new URLSearchParams(window.location.search); const code = params.get("code"); // Get access token export async function getAccessToken() { const verifier = localStorage.getItem("verifier"); // if (!verifier) {throw new Error("Verifier WRONG!")}; const params = new URLSearchParams({ client_id: client_id, grant_type: "authorization_code", code: code, redirect_uri: redirect_uri, code_verifier: verifier, }); const result = await fetch("https://accounts.spotify.com/api/token", { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded"}, body: params, }); const access_token = await result.json(); if (!access_token) { throw new Error("Access Token FALSE!")}; return access_token; } // Profile export async function fetchProfile(token) { const result = await fetch("https://api.spotify.com/v1/me", { method: "GET", headers: { Authorization: `Bearer ${token}` }, }); const profileData = await result.json(); return profileData; }

I structure the app in a way that I click the button to auth spotify account. I get redirect to the auth page and once auth is done I get redirect back to the page where display profile, just the token fetching process is not successful.
I’ve noticed that this error is random… if I keep on reloading sometimes I’ll get a 200… I’m fetching the token two times too I don’t know why, maybe something to do with the way I call it in react.

export function Login() { const [profile, setProfile] = useState(null); const [loading, setLoading] = useState(true); const getProfileData = async () => { const access_token = await getAccessToken(); if (!access_token) { throw new Error("Getting token went wrong..."); } try { const profileData = await fetchProfile(access_token); setProfile(profileData); populateUI(profile); } catch (error) { console.log("Error fetching profile", error); } finally { setLoading(false); } }; useEffect(() => { getProfileData(); }, []); if (loading) { return ( <div> <h1>Loading...</h1> </div> ) } return ( <div> <section id="profile"> <h2>Logged in as <span id="displayName"></span></h2> <img id="avatar" width="200" src="#" /> <ul> <li>User ID: <span id="id"></span></li> <li>Email: <span id="email"></span></li> <li>Spotify URI: <a id="uri" href="#"></a></li> <li>Link: <a id="url" href="#"></a></li> <li>Profile Image: <span id="imgUrl"></span></li> </ul> </section> </div> ) }

I’ve done this approach too but I still had the fetching two times

export function Login() { const [profile, setProfile] = useState(null); const [loading, setLoading] = useState(true); const getAccessToken = async () => { const verifier = localStorage.getItem("verifier"); // if (!verifier) {throw new Error("Verifier WRONG!")}; const params = new URLSearchParams({ client_id: client_id, grant_type: "authorization_code", code: code, redirect_uri: redirect_uri, code_verifier: verifier, }); const result = await fetch("https://accounts.spotify.com/api/token", { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded"}, body: params, }); const access_token = await result.json(); if (!access_token) { throw new Error("Access Token FALSE!")}; return access_token; } // Profile const fetchProfile = async (token) => { const result = await fetch("https://api.spotify.com/v1/me", { method: "GET", headers: { Authorization: `Bearer ${token}` }, }); const profileData = await result.json(); return profileData; } useEffect(() => { const token = getAccessToken(); const profile = fetchProfile(token); populateUI(profile); }, []); if (loading) { return ( <div> <h1>Loading...</h1> </div> ) } return ( <div> <section id="profile"> <h2>Logged in as <span id="displayName"></span></h2> <img id="avatar" width="200" src="#" /> <ul> <li>User ID: <span id="id"></span></li> <li>Email: <span id="email"></span></li> <li>Spotify URI: <a id="uri" href="#"></a></li> <li>Link: <a id="url" href="#"></a></li> <li>Profile Image: <span id="imgUrl"></span></li> </ul> </section> </div> ) }

Here’s screenshot