This guide adds the change-password feature.
The change-password feature lets signed-in users update their password by providing their current password and a new password.
Prerequisites
Section titled “Prerequisites”- A project completed from Add magic link
Add the change password feature
Section titled “Add the change password feature”Add the feature
Run the CLI command:
brkpt auth add change-passwordThe CLI adds a new features/change-password/ folder.
Validate the DTO
The change password feature uses a fixed request shape. This guide has already enabled ValidationPipe, so add validation decorators to the generated DTO.
import { IsString, MinLength } from 'class-validator';
export class ChangeDto { @IsString() currentPassword!: string;
@IsString() @MinLength(6) newPassword!: string;}Implement ChangePasswordAdapter
The change password adapter finds the signed-in user from the access token payload, validates the current password, and updates the stored password.
Create change-password.adapter.ts:
Directorysrc/
Directorybrkpt-auth/
Directoryadapters/
- change-password.adapter.ts
import { Injectable } from '@nestjs/common';import * as bcrypt from 'bcrypt';
import { User } from '../../../generated/prisma/client';import { PrismaService } from '../../prisma/prisma.service';import { ChangePasswordPort } from '../features/change-password/change-password.port';import { AuthJwtPayload } from './types';
@Injectable()export class ChangePasswordAdapter implements ChangePasswordPort<User> { constructor(private readonly prisma: PrismaService) {}
findUserByJwtPayload(payload: AuthJwtPayload): Promise<User | null> { return this.prisma.user.findUnique({ where: { id: payload.sub, }, }); }
validatePassword(user: User, currentPassword: string): Promise<boolean> { return bcrypt.compare(currentPassword, user.password); }
async updatePassword(user: User, newPassword: string): Promise<void> { const password = await bcrypt.hash(newPassword, 10); await this.prisma.user.update({ where: { id: user.id }, data: { password }, }); }
extractUserIdFromJwtPayload(payload: AuthJwtPayload): number { return payload.sub; }}Register the feature
Update features.ts and pass ChangePasswordAdapter to changePasswordFeature:
import { BlacklistAdapter } from './adapters/blacklist.adapter';import { ChangePasswordAdapter } from './adapters/change-password.adapter';import { CoreAdapter } from './adapters/core.adapter';import { CredentialsAdapter } from './adapters/credentials.adapter';import { MagicLinkAdapter } from './adapters/magic-link.adapter';import { OAuthAdapter } from './adapters/oauth.adapter';import { OtpAdapter } from './adapters/otp.adapter';import { SessionAdapter } from './adapters/session.adapter';import { FeatureConfig } from './common/interfaces';import { blacklistFeature } from './features/blacklist/blacklist.feature';import { changePasswordFeature } from './features/change-password/change-password.feature';import { coreFeature } from './features/core/core.feature';import { credentialsFeature } from './features/credentials/credentials.feature';import { EmailMagicLinkDriver } from './features/magic-link/drivers/email.driver';import { magicLinkFeature } from './features/magic-link/magic-link.feature';import { GithubOAuthDriver } from './features/oauth/drivers/github.driver';import { GoogleOAuthDriver } from './features/oauth/drivers/google.driver';import { oauthFeature } from './features/oauth/oauth.feature';import { EmailOtpDriver } from './features/otp/drivers/email.driver';import { otpFeature } from './features/otp/otp.feature';import { sessionFeature } from './features/session/session.feature';
export const features: FeatureConfig[] = [ coreFeature(CoreAdapter), blacklistFeature(BlacklistAdapter), credentialsFeature(CredentialsAdapter), sessionFeature(SessionAdapter), oauthFeature(OAuthAdapter, GoogleOAuthDriver, GithubOAuthDriver), otpFeature(OtpAdapter, EmailOtpDriver), magicLinkFeature(MagicLinkAdapter, EmailMagicLinkDriver), changePasswordFeature(ChangePasswordAdapter),];Run and verify
Section titled “Run and verify”Start the application:
pnpm start:devnpm run start:devyarn start:devThe change-password feature adds one endpoint:
| Method | Path | Description |
|---|---|---|
POST |
/auth/change-password |
Change the signed-in user’s password |
Change the password
Use an access token from any sign-in method, then send the current password and the new password:
POST /auth/change-passwordAuthorization: Bearer <access-token>Content-Type: application/json
{ "currentPassword": "password", "newPassword": "123456"}A successful request changes the password for the signed-in user.
The current session remains active after the password is changed. If the session feature is enabled, other sessions for the same user are revoked.