Set timeout Function on inactivity of user in React JS - node.js

I have created login form in reactjs. This stores a token in state. Login and Logout functions are working properly. But I want to expire this token on inactivity of the user and user will automatically logout.
Login:
export const authSlice = createSlice({
name: "auth",
initialState,
reducers: {
setLogin: (state, action) => {
state.user = action.payload.user;
state.token = action.payload.token;
},
setLogout: (state) => {
state.user = null;
state.token = null;
}
},
});
const login = async (values, onSubmitProps) => {
const loggedInResponse = await fetch("http://localhost:5001/auth/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(values),
});
const loggedIn = await loggedInResponse.json();
onSubmitProps.resetForm();
if (loggedIn) {
dispatch(
setLogin({
user: loggedIn.user,
token: loggedIn.token,
})
);
navigate("/dashboard");
}
};
const handleFormSubmit = async (values, onSubmitProps) => {
if (isLogin) await login(values, onSubmitProps);
};

Related

Testing Cognito JWKS using mock-jwk?

Auth AWS lambda
export const authorizeFinance = async (event) => {
if (event.headers.authorization) {
const token = event.headers.authorization.substring(7);
try {
const verifier = CognitoJwtVerifier.create({
userPoolId: "xyz",
tokenUse: "access",
clientId: "123",
});
const payload = await verifier.verify(token);
if (authLogic(payload)) {
return {isAuthorized: true, context: {AuthInfo: 'Finance'}}
}
return {isAuthorized: false, context: {}}
} catch (e) {
return {isAuthorized: false, context: {}}
}
}
}
Test case in jest using mock-jwks
import createJWKSMock from "mock-jwks";
import {authorizeFinance} from "#functions/auth-finance/handler";
describe('Authenticate finance', () => {
const jwks = createJWKSMock('https://cognito-idp.ap-southeast-2.amazonaws.com/ap-southeast-xyz.', 'well-known/jwks.json');
beforeEach(() => {
jwks.start();
});
afterEach(() => {
jwks.stop();
});
test('should verify the token', async () => {
const token = jwks.token({
aud: 'https://test.auth-domain.com/',
iss: 'https://cognito-idp.ap-southeast-2.amazonaws.com/ap-southeast-xyz',
});
console.log(token);
const event = {
headers: {
authorization: `Bearer ${token}`,
}
};
jest.unmock('axios');
const basicResponse = await authorizeFinance(event);
console.log('jatin', basicResponse);
expect(basicResponse).toEqual({ isAuthorized: false, context: {} });
});
})
Fails
Authentication failed JWK for kid "BlYCji0Uj6V3LAxmK1JHqYgnPJIUUqeiS8YzUf0vfh0=" not found in the JWKS
Authentication failed Missing Token use. Expected one of: id, access

createAysncThunk in Redux Toolkit catching error when making fetch request

I'm working on the user registration functionality of an application using Typescript and Redux Toolkit. When I make the fetch request to the signup endpoint, a new user is saved to the database I've connected, but I keep entering the catch error block.
export const registerUser = createAsyncThunk(
"user/registerUser",
async (form: { username:string, password:string }, thunkAPI) => {
try {
const response = await fetch('/api/auth/signup', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
userInfo: {
username: form.username,
password: form.password
}
}),
});
if (response.status === 200) return 200;
else return 400;
} catch (e) {
console.log('Error')
}
}
);
I've tried logging the response to the console a number of ways
const data = await response.json() console.log(data)
But have had no luck. I think this is an error with how I've done my fetch request using createAsyncThunk but haven't been able to figure out what I've missed.
This is the code for the initial state and slice:
interface UserState {
userProfile: {
id: number | null;
},
registration: {
status: 'loaded' | 'loading'
}
}
const initialState : UserState = {
userProfile: {
id: null,
},
registration: {
status: 'loaded'
}
};
export const userSlice = createSlice({
name: 'user',
initialState,
reducers: {
},
extraReducers: (builder) => {
builder.addCase(registerUser.fulfilled, (state) => { state.registration.status = 'loaded' }),
builder.addCase(registerUser.rejected, (state) => { state.registration.status = 'loaded' }),
builder.addCase(registerUser.pending, (state) => { state.registration.status = 'loading' })
}
})
And here is the code for the function where the action is dispatched on the UI
const handleRegister= async () => {
if (!username) return alert('Username field was left empty');
if (!password) return alert('Password field was left empty');
const {payload} : any = await dispatch(registerUser({ username: username, password: password}));
if (payload === 200) {
alert('Successfully registered. Redirecting to dashboard');
return navigate('/dashboard');
} else { return alert('User creation unsuccessful'); }
}
Appreciate any help as I've looked through many other posts but haven't been able to resolve my issue.

