Skip to content

Instantly share code, notes, and snippets.

@Taofiqq
Created December 31, 2024 20:01
Show Gist options
  • Save Taofiqq/7fc55e30e17f8bc171aa5ccaf35cf592 to your computer and use it in GitHub Desktop.
Save Taofiqq/7fc55e30e17f8bc171aa5ccaf35cf592 to your computer and use it in GitHub Desktop.
A gist for Auth Module - Multi Tenant E-commerce API
import { Controller, Post, Body } from '@nestjs/common';
import { AuthService } from './auth.service';
import { LoginDto } from './dto/login.dto';
import { RegisterTenantDto } from './dto/register-tenant.dto';
@Controller('auth')
export class AuthController {
constructor(private readonly authService: AuthService) {}
@Post('register-tenant')
registerTenant(@Body() registerTenantDto: RegisterTenantDto) {
return this.authService.registerTenant(registerTenantDto);
}
@Post('login')
login(@Body() loginDto: LoginDto) {
return this.authService.login(loginDto);
}
}
import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport';
import { JwtStrategy } from './jwt.strategy';
import { UsersModule } from '../users/users.module';
import { TenantModule } from '../tenants/tenant.module';
import { ConfigModule, ConfigService } from '@nestjs/config';
@Module({
imports: [
UsersModule,
TenantModule,
PassportModule,
JwtModule.registerAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (configService: ConfigService) => ({
secret: configService.get<string>('jwt.secret'),
signOptions: { expiresIn: configService.get<string>('jwt.expiration') },
}),
}),
],
providers: [AuthService, JwtStrategy],
controllers: [AuthController],
exports: [AuthService],
})
export class AuthModule {}
import { Injectable, UnauthorizedException } from '@nestjs/common';
import * as bcrypt from 'bcrypt';
import { UsersService } from '../users/users.service';
import { TenantService } from '../tenants/tenant.service';
import { RegisterTenantDto } from './dto/register-tenant.dto';
import { LoginDto } from './dto/login.dto';
import { JwtService } from '@nestjs/jwt';
import { PermitService } from '../permit/permit.service';
@Injectable()
export class AuthService {
constructor(
private readonly usersService: UsersService,
private readonly tenantService: TenantService,
private readonly jwtService: JwtService,
private readonly permitService: PermitService,
) {}
async registerTenant(registerTenantDto: RegisterTenantDto) {
const tenant = await this.tenantService.create({
name: registerTenantDto.tenantName,
domain: registerTenantDto.domain,
});
const user = await this.usersService.create({
email: registerTenantDto.adminEmail,
password: registerTenantDto.adminPassword,
firstName: registerTenantDto.adminFirstName,
lastName: registerTenantDto.adminLastName,
role: 'ADMIN',
tenantId: tenant.id,
});
const permit = this.permitService.getClient();
await permit.user.create({
key: user.id,
email: user.email,
first_name: user.firstName,
last_name: user.lastName,
role_assignments: [{ role: 'ADMIN', tenant: tenant.permitKey }],
});
return { tenant, user };
}
async login(loginDto: LoginDto) {
const user = await this.usersService.findByEmail(loginDto.email);
if (!user || !(await bcrypt.compare(loginDto.password, user.password))) {
throw new UnauthorizedException('Invalid credentials');
}
const tenant = await this.tenantService.findById(user.tenantId);
const payload = { sub: user.id, role: user.role, tenantId: user.tenantId };
return {
access_token: this.jwtService.sign(payload),
user,
tenant,
};
}
}
import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {}
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { ConfigService } from '@nestjs/config';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(private configService: ConfigService) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: configService.get<string>('jwt.secret'),
});
}
async validate(payload: any) {
return { id: payload.sub, role: payload.role, tenantId: payload.tenantId };
}
}
import { IsEmail, IsString } from 'class-validator';
export class LoginDto {
@IsEmail()
email: string;
@IsString()
password: string;
}
import { IsEmail, IsString } from 'class-validator';
export class RegisterTenantDto {
@IsString()
tenantName: string;
@IsString()
domain: string;
@IsString()
adminFirstName: string;
@IsString()
adminLastName: string;
@IsEmail()
adminEmail: string;
@IsString()
adminPassword: string;
}
import { SetMetadata } from '@nestjs/common';
export const PERMISSION_KEY = 'permission';
export const RequirePermission = (action: string, resource: string) =>
SetMetadata(PERMISSION_KEY, { action, resource });
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment