Authenticate my ReactJS SPA with laravel/sanctum using Axios - reactjs

After a successful authentication (login + token), I'm still unable to request auth:sanctum routes and I get the following response:
LoginForm component
import React, { useState } from "react";
const LoginForm = () => {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const loginHandler = (ev) => {
ev.preventDefault();
if (email.length > 0 && password.length > 0) {
axios.get("/sanctum/csrf-cookie").then(() => {
axios
.post("api/login", {
email: email,
password: password,
})
.then((response) => {
console.log(response.data);
})
.catch(function (error) {
console.error(error);
});
});
}
};
Login action
public function login(Request $request)
{
$request->validate(['email' => 'required', 'password' => 'required|string']);
$user = User::where('email', $request->email)->first();
if (!$user || !password_verify($request->password, $user->password)) {
return response(['message' => 'Bad credentials'], 401);
}
$token = $user->createToken('token')->plainTextToken;
return response(['user' => $user, 'token' => $token], 201);
}
Login Response
{
"user": {
"id": 7,
"email": "daphne19#example.com",
"email_verified_at": "2022-03-09T16:40:59.000000Z",
"created_at": "2022-03-09T16:40:59.000000Z",
"updated_at": "2022-03-09T16:40:59.000000Z"
},
"token": "5|oCnoaVBBYARcFXwdd7dXegchFLS6fckDgr2Bl0L0"
}

You need to pass Sanctum Token in Axios Header.
first you need to set user response in local storage.
const LoginForm = () => {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const loginHandler = (ev) => {
ev.preventDefault();
if (email.length > 0 && password.length > 0) {
axios.get("/sanctum/csrf-cookie").then(() => {
axios
.post("api/login", {
email: email,
password: password,
})
.then((response) => {
//set response in local storage
localStorage.setItem('user', JSON.stringify(response.data))
})
.catch(function (error) {
console.error(error);
});
});
}
};
then you need to pass token in Axios Header
const user = JSON.parse(localStorage.getItem('user'));
const headers = {
accept: 'application/json',
Authorization: 'bearer ' + user.token
}
//set token in axios header
axios.get(API, {
headers: headers
})
.then((res) => { })
.catch((err) => { })

please change the bearer to Bearer while making an authentication requests using Axios.

Related

How to use query string in fetch post?

Newbie here. Building a React site. I'm struggling to get my authentication to go through a fetch post. It keeps returning "No such user" error, but when I have verified the user DOES exist.
I'm using passport on the backend.
const handleSubmit = (event) => {
event.preventDefault();
const data = {
Username: username,
Password: password
};
fetch('https://cthulhuflix.onrender.com/login', {
method: 'POST',
body: new URLSearchParams(JSON.stringify(data))
})
.then ((response) => response.json())
.then ((data) => {
console.log('Login response: ', data);
if (data.user) {
onLoggedIn(data.user, data.token);
} else {
alert('Dave\'s not here! No such user.');
}
})
.catch((e) => {
alert('Something went wrong');
});
};
Here's what I ended up with:
export const LoginView = ({ onLoggedIn }) => {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const handleSubmit = (event) => {
event.preventDefault();
const data = {
Username: username,
Password: password
};
fetch('https://cthulhuflix.onrender.com/login?' + new URLSearchParams(data).toString(), {
method: 'POST',
body: JSON.stringify(data)
}).then ((response) => {
if (response.ok) {
onLoggedIn(username);
} else {
alert('Login failed');
}
});
};

Axios Request failed with status code 500 Registration(with photo)

I wrote an API in laravel and I'm trying to make a registration with accepting a photo and other parameters in React. But I had a problem, most likely because of the photo, when I try to register (I click on the button), I get an Axios 500 error, although the data is all accepted.
Register.js
`
const navigate = useNavigate();
const {http, setToken} = AuthUser();
const registration = (e) => {
e.preventDefault();
// console.log(name, email, phone, photo, password, passwordConfirmation);
console.log(photo);
http.post('/register', {name:name, email:email,phone:phone, photo:photo, password:password, password_confirmation:passwordConfirmation})
.then((response) => {
console.log(response.data.message, response.data.user, response.data.token);
navigate('/login');
})
}
`
AuthUser.js
import axios from "axios";
import { useState } from 'react';
import { useNavigate } from "react-router-dom";
export default function AuthUser() {
const navigate = useNavigate();
const getToken = () => {
const tokenString = sessionStorage.getItem('token');
const userToken = JSON.parse(tokenString);
return userToken;
}
const getUser = () => {
const userString = sessionStorage.getItem('user');
const user_detail = JSON.parse(userString);
return user_detail;
}
const [token, setToken] = useState(getToken());
const [user, setUser] = useState(getUser());
const saveToken = (user,token) => {
sessionStorage.setItem('token', JSON.stringify(token));
sessionStorage.setItem('user', JSON.stringify(user));
setToken(token);
setUser(user);
navigate('/');
}
const logout = () => {
sessionStorage.clear();
navigate('/login');
}
const http = axios.create({
baseURL: "http://127.0.0.1:8000/api",
headers: {
"Content-Type": "application/json",
// "Content-Type": "application/vnd.api+json",
"Authorization": `Bearer ${token}`,
}
});
return {
setToken:saveToken,
token,
user,
getToken,
http,
logout
}
}
LARAVEL AuthController.php
public function register(RegisterRequest $request) {
$request->validated($request->all());
$image = $request->photo;
$imageName = Str::random(32).'.'.$request->photo->getClientOriginalExtension();
$user = User::create([
'name' => $request->name,
'email' => $request->email,
'phone'=>$request->phone,
'photo' => $imageName,
'location' => '',
'bio' => '',
'password' => Hash::make($request->password),
]);
$path = public_path('upload/users');
$image -> move($path, $imageName);
return response([
'message' => 'User has been created',
'user' => new UserResource($user),
'token' => $user->createToken($user->name)->plainTextToken
]);
}
Tried to replace "Content-Type": "application/json" with "Content-Type": "application/vnd.api+json", didn't help; I tried to check through *Postman *that everything works; input without a picture, about the same code also works.

how to get user id after token authentication - REACT

I'm new at coding so hoping this is something simple. I am trying to create delete/update functions for the user when they go to their profile. To delete and update my api needs the user id for:
fetch(${process.env.REACT_APP_API_URL}users/${id}/,
Token authentication works and is stored in the localhost but I can't seem to access the id of the user after login. How can I store the id and call it in this function?
**Notes: the 'userData' const was an attempt at calling the api by:
fetch(${process.env.REACT_APP_API_URL}users/${userData.id}/,
(didn't work)
my ProfilePage code:
const Profile = () => {
const [userData, setUserData] = useState({
username: "",
email: "",
password: "",
});
const { id } = useParams();
const navigate = useNavigate();
const EditAccount = () => {
navigate("/edit-account");
};
const addCar = () => {
navigate("/home");
};
useEffect(() => {
fetch(`${process.env.REACT_APP_API_URL}users/${id}/`)
.then((results) => {
console.log("results", results);
return results.json();
})
.then((data) => {
setUserData(data);
});
});
const Logout = () => {
localStorage.clear();
window.location.href = "/";
};
const DeleteUser = async () => {
fetch(`${process.env.REACT_APP_API_URL}users/${id}/`, {
method: "delete",
headers: {
Authorization: `Token ${localStorage.getItem("token")}`,
},
});
navigate("/");
};

Axios making 2 requests on refresh

When I navigate using Link (react router-dom) I don't have this problem, but if I refresh the browser I get a 403 error in console saying unauthorised and then I get the data in the next request with a 200 response. Why is this making what looks like 2 requests when refreshing the browser?
import { AuthContext } from "../../shared/context/auth-context";
const ContactEntries = () => {
const auth = useContext(AuthContext);
useEffect(() => {
const source = Axios.CancelToken.source();
setIsLoading(true);
const getContactEnquiries = async () => {
try {
const response = await Axios.get(
`${process.env.REACT_APP_BACKEND_URL}/v1/contact`,
{
cancelToken: source.token,
headers: { Authorization: "Bearer " + auth.token },
}
);
if (response.status === 200) {
setIsLoading(false);
setEnquiries(response.data.enquiries);
}
} catch (err) {
setIsLoading(false);
console.log(err.response);
}
};
getContactEnquiries();
return () => {
source.cancel();
};
}, [!!auth.token]);
}
Here is my authContext:
import { createContext } from "react";
export const AuthContext = createContext({
isLoggedIn: false,
userId: null,
token: null,
email: null,
firstName: null,
login: () => {},
logout: () => {},
});
This is because your useEffect is running twice on refresh. On first render it is not getting auth.token and may be it null. And on second render it is making call with 200 status code.
You have to check auth token it coming successfully.
You can check it this way
useEffect(() => {
const source = Axios.CancelToken.source();
setIsLoading(true);
const getContactEnquiries = async () => {
try {
const response = await Axios.get(
`${process.env.REACT_APP_BACKEND_URL}/v1/contact`,
{
cancelToken: source.token,
headers: { Authorization: "Bearer " + auth.token },
}
);
if (response.status === 200) {
setIsLoading(false);
setEnquiries(response.data.enquiries);
}
} catch (err) {
setIsLoading(false);
console.log(err.response);
}
};
if(auth.token) getContactEnquiries();
return () => {
source.cancel();
};
}, [!!auth.token]);

Values won't update after api call with axios

I'm trying to fetch data with axios using React's useEffect in two steps:
1- Get the access token with a POST request
2- Use the token on another POST request to get the desired data
After the first post request, the response returns as expected, but the state value doesn't update. So it sends undefined as the token for the second request.
const [infos, setInfos] = useState(null)
const [token, setToken] = useState('')
useEffect(() => {
const getToken = async () => {
try {
const response = await axios.post(
'adress',
{
username: 'root',
password: 'i_want_my_token',
}
)
setToken(response.data.access)
} catch (error) {
console.log(error)
}
}
getToken()
const getCatalogo = async () => {
try {
let data = { id: 6 }
let configCatalogo = {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`,
},
}
const catalogoResponse = await axios
.post(
'adress',
data,
configCatalogo
)
setInfos(res.data)
} catch (error) {
console.log(error) }
}
getCatalogo()
}, [])
Since the function to get/set your token is asynchronous, you need to use two different useEffects: one to fetch the token and one to use that token once it is set.
const [infos, setInfos] = useState(null)
const [token, setToken] = useState('')
useEffect(() => {
const getToken = async () => {
try {
const response = await axios.post(
'adress',
{
username: 'root',
password: 'i_want_my_token',
}
)
setToken(response.data.access)
} catch (error) {
console.log(error)
}
}
getToken()
}, []);
useEffect(() => {
const getCatalogo = async () => {
try {
let data = { id: 6 }
let configCatalogo = {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`,
},
}
const catalogoResponse = await axios
.post(
'adress',
data,
configCatalogo
)
setInfos(res.data)
} catch (error) {
console.log(error) }
}
getCatalogo()
}, [token]);

Resources