Reputation: 37
I'm making some music website portfolio with Spotify, NextJS and I want to make play music in this website, and need Spotify authenication for use it. when I click Login-button and got 405 HTTP status. I checked on postman and got same error. I searched and it might be error on GET/POST issues but I can't handle where to fix it.
app/api/login code part
export async function LoginHandler (req: NextApiRequest, res: NextApiResponse) {
const state = generateRandomString(16);
const CLIENT_ID = process.env.NEXT_PUBLIC_SPOTIFY_CLIENT_ID;
const scope =
"user-read-private user-read-email user-read-playback-state user-modify-playback-state streaming";
res.redirect(
"https://accounts.spotify.com/authorize?"+
qs.stringify({
response_type: "code",
client_id: CLIENT_ID,
scope: scope,
redirect_uri: `${REDIRECT_URL}/api/callback`,
state: state,
})
);
I use useRouter(next/navigation) to route it.
<button
onClick={() => {
router.push("/api/login");
}}
>
and this one is get token code
export const getAccessTokenData = () => {
return axios<AccessTokenData>({
method: "POST",
url: SPOTIFY_ACCESS_TOKEN_URL,
headers: {
"Content-Type": "application/x-www-form-urlencoded",
Authorization:
"Basic " +
Buffer.from(`${CLIENT_ID}:${CLIENT_SECRET}`).toString("base64"),
},
data: {
grant_type: "client_credentials",
},
});
};
export const getAuthorizationTokenData = (code: string) => {
return axios<AuthorizationTokenData>({
method: 'post',
url: 'https://accounts.spotify.com/api/token',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Authorization:
'Basic ' +
Buffer.from(
`${CLIENT_ID}:${CLIENT_SECRET}`
).toString('base64'),
},
data: {
code: code,
redirect_uri: REDIRECT_URL + '/api/callback',
grant_type: 'authorization_code',
},
});
}
Upvotes: 1
Views: 229
Reputation: 9380
405 error means invalid Authentication or wrong format send parameter. Your getAuthorizationTokenData()'s data was Incorrect Request Format.
To send data in application/x-www-form-urlencoded format of axios POST call, you should use the URLSearchParams
class to construct the request body.
You need to understand Spotify "Authorization Code Flow" More detail in here
Demo code implemented Spotify login and get access token by Authorization Code Flow
and get specific playlist and shows songs. Using next.js.
I added three files from create next.js project (index.tsx, callbacl.tsx and constant.ts)
npx create-next-app@latest my-spotify-app --typescript
You need to remove ./src/app/pages.tsx
file.
Save index.tsx
// pages/index.tsx
import { GetServerSideProps } from 'next';
import { clientId, scope, redirectUri } from './constants';
const Home = ({ spotifyAuthUrl }: { spotifyAuthUrl: string }) => {
return (
<div>
<h1>Spotify Login</h1>
<a href={spotifyAuthUrl}>Login with Spotify</a>
</div>
);
};
export const getServerSideProps: GetServerSideProps = async () => {
const encodeRedirectUri = encodeURIComponent(redirectUri);
const spotifyAuthUrl = `https://accounts.spotify.com/authorize?response_type=code&client_id=${clientId}&redirect_uri=${encodeRedirectUri}&scope=${scope}`;
return { props: { spotifyAuthUrl } };
};
export default Home;
Save callback.tsx
// pages/callback.tsx
import { GetServerSideProps } from 'next';
import axios from 'axios';
import { clientId, clientSecret, redirectUri, myPlaylistId } from './constants';
interface Track {
track: {
name: string;
id: string;
};
}
const Callback = ({ accessToken, playlistTracks }: { accessToken: string, playlistTracks: Track[] }) => {
return (
<div>
<h1>Spotify Playlist Tracks</h1>
<p>Access Token: {accessToken}</p>
<ul>
{playlistTracks.map((track, index) => (
<li key={index}>
{track.track.name}
<br />
<iframe
src={`https://open.spotify.com/embed/track/${track.track.id}`}
width="300"
height="80"
allow="encrypted-media"
></iframe>
</li>
))}
</ul>
</div>
);
};
export const getServerSideProps: GetServerSideProps = async ({ query }) => {
const code = query.code as string;
if (!code) {
return {
redirect: {
destination: '/',
permanent: false,
},
};
}
try {
const response = await axios.post(
'https://accounts.spotify.com/api/token',
new URLSearchParams({
grant_type: 'authorization_code',
code,
redirect_uri: redirectUri,
client_id: clientId,
client_secret: clientSecret,
}).toString(),
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
}
);
const accessToken = response.data.access_token;
const playlistResponse = await axios.get(
`https://api.spotify.com/v1/playlists/${myPlaylistId}/tracks`,
{
headers: {
Authorization: `Bearer ${accessToken}`,
},
}
);
const playlistTracks: Track[] = playlistResponse.data.items;
return { props: { accessToken, playlistTracks } };
} catch (error) {
console.error('Error:', error);
return { props: { accessToken: '', playlistTracks: [] } };
}
};
export default Callback;
Save constans.ts
// constants.ts
export const clientId = '[your client id]';
export const clientSecret = '[your client secret]';
export const redirectUri = 'http://localhost:3000/callback'; // replace your redirect URI
export const myPlaylistId = '[your playlist id]';
export const scope = 'playlist-read-private user-read-private user-read-email user-read-playback-state user-modify-playback-state streaming'; // Add more scopes if needed
npm insatall axios
npm run dev
http:/localhost:3000
Upvotes: 1