Reputation: 503
Upon logging in to my system, I run the MongoDB _id
of the logged in user through the jsonwebtoken's sign
method. It returns to me a hash, which I then put into the session headers of every subsequent request that the client makes to my server.
I now want to decode the session and recover the string _id
from the headers, so I run it against the jsonwebtoken's verify
method. I am not doing this for authentication (that's already handled by looking the session up in a DB). I'm recovering the _id
so I can log the user's activities in a separate collection. I run the verify
function through a middleware and save the decoded result in req.decoded
.
However, when I log req.decoded
, it is a BSON object, rather than a string:
{ _bsontype: 'ObjectID',
id:
{ type: 'Buffer',
data: [ 89, 128, 145, 134, 118, 9, 216, 20, 175, 174, 247, 33 ] },
iat: 1501903389,
exp: 1501989789 }
How can I recover the _id
value from this object, such that I can look for this record again in my collections?
I've tried the following, without success:
model.find(req.decoded).then()
gives me this error:
Error: object [contents of req.decoded here] is not a valid ObjectId
model.find({_id: req.decoded})
gives me this error:
{ CastError: Cast to ObjectId failed for value [contents of req.decoded here] at path "_id" for model [model here]
req.decoded.toString()
logs [object Object]
JSON.stringify(req.decoded)
just turns the BSON into a string
Upvotes: 2
Views: 2534
Reputation: 151132
This of course is subjective to how you actually supply the data to .sign()
in the first place, being the difference of simply supplying the "object" of ObjectID
or by supplying the value instead.
This is actually covered in the general usage for .sign()
as :
If payload is not a buffer or a string, it will be coerced into a string using JSON.stringify.
So in a nutshell that version is going to "stringify" the Object form an require some "digging". In your form the decoded object then has properies of id
with a sub-property of data
which contains an array of bytes than can be converted into a Buffer
. So that's what you do:
let newId = Buffer.from(req.decoded.id.data).toString('hex');
And newId
would then be a "string" represented by the 'hex'
encoded values of the bytes. This of course would be translated by mongoose into an ObjectId
when issued in any "query" or "update" as matching the schema for _id
.
Of course the "alternative" would be simply to .sign()
using the .toString()
value from the ObjectId
in the first place. Then the result of .verify()
would simply the be "hex string" that as supplied, rather than the JSON.stringify
result on the ObjectID
itself.
To demonstrate with a listing:
const bson = require('bson'),
jwt = require('jsonwebtoken');
// Stored ObjectID
console.log("Round 1");
(function() {
let id = new bson.ObjectID();
console.log("Created: %s", id);
let token = jwt.sign(id,'shhh'); // Supply value as ObjectID
let decoded = jwt.verify(token,'shhh');
console.log("Interim");
console.log(decoded);
let newId = Buffer.from(decoded.id.data).toString('hex');
console.log("Decoded: %s", newId);
})();
console.log("\nRound 2");
// Stored String value
(function() {
let id = new bson.ObjectID();
console.log("Created: %s", id);
let token = jwt.sign(id.toString(), 'shhh'); // Supply value as string
let decoded = jwt.verify(token,'shhh');
console.log("Decoded: %s", decoded);
})();
Gives the output, showing the input values and decoded values:
Round 1
Created: 59857328090c497ce787d087
Interim
{ _bsontype: 'ObjectID',
id:
{ type: 'Buffer',
data: [ 89, 133, 115, 40, 9, 12, 73, 124, 231, 135, 208, 135 ] },
iat: 1501917992 }
Decoded: 59857328090c497ce787d087
Round 2
Created: 59857328090c497ce787d088
Decoded: 59857328090c497ce787d088
And demonstrates both forms of usage for supplying the value to .sign()
and what comes out from the subsequent .verify()
calls.
Upvotes: 2