Firebase REST API auth not working with React? - reactjs

Basically a friend and I have been working on our React project and we're using Redux and Redux Thunk on the backend to handle authentication. However, we seem to have ran into an issue. Our request was working before, but now it issues a Fetch Failed Loading: POST, and doesn't continue past the initial call. However, when checking Firebase, it returns the correctly created user. I know it doesn't go past the fetch because the console.log doesn't work at all.
export const signup = (email, password) => {
return async dispatch => {
const response = await fetch('https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=[API-KEY]',
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email: email,
password: password,
returnSecureToken: true
})
}
);
console.log(response);

If async is used,
it is recommended to use try{do await something...}catch(e){} format to write.
try{
do await something
}catch(e){
error something
}
Easy to catch errors

If async is used in the fetch. Need to do this
let response = await fetch(You_URL)
let json = await response.json()
After the response object is obtained,
it needs an await to get the body content from the response
The link below has instructions
Address: Here is the description

Since you are using fetch API, you need to do await again
export const signup = (email, password) => {
return async dispatch => {
const response = await fetch('https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=[API-KEY]',
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email: email,
password: password,
returnSecureToken: true
})
}
);
const data = await response.json();
console.log(data );
References:
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

Related

Post form-data on Axios (React)

I've got the following component in React:
const login = async (username, password) => {
const response = await axios.post('/auth/jwt/login', {
username,
password
});
const {accessToken, user} = response.data;
setSession(accessToken);
dispatch({
type: 'LOGIN',
payload: {
user,
},
});
};
Now, the problem is my API is expecting a form, whereas this request is sending a json on the body, thus I'm getting a 422 error (unprocessable entity).
I've tried creating a FormData() object but no luck so far:
const formData = new FormData();
const login = async () => {
const response = await axios.post('/auth/jwt/login', {
username: formData.username,
password: formData.password
});
const {accessToken, user} = response.data;
setSession(accessToken);
dispatch({
type: 'LOGIN',
payload: {
user,
},
});
};
Can anyone please help me? Thanks!
Specifically you want to POST the data as application/x-www-form-urlencoded instead of as a JSON-encoded body. According to the documentation, in the browser you would use URLSearchParams for this. For example:
const params = new URLSearchParams();
params.append('username', username);
params.append('password', password);
const response = await axios.post('/auth/jwt/login', params);
(That same documentation provides other options as well, to include 3rd party libraries or to POST from NodeJS. The above is specific to in-browser code with no 3rd party libraries.)
The previous solution didn't work for me. This did:
const form = new FormData();
form.append('username', username)
form.append('password', password)
const response = await axios.post('/auth/jwt/login', form,
{ headers: { 'Content-Type': 'multipart/form-data' } }
);
In fact I could just do this:
const login = async (username, password) => {
const response = await axios.post('/auth/jwt/login', {
username,
password
},
{ headers: { 'Content-Type': 'multipart/form-data' } }
);
const {accessToken, user} = response.data;
setSession(accessToken);
dispatch({
type: 'LOGIN',
payload: {
user,
},
});
};

I can't make the post or put with fetch or axios to the swagger-ui API to create a login page

I am trying to make a login page with react using a swagger api: this is the code that i have but it give me this error: POST https://dev.tuten.cl/TutenREST/rest/user/testapis%40tuten.cl 400 (Bad Request)
when i make the test in the API, it gives me an ok, but with my function the result it's 400 BAD REQUEST i can't understand why it's not working:
Can anyone help me?
const onSignIn = async ({ email, password, app }) => {
const result = await fetch('https://dev.tuten.cl/TutenREST/rest/user/testapis%40tuten.cl', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email,
password,
app,
}),
});
if (result.ok) {
const promiseData = await result.json();
console.log(promiseData);
} else {
console.log('Access is not allowed');
}
};

How can i handle axios error in redux-saga

Is there a way to capture the error response from axios in a try/catch redux-saga?
I have the following axios logging function:
export const login = (username, password) => {
const config = {
headers: {
'Content-Type': 'application/json',
},
};
const body = JSON.stringify({ username, password });
return axios
.post('http://127.0.0.1:8000/accounts-api/login', body, config)
.then(response => response.data)
.catch(error => error.response.data)
};
which returns
{user: {…}, token: "b5d36ec9086f7f2403a02c2e8d70695e85a48cad2d81e39c9b31fddaa759a79e"}
when the password and username is correct or
{non_field_errors: ["Incorrect Credentials"]}
when password or username is not correct.
The login function is called in the following redux-saga generator:
export function* signIn({ payload: { username, password } }) {
try {
const response = yield login(username, password)
let { user, token } = yield response
yield console.log(user)
yield console.log(token)
} catch(e) {
yield console.log(e)
}
}
Is there a way to capture the error response from axios ( in this case {non_field_errors: ["Incorrect Credentials"]} )in redux-saga catch?
Now with incorect user credential user and token are set to undefined and function is not moving on to redux-saga catch.

How can I share local image to Firebase and then be able to retrieve whatever device I sign in in React Native?

