nestjs-credentials
Token-agnostic username/password credential verification for NestJS: a UserStore seam, a pluggable PasswordHasher (zero-dependency scrypt default), and a fail-closed verify service. It validates who the user is — you mint whatever token you like.
ESM-only. Requires Node ≥ 20 and NestJS 10 / 11.
Pairs with
nestjs-jwt-guardandnestjs-oauth2-password: verify here, then issue the token there. This package issues nothing.
Install
npm install nestjs-credentialsNo runtime dependencies — the default hasher uses Node's built-in scrypt. @nestjs/common and reflect-metadata are peers (already in any Nest app).
Quick start
Register it with the only app-specific seam — how to find a user:
import { Module } from '@nestjs/common';
import { CredentialsModule } from 'nestjs-credentials';
import { UsersService } from './users.service';
@Module({
imports: [
CredentialsModule.register({
imports: [UsersModule],
inject: [UsersService],
// return a UserStore: { findByIdentifier(id) => user | null }
useFactory: (users: UsersService) => ({
findByIdentifier: (email) => users.findByEmail(email),
}),
// optional — defaults to (user) => user.passwordHash
getPasswordHash: (user) => user.password,
}),
],
})
export class AuthModule {}Verify credentials, then issue a token (e.g. with nestjs-jwt-guard):
import { CredentialsService } from 'nestjs-credentials';
import { JwtAuthService } from 'nestjs-jwt-guard';
constructor(
private readonly credentials: CredentialsService,
private readonly jwt: JwtAuthService,
) {}
async login(email: string, password: string) {
const user = await this.credentials.verify(email, password); // user | null
if (!user) throw new UnauthorizedException();
return { accessToken: await this.jwt.sign({ sub: user.id, role: user.role }) };
}Hash a password on registration:
const passwordHash = await this.credentials.hash(dto.password);Password hashing
The default ScryptPasswordHasher is zero-dependency (Node scrypt), timing-safe, and stores scrypt__INLINE_CODE_11__lt;salt>__INLINE_CODE_11__lt;key>. Swap in bcrypt/argon2 by implementing PasswordHasher:
import type { PasswordHasher } from 'nestjs-credentials';
import * as argon2 from 'argon2';
const argonHasher: PasswordHasher = {
hash: (plain) => argon2.hash(plain),
verify: (plain, stored) => argon2.verify(stored, plain),
};
CredentialsModule.register({ useFactory: () => userStore, hasher: argonHasher });Configuration
| Option | Default | Description |
|---|---|---|
useFactory |
— | Returns the UserStore (the only required, app-specific seam) |
imports / inject |
[] |
Wire providers into useFactory |
hasher |
ScryptPasswordHasher |
A PasswordHasher implementation |
getPasswordHash |
(u) => u.passwordHash |
Reads the stored hash off a user |
isGlobal |
true |
Register the module globally |
API
Module & service
| Export | Description |
|---|---|
CredentialsModule.register(options) |
Wires CredentialsService with your UserStore + optional hasher/getter. See Configuration. |
CredentialsService.verify(identifier, password) |
Look up + verify → the user, or null (fail-closed). |
CredentialsService.hash(password) |
Hash a plaintext password with the configured hasher (e.g. on registration). |
Hashing
| Export | Description |
|---|---|
ScryptPasswordHasher |
Default zero-dependency PasswordHasher (Node scrypt, timing-safe). |
PasswordHasher |
The { hash, verify } interface — implement it to plug in bcrypt/argon2. |
Advanced & types
| Export | Description |
|---|---|
USER_STORE, CREDENTIALS_OPTIONS |
DI tokens for the user store and resolved options. |
resolveCredentialsOptions(options) |
Merge options over the defaults → ResolvedCredentialsOptions. |
defaultGetPasswordHash |
The default getter, (user) => user.passwordHash. |
UserStore, CredentialsModuleOptions, ResolvedCredentialsOptions, PasswordHashGetter |
Supporting types. |
Related Projects
- nestjs-jwt-guard — bearer-JWT auth for NestJS (the token half — verify this, issue there).
- nestjs-oauth2-password — OAuth2 Password-grant token endpoint for NestJS (verify here, issue the token there).
- nestjs-accesscontrol — The official NestJS integration for AccessControl v3 (RBAC + ABAC).
- nestjs-http-envelope — A uniform, configurable response & error envelope for NestJS.
- nestjs-configuard — DB-backed, typed, ABAC-filtered runtime config for NestJS.
License
MIT Onur Yıldırım