DDD approach for user authentication and registration

2 weeks ago 18
ARTICLE AD BOX

I’m using a DDD approach in my application. I want to learn best practices for writing DDD code the way Big Tech companies and experienced developers do it.

So, I have a User entity with the following properties: firstName, lastName, middleName (optional), email, password, phone, emailVerified, phoneVerified.

I’m planning for my users to be able to authenticate either via email + password or via phone with an OTP code. The question is: what should the User entity look like?

From the perspective of registering with email + password, the user doesn’t need to enter a phone number because that field isn’t needed for that registration method. And vice versa: when registering by phone, the user doesn’t provide email and password.

I can create the User class as described below:

export class User { id: UserId firstName: FirstName lastName: LastName middleName?: MiddleName email?: Email password?: Password // or passwordHash?: PasswordHash emailVerified?: boolean phone?: Phone phoneVerified?: boolean constructor(id: UserId, firstName: FirstName, lastname: LastName, middleName?: MiddleName, email?: Email, password?: Password, emailVerified?: boolean, phone?: Phone, phoneVerified?: boolean) { this.id = id this.firstName = firstName this.lastName = lastName this.middleName = middleName this.email = email this.password = password this.emailVerified = emailVerified this.phone = phone this.phoneVerified = phoneVerified } static registerByEmail(params: {id: UserId, firstName: FirstName, lastName: LastName, middleName?: MiddleName, email: Email, password: Password}) { return new User(params.id, params.firstName, params.lastName, params.middleName, params.email, params.password, false, undefined, false) } }

I also have another implementation:

type AuthMethod = | { kind: "email", email: Email, password: Password, emailVerified: boolean } | { kind: "phone", phone: Phone, phoneVerified: boolean } interface UserProps { id: UserId firstName: FirstName lastname: LastName middleName?: MiddleName authMethod: AuthMethod } export class User { id: UserId firstName: FirstName lastName: LastName middleName?: MiddleName authMethod: AuthMethod constructor(props: UserProps) { this.id = props.id this.firstName = props.firstName this.lastName = props.lastName this.middleName = props.middleName this.authMethod = props.authMethod } static registerByEmail(params: { id: UserId; fullName: FullName; email: Email; password: Password}) { return new User({ id: params.id, fullName: params.fullName, authMethod: { kind: 'email', email: params.email, password: params.password, emailVerified: false, } }); } }

I want to learn the correct solution from the community and find examples of similar implementations. I would be very grateful for advice from experienced developers who work on Big Tech projects.

Read Entire Article