I'm trying to post images to Firebase real-time database. Until now, I've successfully done that, the images can be shown but only when I still connect the app and not yet reload
I know the reason is because the uri I post on database has the type like this:
content://com.google.android.apps.photos.contentprovider/0/1/content%3A%2F%2Fmedia%2Fexternal%2Fimages%2Fmedia%2F58/ORIGINAL/NONE/image%2Fjpeg/484166561
Here's the code in Redux action for adding a post:
export const addPost = (postImage, date, description, checkin_location) => {
return async (dispatch, getState) => {
const token = getState().auth.user.token;
const userId = getState().auth.user.uid;
const response = await fetch(
`https://..../users/${userId}/posts.json?auth=${token}`, {
method: 'POST',
headers:{
'Content-Type': 'application/json'
},
credentials: 'same-origin',
body: JSON.stringify({
postImage,
date,
description,
checkin_location,
})
});
const resData = await response.json();
console.log(resData);
if(!response.ok){
console.log("reponse isn't ok in post action ", response)
};
dispatch({
type: ADD_POST,
postData:{
id: resData.name,
ownerId: userId,
postImage,
date,
description,
checkin_location
}
})
}
}
What should I do in order to achieve that?
Or to be precise, how can I convert that uri link to be say an url or at least a type that Image component can display even when I reload or sign in by another device
I'm using real-time database and heard of Firestore and Cloud Functions but haven't used it yet
PLEASE HELP

JWT Secure Routes in React

I am adding JWT authentication to a blog app I'm working on. On the server side (built with Nodejs) I am creating the token and sending it back with a successful login. On the client side I am saving the token in LocalStorage. When I log in and check the application tab in dev tools I can see the token. On the server route where blogs are posted to I check authentication. If the token is authenticated the blog posts to the database, but if I delete the token or change it and then make the post request the request fails, as expected.
So far so good.
What I'm confused about is how to restrict access to the page where the blog editor resides on the client. If people aren't authenticated they should not be able to access this page at all, even though if not authenticated they can't post anyway.
Login route on server:
router.post('/login', async (req, res, next) => {
const cursor = User.collection.find({username: req.body.username}, {username: 1, _id: 1, password: 1});
if(!(await cursor.hasNext())) {
return res.status(401).json({ message: 'Cannot find user with that username' });
}
const user = await cursor.next();
try {
if(await bcrypt.compare(req.body.password, user.password)) {
const token = jwt.sign({
email: user.email,
userId: user._id
}, process.env.JWT_SECRET, { expiresIn: "1h" })
return res.status(201).json({
message: 'User Authenticated',
token: token
});
} else {
return res.status(400).json({
authenticated: false,
username: req.body.username,
password: req.body.password
})
}
} catch (err) {
return res.status(500).json({ message: err })
}
});
How I'm checking the token authentication on the server:
const jwt = require('jsonwebtoken');
module.exports = (req, res, next) => {
try {
const token = req.headers.authorization;
console.log(token);
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.userData = decoded;
next();
} catch (error) {
return res.status(401).json({ message: 'Auth Failed' })
}
}
My client side login route fetch:
handleSubmit(event) {
event.preventDefault();
const formData = {
username: event.target.username.value,
password: event.target.password.value
}
fetch('http://localhost:4000/user/login', {
method: "POST",
mode: "cors",
body: JSON.stringify(formData),
headers: {
"Content-Type": "application/json"
}
})
.then(res => res.json())
.then(res => {
localStorage.setItem('authorization', res.token);
console.log(res);
})
.catch(err => console.error(err))
}
And here is my fetch call from the client on the blog posting route where the editor resides:
handleSubmit = (event) => {
event.preventDefault();
const data = new FormData(event.target);
const body = event.target.postBody.value;
const postTitle = event.target.title.value;
console.log(event.target);
console.log(data);
console.log(event.target.postBody.value);
fetch('http://localhost:4000/blog', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
"Authorization": localStorage.getItem('authorization')
},
mode: 'cors',
body: JSON.stringify({
title: postTitle,
postBody: body
})
})
.then(res => res.json())
.then(err => console.error(err))
}
So, like I said, everything is working as expected but I don't want people to be able to access the editor page if they are not authenticated. I guess I would check to see if the token exists in localstorage and then redirect? But wouldn't I also need to check to see if the token on the client can be authenticated on the server as well? So would I essentially need to post to the server to do the check whenever someone navigates to that page, or any other page I want to restrict access to? Come to think of it, if a user is already authenticated I don't want them to be able to access the login page either.
I have heard that people use Redux to manage state across components, but I really don't want to go down that road, at least not yet because this project is for learning purposes and I don't really want to start with Redux or anything else like that until I have a better grasp of React on it's own. I don't know if I need Redux or not and from what I understand, that's enough to know that I probably don't need it.
This is just such a different flow than I'm used to from PHP sessions and I'm having some trouble wrapping my head around it.
I realize that you folks may not really need to see all this code, but I also would like some more experienced eyes to see it and point out anywhere I might be making mistakes or where I could improve here.
So this is what I have come up with for now, if anyone knows a better way, I'm definitely open to suggestions.
I created a class called CheckAuth which essentially just makes a GET request to the server and sends the jwt along with it.
checkAuth.js:
class CheckAuth {
constructor() {
this.auth = false;
}
async checkLogin() {
console.log(localStorage.getItem("authorization"));
let data = await fetch('http://localhost:4000/auth', {
method: "GET",
mode: "cors",
headers: {
"Content-Type": "application/json",
"authorization": localStorage.getItem("authorization")
}
})
return data.json();
}
logout(cb) {
localStorage.removeItem('authenticated')
this.auth = false;
cb();
}
async isAuthenticated() {
const data = await this.checkLogin()
return data;
}
}
export default new CheckAuth();
Then on pages that only logged in users should see I am doing a simple check to see if they have the token and if it's valid inside of componentDidMount().
componentDidMount() {
const check = checkAuth.isAuthenticated();
console.log(check);
check.then(res => {
console.log(res);
if(res.authenticated !== true) {
this.props.history.push("/login");
}
})
.catch(err => { console.error(err) })
}

Resources