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