Web crypto crash course
You want to create an authorization server (for a SPA) with node, fast. This is what you need.
Libraries:
cryptojs
: a pure JS crypto library. Slower thancrypto
but easy to installjwt-simple
: simple JWT tokens. The most popular library (and more complex) isjsonwebtoken
permit
: a ligthway library to authorize. A replacement of passport if you don't need social accounts@uphold/http-errors
: don't write error classes (again!)
npm install --save cryptojs
npm install --save jwt-simple
npm install --save permit
npm install --save @uphold/http-errors
Examples are for express, but can be implemented in any other framework easely:
1. Don't store passwords #
When creating user accounts, store the hashed password:
// POST /signUp
async function signUp(req, res) {
const { email, password, repeatPassword } = req.body;
if (!email || !password || passord !== repeatPassword) {
throw BadRequestError();
}
const salt = await bcrypt.genSalt();
const hashedPassword = await bcrypt.hash(password, salt);
const user = db.createUser(email, hashedPassword);
res.send({ message: "User created. Please login." });
}
To verify password:
// POST login
async function login(req) {
const { email, password } = req;
if (!email || !password) {
throw BadRequestError("Invalid email or password");
}
const user = await db.findByEmail(email);
const validPassword = user
? await bcrypt.compare(password, user.password)
: false;
if (validPassword) {
res.json({ token: createToken(user) });
} else {
throw BadRequestError("Invalid login");
}
}
Notice that we returned a JWT token (will create that in the next step)
2. Create JWT tokens (HS256 version) #
Now you need to give the client a token. First you have to store a secret. For example using environment variables:
JWT_SECRET=please-generate-the-password-with-salt
And then use it:
import jwt from "jwt-simple";
const JWT_SECRET = process.env.JWT_SECRET;
function createToken(user) {
const payload = {
userNane: user.name,
userId: user.id,
role: user.role,
};
return jwt.encode(payload, JWT_SECRET, "HS256");
}