Home > Net >  JsonWebTokenError: jwt must be a string, node.js
JsonWebTokenError: jwt must be a string, node.js

Time:07-07

I'm getting the error JsonWebTokenError: jwt must be a string when getting the jwt from the front end (react.js) and using in middleware to verify the token. If I tried to use toString it gives me another error JsonWebTokenError: jwt malformed.

Update

As soon as i pass the accessToken from frontEnd it converted into object in the AuthMiddleware.js. I'm passing middleware on header in file Post.js(attached below)

AuthMiddleware.js

const { verify } = require("jsonwebtoken")


const validateToken = (res, req, next) => {
    const accesToken = req.header("accesToken");
    const stringAccesToken = accesToken.toString()
    console.log(typeof (stringAccesToken), "accesToken type")

if (!stringAccesToken) {
    return res.json({ error: "user not logged in" })

}

try {
    const validToken = verify(stringAccesToken, "importantSecret");
    console.log(validToken, 'validtoken')
    if (validToken) {
        return next();
    }
} catch (err) {
    console.log(err, "error")
    }

}

module.exports = { validateToken }

User.js (backend for login)

const express = require("express");
const router = express.Router()
const { Users } = require("../models")
const bcrypt = require("bcrypt")

const { sign } = require("jsonwebtoken")

  

router.post("/login", async (req, res) => {
    const { username, password } = req.body;
    const user = await Users.findOne({ where: { username: username } });

    if (!user) {
        return res.json({ error: "User dosen't exist" })
    }

    bcrypt.compare(password, user.password)
        .then((match) => {
            if (!match) {
                return res.json({ error: "Wrong Username and Password match" })
            }
            const accessToken = sign({ username: user.username, id: user.id }, "importantSecret")
            res.json(accessToken)
        })
})

module.exports = router;

Post.js

import React, { useEffect, useState } from 'react'
import { useParams } from 'react-router-dom';
import axios from 'axios';
import './Post.css'


function Post() {

    let { id } = useParams();

    const [postObject, setPostObject] = useState({})
    const [comments, setComments] = useState([]);
    const [newComment, setNewComment] = useState("");

    // console.log(comments)

    const addComment = () => {


        const accessToken = sessionStorage.getItem('accessToken')
        console.log(typeof (accessToken), 'acces token in comment button')

        axios.post(`http://localhost:4000/comments`,
            {
                commentBody: newComment,
                PostId: id
            },
            {
                headers: {
                    accessToken: sessionStorage.getItem("accessToken"),
                }
            }
        )
            .then((res) => {
                // console.log(res)
                const data = res.data;
                console.log(data, 'comments')

                setComments([...comments, data])
                setNewComment("")
            })
            .catch((err) => {
                alert(err, 'Error:comment')
            })
    }



    useEffect(() => {
        axios.get(`http://localhost:4000/posts/byId/${id}`)
            .then((res) => {
                // console.log(res)
                const data = res.data;
                // console.log(data)

                setPostObject(data)
                // setPost(data)

            })

        // comment api request
        axios.get(`http://localhost:4000/comments/${id}`)
            .then((res) => {
                // console.log(res)
                const data = res.data;
                // console.log(data)

                setComments(data)

            })
    }, [])


    return (
        <div className='Post'>

            <div className='left__side'>
                <div className='left__side__wrapper'>

                    <div className='title'>{postObject.title}</div>
                    <div className='text'>{postObject.postText}</div>
                    <div className='username'>{postObject.username}</div>
                </div>


            </div>
            <div className='right__side'>
                <div className='right__side__wrapper'>
                    <div className='add__comment__container'>

                        <input type="text"
                            value={newComment}
                            placeholder="Comment"
                            //  autoComplete="off"
                            onChange={(e) => setNewComment(e.target.value)}

                        />
                        <button onClick={addComment}> Submit Comment</button>

                    </div>
                    <div className='listOfCommnets'>

                        {comments.map((item, index) => {
                            {/* console.log(item, 'item') */ }
                            return <div className='comments' key={index}>Comments:<br />{item.commentBody}</div>

                        })}
                    </div>
                </div>
            </div>

        </div>
    )
}

export default Post

CodePudding user response:

Because the jwt token is using an object as an input rather than using the word "verify," it won't work with the object in which you are receiving the error any longer. Instead, you must attempt as follows.

var jwt = require("jsonwebtoken");

const validateToken = (res, req, next) => {
const accesToken = req.header("accesToken");
const stringAccesToken = accesToken;

if (!stringAccesToken) {
   return res.json({ error: "user not logged in" });
}

jwt.verify(stringAccesToken, "importantSecret", function (err, decoded) {
  if (err)
    return console.log(err)
  // Next Code
  next();
 });
};

module.exports = { validateToken };

CodePudding user response:

I found the solution: As the error said JWT need to be string,

I first tried using accesToken.toString() that gives [object object], On second try i used JSON.stringy and that was also unsuccessful.

Final scuccesful attemp was to use library name - flatted (to convert json to string and after using it i just used split till i did'nt get the token).

faltted (link) - https://github.com/WebReflection/flatted#flatted

Worked Solution -

AuthMiddleware.js

const { parse, stringify, toJSON, fromJSON } = require('flatted');



const validateToken = (res, req, next) => {


    const authToken = req.header("accessToken");
    const string = stringify(authToken)
    const token = string && string.split(' ')[2];
    const tokenPure = token.split('"')[4]

    if (!tokenPure) {
        return res.json({ error: "user not logged in" })

    }
    try {
        const validToken = verify(tokenPure, "importantSecret");
        // console.log(validToken, 'validtoken')
        if (validToken) {
            return next();
        }
    } catch (err) {
        console.log(err, "error")
    }

}

module.exports = { validateToken }
  • Related