I get undefined when reading my response but there is a response in React.js

I can't figure it out, the answer comes in the network table but when I want to console.log it, this will display undefined. Do you have any idea why? I attach the pictures and the code.
Here is a image with my codes and response
Here is the code - first one is where I send the response. As I said, it's going well on network tab, I get a 200 status.
export const getAccountStatus = async (req, res) => {
const user = await User.findById(req.user._id).exec();
const account = await stripe.accounts.retrieve(user.stripe_account_id);
// console.log("user account retrieve", account);
const updatedUser = await User.findByIdAndUpdate(
user._id,
{
stripe_seller: account
},
{ new: true }
)
.select("-password")
.exec();
console.log(updatedUser);
res.send(updatedUser);
};
Here is the page where i want to console.log it:
const StripeCallback = ({ history }) => {
const { auth } = useSelector(state => ({ ...state }));
const dispatch = useDispatch();
useEffect(() => {
if (auth && auth.token) accountStatus();
}, [auth]);
const accountStatus = async () => {
try {
const res = await getAccountStatus(auth.token);
console.log(res);
} catch (err) {
console.log(err);
}
};
return <div>test</div>;
};
Ang here is the Axios.post (which is working well as I know):
export const getAccountStatus = async token => {
await axios.post(
`${process.env.REACT_APP_API}/get-account-status`,
{},
{
headers: {
Authorization: `Bearer ${token}`
}
}
);
};
Thank you!
getAccountStatus doesn't have a return statement, so res in const res = await getAccountStatus(auth.token); will always be undefined.
export const getAccountStatus = async token => {
return axios.post( // <----- added return
`${process.env.REACT_APP_API}/get-account-status`,
{},
{
headers: {
Authorization: `Bearer ${token}`
}
}
);
};

how to update context state in react

