M.KH
M.KH

Reputation: 420

is it safe to save data that affect component rendering in JWT payload?

i'm working on a MERN app where users have multiple roles, and in react the components are rendered conditionally and differently based on the user role. in my app i store a JWT that contains the user's id and role in a cookie and then decode this token in a global user context that would pass the user's data on to other components..is this a safe practice?

wouldn't any malicious user be able to decode and alter the user role in the JWT and then replace the original cookie with it which would result in them accessing components and data they are not supposed to access? i know they can't do much harm backend-wise because the token is validated in every API call in my back end..but on the front end i can't validate the token.

is there a better practice than this?

here is my user context code

import React from 'react';
import { useReducer, useEffect } from 'react';
import Cookies from 'js-cookie';
import jwt_decode from "jwt-decode";

export const UserContext = React.createContext();

export function userReducer(state, action) {
    switch (action.type) {
        case "LOGIN":
            return { user: action.payload };
        case "LOGOUT":
            return { user: null };
        default:
            return state;
    }
}

let UserContextProvider = function (props) {
    let userToken = Cookies.get("userToken");
    let userInfo = jwt_decode(userToken);
    const [state, dispatch] = useReducer(userReducer, {
        user: userInfo
    })

    useEffect(() => {
        if (userToken) {
            dispatch({ type: "LOGIN", payload: userToken })
        }
    }, [])

    return <UserContext.Provider value={{ state, dispatch }}>
        {props.children}
    </UserContext.Provider>
}

export default UserContextProvider;

an example of conditional rendering that i intend to do

 <FormGroup name="name" id="name" type="text" text={text} required={true} />
            <FormGroup name="tags" id="tags" type="text" text={text} required={true} />
            <FormGroup name="address" id="address" type="text" text={text} required={true} />
            <FormGroup name="images" id="images" type="file" text={text} accept="image/*" required={false} multiple={true} />
            {user.role==3 && <FormGroup name="video" id="video" type="file" text={text} accept="video/mp4,video/x-m4v,video/*" required={false}} />
            <div className="my-5 mx-auto w-50">
                <label className="form-label text-main fs-3" htmlFor="msg">{text}</label>
                <textarea className="form-control" required="required" name="description" id="description" rows="8" ></textarea>
            </div>

as you can see here only a user that has a role of 3 can access a video upload input in the form..wouldn't any malicious be able to alter the JWT in the cookie and have his role changed to 3? he would then be able to see the video upload input, the submission of the form would fail at the backend because the token is validated there, but what can i do to protect my site on the front end?

Upvotes: 0

Views: 104

Answers (1)

blastz
blastz

Reputation: 365

You can get user info from an api like /users/me, so you can check the token signature in server.

User still can intercept your request, then return the fake role or debug your code by dev tool to show the hidden elements.

But it will be more safe than your current code, user only need to do this to change the role:

const userInfo = JSON.parse(window.atob(userToken.split('.')[1]));
userInfo.role = 3;

Just remember your source code is in the browser, so you can't protect yourself in front-end.

Upvotes: 1

Related Questions