npm.io
1.0.0 • Published 23h ago

nestjs-credentials

Licence
MIT
Version
1.0.0
Deps
0
Size
29 kB
Vulns
0
Weekly
0

nestjs-credentials

build coverage mutation score version zero dependencies ESM TypeScript license

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-guard and nestjs-oauth2-password: verify here, then issue the token there. This package issues nothing.

Install

npm install nestjs-credentials

No 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.

License

MIT Onur Yıldırım

Keywords