HTTP Fetch Spotify API token request failure - javascript

so basically under guidance of the Spotify WebAPI doc I am trying to request an access token via Client Credentials method. Spotify API Doc. I want to use a regular HTTP fetch request, I can not use any 3rd party libraries. I am getting a 400 return status error response: {error: "unsupported_grant_type", error_description: "grant_type parameter is missing"}. However I believe my request should be formated correctly for its grant type. I have looked at tons of articles, MDN doc, and the Spotify doc and I can not figure out why this is not working. I will include the code which I have obviously taken the api keys out of but they are correct. Link to code.
import React, { Component, useState , useEffect } from 'react';
//Custom IMPORTS:
import '../PageCss/HeaderSection.css'
const Spotify = () => {
const [baseUrl, setBaseUrl] = useState("https://accounts.spotify.com/api/token");
const [token, setToken] = useState([]);
const [currentStatus, setStatus] = useState(false);
const client_id = '';
const client_secret = '';
const data = { grant_type: 'client_credentials' };
useEffect(() => {
fetch(baseUrl,
{
method: 'POST',
headers: {
"Content-Type": "application/x-www-form-urlencoded",
'Authorization': 'Basic ' + (client_id + ':' + client_secret).toString('base64')
},
redirect: 'follow',
body: JSON.stringify(data),
})
.then((response) => {
if (!response.ok) {
return Promise.reject(new Error("Response Error!"));
}
else {
return response.json();
}
})
.catch((err) => {
console.log(err);
})
.then((json) => {
try {
setToken(json.results);
setStatus(true);
console.log("TOKEN:" + token)
}
catch
{
return Promise.reject(new Error(`State Error!: Data: ${token} , Connection:${currentStatus}`));
}
})
.catch((err) => {
console.log(err);
})
}, [baseUrl]);
return (
<div >
</div>
)
};
export default Spotify;
My application is a react app, hosted on GitHub. It's a fully functioning site and everything else is working fine. My other API fetch calls are working fine so I know this one must have an issue in it. The only line of code giving me an error is this 400 status from the fetch request.

