passwordField
A masked input whose value is hashed with bcrypt before it is stored.
import { passwordField } from 'nextjs-cms/core/fields'Basic usage
passwordField({ name: 'password' })The value is never stored in plain text: it's hashed with bcrypt (cost 10) on save.
With every option
passwordField({
name: 'password',
label: 'Portal password',
required: true,
order: 5,
placeholder: 'At least 12 characters',
minLength: 12,
maxLength: 72,
validation: {
regex: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).+$/,
message: 'Use upper- and lowercase letters and at least one number.',
},
})Options
| Option | Type | Default | Description |
|---|---|---|---|
placeholder | string | none | Hint in the empty input. |
minLength | number | none | Minimum length of the plain-text password. |
maxLength | number | none | Maximum length of the plain-text password. |
validation | { regex: RegExp; message: string } | none | Pattern the password must match. message is shown when it doesn't. |
Plus the common options. defaultValue and localized make no sense for passwords.
Options in detail
validation
Checked on the plain-text value, before hashing. The error reads <label>: <message>.
// At least one digit and one symbol
validation: {
regex: /^(?=.*\d)(?=.*[^A-Za-z0-9]).+$/,
message: 'Include at least one number and one symbol.',
}maxLength and bcrypt
bcrypt only uses the first 72 bytes of a password. Setting maxLength: 72 avoids passwords whose tail is silently ignored.
Use case: credentials for your website's users
A common use is a section of accounts that log in to your website (a members area, a partner portal):
sections/partners.section.ts
const email = textField({ name: 'email', required: true })
export default hasItemsSection({
name: 'partners',
order: 8,
title: { section: 'Partners', singular: 'Partner', plural: 'Partners' },
headingField: email,
db: { table: 'partners', unique: [{ columns: [email] }] },
fields: [email, passwordField({ name: 'password', required: true, minLength: 12 })],
})website/lib/auth.ts
import bcrypt from 'bcrypt'
import { eq } from 'drizzle-orm'
export async function verifyPartner(email: string, password: string) {
const [partner] = await db.select().from(PartnersTable).where(eq(PartnersTable.email, email)).limit(1)
if (!partner) return null
return (await bcrypt.compare(password, partner.password)) ? partner : null
}Good to know:
Admin accounts (the people who log in to the CMS) are not a section. They're managed on the built-in Admins page. See Admins & Permissions.
Storage
| Column | VARCHAR(255) CHARACTER SET utf8mb4 |
| Value | bcrypt hash, like $2b$10$N9qo8uLOickgx2ZMRZoMye... |