I am having a problem that when user upload their profile image it did not change, user have to log out and log back in to make a change complete.
Here is my back end how to get image from client and store it on cloudinary:
profilesController.js:
exports.updateAvatar = async (req, res) => {
// Find user with matching token
// const updates = [];
const updateUserAvatar = await models.User.findOne({
where: {
id: req.id,
},
});
// Was user found?
if (updateUserAvatar === null) {
return res.status(200).json({
validationErrors: {
errors: [
{
msg: "Reset is invalid or has expired.",
},
],
},
});
}
// Update user with new info
models.User.update(
{
picture: req.imageUrl,
},
{
where: {
id: updateUserAvatar.dataValues.id,
},
}
);
console.log(updateUserAvatar);
At the console it should gave me a new image url but instead it just keep the old image url
Here is my profilesAPI where my route is:
router.post('/upload/image', function (req, res, next) {
const dUri = new Datauri();
const dataUri = (req) => dUri.format(path.extname(req.name).toString(), req.data);
if (req.files !== undefined && req.files !== null) {
const { file, id } = req.files;
const newFile = dataUri(file).content;
cloudinary.uploader.upload(newFile)
.then(result => {
const imageUrl = result.url;
const data = {id : req.body.id, imageUrl };
updateAvatar(data);
return res.status(200).json({ message: 'Success', data: { imageUrl } });
}).catch(err => res.status(400).json({message:'Error', data: { err}}));
} else {
return res.status(400).json({ message: 'Error' });
}
});
And that's all for my back end code. Here is my front end that cient send image to server:
Here is the method that help user can send image to server:
const UserCard = ({ name, userEmail, isVerified, id, updateUserAvatar, currentUser }) => {
const [selectedValue, setSelectedValue] = useState("a");
const handleChange = (event) => {
setSelectedValue(event.target.value);
};
const [imageSelected, setImageSelected] = useState("");
const uploadImage = () => {
const formData = new FormData();
formData.append("file", imageSelected);
formData.append("id", id);
axios
.post("/api/v1/profiles/upload/image", formData, {
headers: { "Content-Type": "multipart/form-data" },
})
.then((response) => {
updateUserAvatar(response.data.data.imageUrl);
});
};
useEffect(() => {
if (imageSelected !== '') {
uploadImage();
}
}, [imageSelected]);
return (
<div className="avatar--icon_profile">
<Card className="profile--card_container">
<CardContent>
{currentUser.picture ? (
<div>
<input
className="my_file"
type="file"
ref={inputFile}
onChange={(e) => setImageSelected(e.target.files[0])}
/>
<div className="profile-image">
<Avatar
src={currentUser.picture}
alt="Avatar"
className="avatar--profile_image"
onClick={onButtonClick}
/>
</div>
</div>
and here is my Global State. I tried to update nested state in my context but seems like it didn't work.
const GlobalState = (props) => {
// User State -----------------------------------------------------------------------------
const [currentUser, setUser] = useState(props.serverUserData);
console.log(currentUser)
const updateUser = (userData) => {
setUser(userData);
};
// This method is passed through context to update currentUser Avatar
const updateUserAvatar = (picture) => {
setUser({ ...currentUser, picture: picture });
};
const providerValues = {
currentUser,
updateUser,
updateUserAvatar,
};
return (
<GlobalContext.Provider value={providerValues}>
{props.children}
</GlobalContext.Provider>
);
};
export default GlobalState;
and here is my console.log(currentUser) gave me:
{id: "a19cac5c-ea25-4c9c-b1d9-5d6e464869ed", name: "Nhan Nguyen", email: "nhan13574#gmail.com", publicId: "Nh1615314435848", picture: "http://res.cloudinary.com/teammateme/image/upload/v1617229506/gnlooupiekujkrreerxn.png", …}
email: "nhan13574#gmail.com"
id: "a19cac5c-ea25-4c9c-b1d9-5d6e464869ed"
isSessionValid: true
name: "Nhan Nguyen"
picture: "http://res.cloudinary.com/teammateme/image/upload/v1617229506/gnlooupiekujkrreerxn.png"
publicId: "Nh1615314435848"
__proto__: Object
Can anyone help me solve this problem? I really appreciate it
Added GlobalContext.js:
import React from "react";
const globalStateDefaults = {
modals: {
isAuthModalOpen: false,
modalToDisplay: "signup",
toggleModal: () => {},
setModalToDisplay: () => { },
},
user: undefined,
pageName: undefined,
loading: false,
teamProfileId: "",
userProfileId: "",
};
export const GlobalContext = React.createContext(globalStateDefaults);
You need to consume the context where you are trying to update user state.
const {currentUser, updateUser, updateUserAvatar} = React.useContext(GlobalContext)
Then you can call
updateUserAvatar(response.data.data.imageUrl)

After jwt verification the state change is not presisting

So on the front end I'm using this function to have the user Log In if they have a This Function only works at the time of log in and after if the users just navigates to a different page on the site then it resets the userData state's values to undefined, The api link "http://localhost:5000/users/isTokenValid" returns either true or false
const [adminData, setAdminData] = useState({
token: undefined,
user: undefined,
});
const [authData, setAuthData] = useState(undefined);
const [userData, setUserData] = useState({
token: undefined,
user: undefined,
});
useEffect(() => {
const checkLoggedIn = async () => {
let token = localStorage.getItem('auth-token');
if (token === null) {
localStorage.setItem('auth-token', '');
token = '';
}
const tokenRes = await axios.post(
'http://localhost:5000/users/isTokenValid',
null,
{ headers: { 'x-auth-token': token } },
);
if (tokenRes.data) {
const userRes = axios.get('http://localhost:5000/users/', {
headers: { 'x-auth-token': token },
});
setUserData({
token,
user: userRes.data,
});
}
};
checkLoggedIn();
}, []);
return (
<UserContext.Provider value={{ userData, setUserData }}>
<AdminContext.Provider value={{ adminData, setAdminData }}>
<AuthContext.Provider value={{ authData, setAuthData }}>
<Routes />
</AuthContext.Provider>
</AdminContext.Provider>
</UserContext.Provider>
);
I didn't add await.
if (tokenRes.data) {
const userRes = await axios.get('http://localhost:5000/users/', {
headers: { 'x-auth-token': token },
});
setUserData({
token,
user: userRes.data,
});
}

Resources