Hey so I actually got the inital token request to work with this code:
fetch(baseUrl,
{
method: 'POST',
body: 'grant_type=client_credentials&client_id=' + client_id + '&client_secret=' + client_secret,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
Inspired by the OAuth doc and some more researching. It works now and I have a token from Spotify.

Related

How to use POST api token to use third party APIs in nextjs

I need to POST to a third party api route to receive an access token to be authorized to fetch data from their endpoints, but I'm not sure how to use the token. They are using Swagger:
export default async function() {
const res = await fetch('url', {
method:'POST',
headers: {
accept: 'application/json'
}
});
const data = await res.json()
console.log(data)
}
I get in response:
{
access_token: 'my token...',
...
}
But I'm not sure how I'd use this response to authorize fetching data. Do I need to pass the token to the headers in the fetch?
export async function getStaticProps() {
const res = await fetch( `url`, {
headers: {
accept: 'application/json',
}
});
const data = await JSON.stringify(res);
return {
props: {
items: data
},
};
}
I can't seem to find much info on this, or I'm just searching for the wrong things. I'm not sure if I'm understanding this correctly
Likely you'll need to send that token in an Authorization header with the request, something like this:
const res = await fetch(`url`, {
headers: {
accept: 'application/json',
Authorization: `Bearer ${token}`,
}
});
const json = await res.json()
const data = JSON.stringify(json);
The API docs should be able to tell you specifics though, if you're still having issues please post the API docs if they're public!

Spotify Web API returns 404 with valid show id

I'm trying out the WebAPI and have run into a snag that doesn't make sense.
In the developer console a search for the episode list for show id 4rOoJ6Egrf8K2IrywzwOMk returns a list.
Even accessing the given URL (https://api.spotify.com/v1/shows/4rOoJ6Egrf8K2IrywzwOMk/episodes) in the browser returns the episode list, if I'm logged into my spotify account.
I'm not sure what's broken in my code.
async function listPodcastEpisodes(id) {
const access_token = await getAuth()
const api_url = `https://api.spotify.com/v1/shows/${id}/episodes`
console.log(api_url)
try {
const response = await axios.get(api_url, setAxiosOptions(access_token))
return response.data
} catch(err) {
console.log(`Error: ${JSON.stringify(err?.response?.data, null, 2)}`)
}
}
listPodcastEpisodes(process.argv[2])
.then(x => console.log(x))
This code returns:
$ node getInfo.js 4rOoJ6Egrf8K2IrywzwOMk
https://api.spotify.com/v1/shows/4rOoJ6Egrf8K2IrywzwOMk/episodes
Error: {
"error": {
"status": 404,
"message": "non existing id"
}
}
undefined
The other functions and variable settings:
const auth = `${process.env.ID}:${process.env.SECRET}`
const auth_encoded = Buffer.from(auth, 'utf-8').toString("base64")
function setAxiosOptions(data) {
return {
headers: {
'Authorization': `Bearer ${data}`,
'Content-Type': 'application/json'
}
}
}
async function getAuth () {
try {
const token_url = 'https://accounts.spotify.com/api/token';
const data = qs.stringify({'grant_type':'client_credentials'});
const response = await axios.post(token_url, data, {
headers: {
'Authorization': `Basic ${auth_encoded}`,
'Content-Type': 'application/x-www-form-urlencoded'
}
})
return response.data.access_token;
} catch(error) {
console.log(error);
}
}
It looks like you may need to include the market parameter.
I found this GitHub issue on the official Web API repo describing the same problem you're experiencing. This issue is referenced by this issue, where GitHub user MrXyfir posts their workaround:
Edit: For anyone else who ends up with this issue, the solution for me was to set the market param. https://api.spotify.com/v1/shows/4rOoJ6Egrf8K2IrywzwOMk/episodes?market=US

Typescript removes Authorization header from POST and PATCH fetch requests

I've built an API using C# that uses JWT tokens for authorization. On the frontend I store these tokens in local storage and get them, when creating a request. When creating GET or DELETE requests, everything works fine, and using console.log() I can see that fetch options have the Authorization header added. However when using POST or PATCH methods, the Authorization header is missing immediatly after adding it to the object. Here is my request method:
const send = async (apiOptions: ApiParams): Promise<FetchReturn> => {
const accessToken = GetAccessToken()
const options: ApiOptions = {
method: apiOptions.method,
headers: {
Authorization: `Bearer ${accessToken}`
}
}
console.log(options)
if (apiOptions.data) {
options.headers = {
'Content-Type': 'application/json'
}
options.body = JSON.stringify(apiOptions.data)
}
const result = await fetch(`${getUrl()}/${apiOptions.path}`, options).then(res => res).catch(err => err)
if (!result.ok) {
if (IsExpired()) {
const refreshResult = await fetch(`${getUrl()}/api/user/refresh`, {method: 'POST', headers:{
'Content-Type': 'application/json'
}, body: JSON.stringify(GetRefreshRequest())}).then(res => res).catch(err => err)
if (refreshResult.ok) {
Login(JSON.parse(await refreshResult.text()))
return await send(apiOptions)
} else if (refreshResult.status === 401) {
Logout()
window.location.reload()
return { code: 0, text: ""}
}
}
}
const text = await result.text()
return { code: result.status, text: text }
}
I suppose that in apiParams for POST you have property 'data' assigned, and later you have if-condition that completely replaces request headers object.
Change it to:
options.headers['Content-Type'] = 'application/json';
To keep authorization in headers
The first time check your apiOptions.data
i think , its null when you call POST/Patch request
Just put console.log("...") In the if statement , Then try for resolve your Error
If your problem not resolved, put a replay under my post

Receving "500 Internal Server Error" on Post Request to Firebase-Cloud-Function Endpoint

I'm trying to make a POST request using axios to my firebase cloud-function on form submit in react app. But I get '500' error everytime I make a request with an html-page response This app works best with javascriot enabled.
Latest Update:
It looks like there is no issue with cloud function
code. Rather more of a react-component issue. I used Postman to send
the POST request with header prop Content-Type set to application/json
and sending body in raw format {"email": "example_email"} and got
expected response from the cloud function. But when sent the request from
react component above, I get an html file response saying the app
works best with javascript enabled
I've tried setting Content-Type to both Application/json and multipart/form-data as I suspected it to be an issue but still got no luck.
Following is my code for cloud function and react submit form:
Cloud Function
const functions = require('firebase-functions');
const cors = require('cors')({ origin: true })
const runThisFunc1 = require(./libs/runThisFunc1);
const runThisFunc2 = require(./libs/runThisFunc2);
exports.wizardFunc = functions.https.onRequest((request, response) => {
cors(request, response, () => {
let email = request.body.email;
try {
return runThisFunc1(email)
.then(data => {
console.log("Word Done by 1!");
return runThisFunc2(data);
})
.then(res => {
console.log("Word Done by 2!");
return response.status(200).send("Success");
})
.catch(err => {
console.error("Error: ", err.code);
return response.status(500).end();
});
}catch(err) {
return response.status(400).end();
}
});
});
React-Form-Component Snippet
import axios from 'axios'
...
handleSubmit = e => {
e.preventDefault()
const { email } = this.state
axios({
method: 'post',
url: `${process.env.REACT_APP_CLOUD_FUNCTION_ENDPOINT}`,
data: { email: email },
config: {
headers: {
'Content-Type': 'multipart/form-data'
}
}
})
.then(res => {
//do something with reponse here
})
.catch(error => {
console.error(error)
})
}
...
Is there something wrong I am doing in the code or the request config is wrong?

axios header Authorization using vue.js

I am trying to use a header token with axios. However I am presented with a CORS error as I am clearly not passing over the token correctly (moving to a not authorized feed works)
Here is my http-common.js file
const token = `08E1B4C220E671AC6A48`
// my user app token from micro.blog 08E1B4C220E671AC6A48
export const HTTP = axios.create({
// baseURL: 'https://micro.blog/feeds/adamprocter.json'
baseURL: 'https://micro.blog',
headers: {
Authorization: `Bearer ${token}`
}
})
and here is my Timeline.vue component
import { HTTP } from '#/http-common'
export default {
components: {
MicroPosts
},
data() {
return {
posts: []
}
},
created() {
// no auth get = HTTP.get('')
HTTP.get('/account/verify')
.then(response => {
//console.log(response.data)
this.posts = response.data.items
})
.catch(error => {
console.log('caught error' + error.response)
})
}
}
The URL is correct but the token is failing (I believe)
POST /account/verify — Accepts an app token (which I have set up) and returns an auth token and other details.
This is the API documentation which is a little sparse but
http://help.micro.blog/2017/api-json/
http://help.micro.blog/2018/api-authentication/
I am sure it is something obvious, any help much appreciated.
The documentation says /account/verify accepts POST. You are sending a GET.

Categories

Resources