| name | bcrypt |
|---|---|
| description | Use this skill when working with BCrypt password hashing in ColdBox/BoxLang applications. Covers installation, work-factor configuration, hashing passwords, verifying credentials, generating salts, mixin helpers in handlers/interceptors, user registration, authentication, password change/reset, and security best practices for credential handling. |
| applyTo | **/*.{bx,cfc,cfm,bxm} |
Load this skill when:
- Hashing passwords before storing in the database
- Verifying user credentials during authentication
- Implementing user registration or password change flows
- Configuring work factor / cost factor for security tuning
- Using BCrypt mixin helpers in handlers and views
- Migrating plain-text or MD5/SHA passwords to BCrypt
Examples use BoxLang (.bx) syntax. Adapt as needed:
| Concept | BoxLang (.bx) |
CFML (.cfc) |
|---|---|---|
| Class declaration | class { |
component { |
| DI annotation | @inject above property |
property name="x" inject="y"; |
box install bcrypt// config/ColdBox.cfc — optional, default workFactor = 12
moduleSettings = {
bcrypt = {
workFactor = 12 // range 4–31; higher = slower but more secure
}
}Security note: BCrypt cost factor 12 takes ~250 ms per hash on modern hardware. Increase to 14–15 for high-value accounts. Never go below 10 in production.
// BoxLang / CFML script
property name="bcrypt" inject="@bcrypt";Mixin helpers are available automatically in ColdBox handlers, interceptors, layouts, and views:
bcryptHash( password [, workFactor] )bcryptCheck( candidate, hash )bcryptSalt( [workFactor] )
// Default work factor
var hash = bcrypt.hashPassword( "SecurePass123!" )
// Custom work factor
var hash = bcrypt.hashPassword(
password = "SecurePass123!",
workFactor = 14
)
// Result: $2a$14$... (60-character BCrypt hash)var isValid = bcrypt.checkPassword(
candidate = plaintextPassword,
bCryptHash = storedHash
)
// Always compare in constant time — never compare hashes directly with ==var salt = bcrypt.generateSalt( 12 ) // explicit work factorclass UserService {
@inject
property name="userDAO";
@inject("@bcrypt")
property name="bcrypt";
function register( required struct data ) {
// NEVER store plaintext passwords
data.password = bcrypt.hashPassword( data.password )
return userDAO.create( data )
}
}class AuthService {
@inject
property name="userDAO";
@inject("@bcrypt")
property name="bcrypt";
function authenticate( required string username, required string password ) {
var user = userDAO.findByUsername( username )
// Use same error message for missing vs wrong password — no user enumeration
if ( isNull( user ) || !bcrypt.checkPassword( password, user.getPassword() ) ) {
throw( type = "InvalidCredentials", message = "Invalid username or password" )
}
return user
}
}function changePassword(
required numeric userId,
required string currentPassword,
required string newPassword
) {
var user = userDAO.findOrFail( userId )
if ( !bcrypt.checkPassword( currentPassword, user.getPassword() ) ) {
throw( type = "InvalidPassword", message = "Current password is incorrect" )
}
user.setPassword( bcrypt.hashPassword( newPassword ) )
user.save()
}function resetPassword( required string token, required string newPassword ) {
var record = tokenDAO.findValidToken( token )
if ( isNull( record ) || record.getExpiresAt() < now() ) {
throw( type = "InvalidToken", message = "Reset token is invalid or expired" )
}
var user = userDAO.find( record.getUserId() )
user.setPassword( bcrypt.hashPassword( newPassword ) )
user.save()
tokenDAO.invalidate( token ) // one-time use
}- Never store or log plaintext passwords — only store the BCrypt hash
- Use work factor 12+ in production; re-evaluate every 1–2 years
- Avoid user enumeration — return the same error for wrong username AND wrong password
- Rate-limit login attempts — BCrypt slows individual hashes but not brute-force at scale
- Upgrade legacy hashes on login — if a user logs in with an old MD5 hash, re-hash with BCrypt before saving
- Do not use
==to compare hashes — always usebcrypt.checkPassword()
- BCrypt module: https://github.com/coldbox-modules/bcrypt