Passwords & JWT
Passwords (scrypt)
Section titled “Passwords (scrypt)”import { hashPassword, verifyPassword } from "@mountsqli/auth";
const hash = hashPassword("s3cret");// scrypt$15$<salt>$<hash>
const ok = verifyPassword("s3cret", hash); // true- scrypt cost
N = 2^15(above Node’s2^14default). - Cost stored in the hash format
scrypt$<cost>$<salt>$<hash>so it can be raised later without breaking existing hashes. - Comparison is constant-time (
timingSafeEqual).
JWT (HS256)
Section titled “JWT (HS256)”Uses the jose library under the hood.
import { createToken, verifyToken, decodeToken } from "@mountsqli/auth";
const token = await createToken( { sub: "u1", email: "a@b.c" }, "my-secret", { maxAge: 3600 },);
const payload = await verifyToken(token, "my-secret");// { sub: "u1", email: "a@b.c", iat: ..., exp: ... } or null
const decoded = decodeToken(token); // no verification, debugging only| Function | Purpose |
|---|---|
hashPassword(pw) |
→ scrypt hash string |
verifyPassword(hash, pw) |
→ boolean (constant-time) |
createToken(payload, secret, opts?) |
→ JWT string (HS256) |
verifyToken(token, secret) |
→ JWTPayload | null |
decodeToken(token) |
→ decoded payload (no verify) |
Best practices
Section titled “Best practices”- Store the hash, never the password.
- Use a 32+ byte random secret for HS256.
- Let
createTokensetiat/exp— don’t hand-roll them.
Common mistakes
Section titled “Common mistakes”- Using a short or guessable JWT secret.
- Storing password hashes in a column without
.nullable()(OAuth-only users have no password).
Related
Section titled “Related”- Sessions — token-based session lifecycle.
- OAuth & Providers — tokens from social login.
