--description--
Serialization and deserialization are important concepts in regard to authentication. To serialize an object means to convert its contents into a small key that can then be deserialized into the original object. This is what allows us to know who has communicated with the server without having to send the authentication data, like the username and password, at each request for a new page.
To set this up properly, you need to have a serialize function and a deserialize function. In Passport, these can be created with:
passport.serializeUser(cb);
passport.deserializeUser(cb);
The callback function passed to serializeUser
is called with two arguments: the full user object, and a callback used by passport.
The callback expects two arguments: An error, if any, and a unique key to identify the user that should be returned in the callback. You will use the user's _id
in the object. This is guaranteed to be unique, as it is generated by MongoDB.
Similarly, deserializeUser
is called with two arguments: the unique key, and a callback function.
This callback expects two arguments: An error, if any, and the full user object. To get the full user object, make a query search for a Mongo _id
, as shown below:
passport.serializeUser((user, done) => {
done(null, user._id);
});
passport.deserializeUser((id, done) => {
myDataBase.findOne({ _id: new ObjectID(id) }, (err, doc) => {
done(null, null);
});
});
Add the two functions above to your server. The ObjectID
class comes from the mongodb
package. mongodb@~3.6.0
has already been added as a dependency. Declare this class with:
const { ObjectID } = require('mongodb');
The deserializeUser
will throw an error until you set up the database connection. So, for now, comment out the myDatabase.findOne
call, and just call done(null, null)
in the deserializeUser
callback function.
Submit your page when you think you've got it right. If you're running into errors, you can check out the project completed up to this point.
--hints--
You should serialize the user object correctly.
async (getUserInput) => {
const url = new URL("/_api/server.js", getUserInput("url"));
const res = await fetch(url);
const data = await res.text();
assert.match(
data,
/passport.serializeUser/gi,
'You should have created your passport.serializeUser function'
);
assert.match(
data,
/null,\s*user._id/gi,
'There should be a callback in your serializeUser with (null, user._id)'
);
}
You should deserialize the user object correctly.
async (getUserInput) => {
const url = new URL("/_api/server.js", getUserInput("url"));
const res = await fetch(url);
const data = await res.text();
assert.match(
data,
/passport.deserializeUser/gi,
'You should have created your passport.deserializeUser function'
);
assert.match(
data,
/null,\s*null/gi,
'There should be a callback in your deserializeUser with (null, null) for now'
);
}
MongoDB should be a dependency.
async (getUserInput) => {
const url = new URL("/_api/package.json", getUserInput("url"));
const res = await fetch(url);
const packJson = await res.json();
assert.property(
packJson.dependencies,
'mongodb',
'Your project should list "mongodb" as a dependency'
);
}
Mongodb should be properly required including the ObjectId.
async (getUserInput) => {
const url = new URL("/_api/server.js", getUserInput("url"));
const res = await fetch(url);
const data = await res.text();
assert.match(
data,
/require.*("|')mongodb\1/gi,
'You should have required mongodb'
);
assert.match(
data,
/new ObjectID.*id/gi,
'Even though the block is commented out, you should use new ObjectID(id) for when we add the database'
);
}