NodeJS

From Organic Design wiki

Express

Email Validation

This post explains the general process for validating email, in my use case it didn't make sense to have users with non-validated emails so my process is this:

  • Create an email verification entry into the database with the fields:
    • Account reference
    • Email string
    • Random 128 character hex token
    • Expires Date/Time (current time + 1h)
  • Use nodemailer to send an email with a link to "/verify-token/:token"
  • Add the "/verify-token/:token" to express and look in the database for that token.
    • If it exists, check it isn't pass expiry and update the account with the email referenced in the token then remove the token.
    • If it does not exist or is not valid return an error to the user.

CSRF

If you want to implement CSRF protection in express for a SPA application you need to inject the token into the template html, this is best done using steams for performance. This code also uses express sessions instead of cookies for tracking the tokens.

const Transform		= require("stream").Transform;
const newLineStream = require("new-line");
const fs			= require("fs");
const csurf			= require("csurf");
const session		= require("express-session");

const csrfProtection		= csurf();
const app					= express();

app.use(session({
	secret: crypto.randomBytes(32).toString("hex"),
	resave: false,
	saveUninitialized: true,
	cookie: { secure: serverConfig.protocol === "https" }
}));

const csrfInject = (req, res, file) => {
	const streamParser = new Transform();

	// Modify the transform to inject custom code.
	streamParser._transform = function (data, encoding, done) {
		const str = data.toString().replace("</head>", `<meta content="${req.csrfToken()}" name="csrf-token" /></head>`);
		this.push(str);
		done();
	};

	res.set("Content-Type", "text/html");

	// Send the file.
	return fs.createReadStream(file)
		.pipe(newLineStream())
		.pipe(streamParser)
		.on("error", console.error)
		.pipe(res);
};

app.get("/*", csrfProtection, (req, res, next) => {
	return csrfInject(req, res, path.resolve(__dirname,"../dist/index.html"));
});

// app.post("/endpoint", csrfProtection ...

You can access and use the token on the front end like so:

const csrf = document.querySelector(`meta[name="csrf-token"]`)?.getAttribute("content");

fetch("/endpoint", {
	method: "POST",

	headers: {
		"CSRF-Token": csrf
	}
});

See also