I have a react JS login page that accepts the user name and password. Upon entering the user name and and password, the credentials are processed against a json (API) file, which generates a token for the client. My goal is to pass the token to a landing page after the client has logged in and populate a dropdown list with the clients respective data. The problem I am facing is getting the clients token to pass from my login page to the landing page.
In my login page, I am using Fetch to retrieve the token from the API and then store the token using session-storage. The code snippet for getting the token:
componentDidMount() {
this.fetchData();
}
//request the token
fetchData() {
return fetch('http://myapiaut:1111/api/auth', {
method: 'POST',
headers: {
'Content-type': 'application/json',
},
body: JSON.stringify({
username: 'myAdminusername',
password: 'myAdminPassword',
Authorization: 'myAdminPassword',
})
}) /*end fetch */
.then(results => results.json())
.then(data => {
this.setState({ data: data })
sessionStorage.setItem("token", data)
})
}
//authenticate request
requestUserInfo() {
var token = sessionStorage.getItem("token");
return fetch('http://myapiaut:1111/api/auth', {
method: 'GET',
headers: new Headers({
Authorization: 'Bearer' + sessionStorage.token
}),
})
.then((response) => response.json());
}
Landing page
componentDidMount() {
fetch('http://myapiclients:22222/api/clients', {
method: 'GET',
headers: {
'Content-type': 'application/json',
'Authorization': 'Bearer ' + sessionStorage.token
},
})
.then(results => results.json())
.then(data => this.setState({ data: data }))
}
...going back to the login page, I confirmed that I'm getting the token via fetchData function, but the problem I am encountering is properly storing the token so that it may be passed to the landing page.
FYI- I've already built the landing page and it functions properly when I manually copy the generated token into the Authorization section of the Fetch.
...Could, I please get some help as to what I'm doing wrong?
The problem is here:
.then(data => this.setState({ data: data }))
.then(data => sessionStorage.setItem('token', data))
setState doesn't resolve a Promise so it does not have then()
Change it to something like:
.then(data => {
this.setState({ data: data })
sessionStorage.setItem('token', data)
})
In landing page:
componentDidMount() {
fetch('http://myapiclients/api/clients', {
method: 'GET',
headers: {
'Content-type': 'application/json',
'Authorization': 'Bearer ${token}' // token is not defined!
},
})
.then(results => results.json())
.then(data => this.setState({ data: data }))
}
token is not defined, so it will be 'Bearer undefined', either define it before fetch(...) with sessionStorage.getItem("token") or in fetch headers do something like:
'Authorization': 'Bearer ' + sessionStorage.token
Related
I create a login form using Nextjs and backend with Laravel 8, I generate an XSRF-TOKEN in Laravel then set it on cookie, I can see the token inside inspect element> application tab> cookie section, but I can't set it on my fetch request to make my login, I using redux to store my data such: products, auth, cart and etc
AuthAction.js code:
export const LOGIN_AUTH = "LOGIN_AUTH";
export const LOGOUT_AUTH = "LOGOUT_AUTH";
export const HandleLogin = (data) => {
return async (dispatch, getState) => {
const getCsrf = await fetch("http://localhost:8000/sanctum/csrf-cookie");
if (!getCsrf.ok) {
throw new Error("Faild to set csrf token");
}
console.log("getCsrf", cookie.load("XSRF-TOKEN"));
const response = await fetch("http://localhost:8000/api/app/user/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
});
if (!response.ok) {
throw Error("Login faild");
}
try {
const responseData = await response.json();
console.log("login", responseData);
dispatch({
type: LOGIN_AUTH,
user: responseData,
});
} catch (err) {
console.log("Login err", err);
throw err;
}
};
};
after console.log("getCsrf", cookie.load("XSRF-TOKEN")); nothing happened.
what do I do wrong in my code?
cookie screenshot:
request response:
Use axios instead of fetch.
Example:
axios
.get("http://localhost:8000/sanctum/csrf-cookie", {
withCredentials: true,
})
.then((response) => {
axios("http://localhost:8000/api/app/user/login", {
method: "post",
data: data,
withCredentials: true,
})
.then((response) => {
console.log("login", response.data);
})
.catch((error) => {
console.log(error);
});
})
.catch((error) => {
// handle error
console.log(error);
})
.then(() => {
//
});
Since your next.js and laravel apps are on different origins, you need to set fetch to explicitly send cookies.
const response = await fetch("http://localhost:8000/api/app/user/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
credentials: 'include'
});
You can read more about the credentials property in the MDN docs
Also, you can read the cookie in the front-end if it's http-only cookie.
Also, don't forget to set up Cross origin resource sharing in your backend app.
I'm pretty new to working with API's, and I'm currently trying to fetch some data from the Spotify API in a Next.js website.
The problem is that the only end-point that gives me any data is the 'top-tracks': (https://api.spotify.com/v1/me/top/tracks), all the other end-points I've tried gives this error:
Request failed FetchError: invalid json response body at https://api.spotify.com/v1/me/player/recently-played reason: Unexpected token U in JSON at position 0
This is the function I'm using to fetch data from the API:
const basic = Buffer.from(`${client_id}:${client_secret}`).toString("base64");
const TOKEN_ENDPOINT = `https://accounts.spotify.com/api/token`;
export default async function handler(req, res) {
const response = await fetch(TOKEN_ENDPOINT, {
method: "POST",
headers: {
Authorization: `Basic ${basic}`,
"Content-Type": "application/x-www-form-urlencoded",
},
body: querystring.stringify({
grant_type: "refresh_token",
refresh_token,
}),
})
.then((response) => response.json())
.then((data) => {
const access_token = data.access_token;
return fetch(`https://api.spotify.com/v1/me/player/recently-played`, {
method: "GET",
headers: {
Authorization: `Bearer ${access_token}`,
},
});
})
.then((response) => response.json())
.catch((err) => {
console.error("Request failed", err);
});
return res.status(200).json(response);
}
(First getting the access token, using clientId and secret from env-variables, then fetching data from API using said token)
Any idea of what I'm doing wrong here? All help is greatly appreciated :)
Also:
I've added the necessary scopes, so I should have permisssion to get the data!
Send email and password to axios as a post request
The server responds with a bearer token in the header.
We are implementing the login function by storing the token in local storage.
However, there are times when you run the code, and there are times when it doesn't.
When it does not run, the page is refreshed when the button is clicked, and the console window of the Chrome developer tool is also opened.
As a result of checking with the console log, the function is executed, but it seems that refreshing occurs when a request is made to axios.
Can I see what's wrong?
https://codesandbox.io/s/cranky-sun-l36oz
const login = () => {
setLoading(true);
axios({
url: 'api url',
method: 'POST',
data: {
email: email,
password: password,
},
headers: {
'Content-Type': 'application/json',
},
})
.then((response) => {
token = response.headers.authorization;
console.log(token);
localStorage.setItem('authorization', token);
alert('success');
setLoading(false);
})
.catch((error) => {
console.log(error.status);
});
};
Based on what I understand from your post, you want to prevent the page from refreshing when you send Axios request. (Luckily, I can understand your Google-translated English a little more because I am from South Korea.)
You can use event.preventDefault() in the login handler to stop the page from refreshing. I test the code below in your code sandbox and the page is not refreshed anymore.
const login = (e) => {
e.preventDefault()
setLoading(true);
axios({
url: 'api url',
method: 'POST',
data: {
email: email,
password: password,
},
headers: {
'Content-Type': 'application/json',
},
})
.then((response) => {
token = response.headers.authorization;
console.log(token);
localStorage.setItem('authorization', token);
alert('success');
setLoading(false);
})
.catch((error) => {
console.log(error.status);
});
};
I'm familiar with posting data with Axios, but trying to use fetch instead. How would I convert to a fetch request, I think what I'm doing is correct...
const data = new FormData();
The following axios request works:
data.append( 'Image', this.state.image, this.state.image.name );
axios.post( '/api/upload', data, {
headers: {
'accept': 'application/json',
'Accept-Language': 'en-US,en;q=0.8',
'Content-Type': 'multipart/form-data;',
}
})
.then ...
I tried to convert here;
data.append( 'Image', this.state.image, this.state.image.name );
fetch( '/api/upload', data, {
method: 'POST',
headers: {
'accept': 'application/json',
'Accept-Language': 'en-US,en;q=0.8',
'Content-Type': 'multipart/form-data;',
},
body: JSON.stringify(data)
})
.then ...
Returns 404 error, not found.
What am I failing to do here?
2021 answer: just in case you land here looking for how to make GET and POST Fetch api requests using async/await or promises as compared to axios.
I'm using jsonplaceholder fake API to demonstrate:
Fetch api GET request using async/await:
const asyncGetCall = async () => {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'GET',
headers: {
'Content-Type': 'application/json'
},
});
const data = await response.json();
// enter you logic when the fetch is successful
//example: show success modal, clear form, route to another page etc.
console.log(data);
} catch(error) {
// enter your logic for when there is an error,
// example: open a modal with error message.
console.log(error)
}
}
asyncGetCall()
Fetch api POST request using async/await:
const asyncPostCall = async () => {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
// your expected POST request payload goes here
title: "My post title",
body: "My post content."
})
});
const data = await response.json();
// enter you logic when the fetch is successful
//example: show success modal, clear form, route to another page etc.
console.log(data);
} catch(error) {
// enter your logic for when there is an error,
// example: open a modal with error message.
console.log(error)
}
}
asyncPostCall()
GET request using Promises:
fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
})
.then(res => res.json())
.then(data => {
// enter you logic when the fetch is successful
//example: show success modal, clear form, route to another page etc.
console.log(data)
})
.catch(error => {
// enter your logic for when there is an error,
// example: open a modal with error message.
console.log(error)
})
POST request using Promises:
fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
// your expected POST request payload goes here
title: "My post title",
body: "My post content."
})
})
.then(res => res.json())
.then(data => {
// enter you logic when the fetch is successful
//example: show success modal, clear form, route to another page etc.
console.log(data)
})
.catch(error => {
// enter your logic for when there is an error,
// example: open a modal with error message.
console.log(error)
})
GET request using Axios:
const axiosGetCall = async () => {
try {
const { data } = await axios.get('https://jsonplaceholder.typicode.com/posts')
// enter you logic when the fetch is successful
// example: show success modal, clear form, route to another page etc.
console.log(`data: `, data)
} catch (error) {
// enter your logic for when there is an error,
// example: open a modal with error message.
console.log(`error: `, error)
}
}
axiosGetCall()
POST request using Axios:
const axiosPostCall = async () => {
try {
const { data } = await axios.post('https://jsonplaceholder.typicode.com/posts', {
// your expected POST request payload goes here
title: "My post title",
body: "My post content."
})
// enter you logic when the fetch is successful
// example: show success modal, clear form, route to another page etc.
console.log(`data: `, data)
} catch (error) {
// enter your logic for when there is an error,
// example: open a modal with error message.
console.log(`error: `, error)
}
}
axiosPostCall()
fetch only takes two arguments.
fetch('/api/upload', {
method: 'post',
body: JSON.stringify(data),
headers: {
'accept': 'application/json',
'Accept-Language': 'en-US,en;q=0.8',
'Content-Type': 'multipart/form-data;',
},
})
.then(res => res.json())
.then(json => console.log(json));
$ajax server response:
{"username":"","password":""}
fetch server response:
{"{\"username\":\"\",\"password\":\"\"}":""}
Why aren't they the same? I need the same server response. I'm using PHP+Apache
Here is my code:
import $ from 'jquery';
export function FetchData(type, data){
const serverUrl = 'http://localhost/oms/'+ type + ".php";
return new Promise((resolve, reject) => {
$.ajax({
type: 'POST',
url: serverUrl,
data //body : {username: "username", password:"password"}
})
.done(function(res) {
//console.log(res);
resolve (res);
})
.fail(function(jqXHR, exception){
//alert('server error()');
reject(jqXHR);
});
fetch(serverUrl,{
method: 'POST',
headers: {
Accept: '*/*',
'Content-Type': 'application/x-www-form-urlencoded',
//'Access-Control-Allow-Origin': '*',
//'Access-Control-Allow-Methods': 'POST,GET,OPTIONS,PUT,DELETE',
//'Access-Control-Allow-Headers': 'Content-Type,Accept',
},
body: JSON.stringify(data)
//body : {username: data.username, password: data.password}
})
.then((response) => response.json())
.then((responseJson) => {
resolve(responseJson);
})
.catch((error) => {
reject(error);
});
});
}
The responses are essentially the same just that response from fetch library returns a Stringified JSON.
You need to convert it into actual JS object.
const responseData = JSON.parse(response.json())
This occurs because you're sending the content type application/x-www-form-urlencoded with JSON data you need to change it to application/json like
export const FetchData = (type, data) => {
let serverUrl = 'http://localhost/oms/'+ type + ".php";
let data = {
username: data.username,
password: data.password
};
return new Promise((resolve, reject) => {
fetch(serverUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
credentials: 'include',
body: JSON.stringify(data),
})
.then((response) => response.json())
.then((responseJson) => {
resolve(responseJson)
})
.catch((error) => {
reject(error)
})
})
};
I added credentials it's read-only property of the Request interface indicates whether the user agent should send cookies from the other domain in the case of cross-origin requests. This is similar to XHR’s withCredentials flag
If you want to use something smaller to jQuery you can use Axios It's XMLHttpRequests
If you get some CORS issues this will help you