/opt/mawid/apps/api/src/auth
Edit: /opt/mawid/apps/api/src/auth/auth.service.ts (2047B)
import { ConflictException, Injectable, UnauthorizedException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import * as argon2 from 'argon2';
import type { LoginInput, RegisterInput } from '@mawid/shared';
import { PrismaService } from '../prisma/prisma.service';
export interface AuthResult {
accessToken: string;
user: { id: string; email: string; name: string; clinicId: string };
}
@Injectable()
export class AuthService {
constructor(
private readonly prisma: PrismaService,
private readonly jwtService: JwtService,
) {}
async register(input: RegisterInput): Promise
{
const existing = await this.prisma.user.findUnique({ where: { email: input.email } });
if (existing) throw new ConflictException('Email is already registered');
const passwordHash = await argon2.hash(input.password);
const user = await this.prisma.$transaction(async (tx) => {
const clinic = await tx.clinic.create({
data: { name: input.clinicName, phone: input.clinicPhone },
});
return tx.user.create({
data: {
clinicId: clinic.id,
email: input.email,
passwordHash,
name: input.name,
role: 'owner',
},
});
});
return this.issueToken(user);
}
async login(input: LoginInput): Promise {
const user = await this.prisma.user.findUnique({ where: { email: input.email } });
if (!user || !(await argon2.verify(user.passwordHash, input.password))) {
throw new UnauthorizedException('Invalid email or password');
}
return this.issueToken(user);
}
private async issueToken(user: {
id: string;
email: string;
name: string;
clinicId: string;
}): Promise {
const accessToken = await this.jwtService.signAsync({
sub: user.id,
clinicId: user.clinicId,
email: user.email,
});
return {
accessToken,
user: { id: user.id, email: user.email, name: user.name, clinicId: user.clinicId },
};
}
}