-
-
Save muneneevans/23771ab5ab0e141f947003c24c7eadf3 to your computer and use it in GitHub Desktop.
Authentication in Nestjs using JWT and Local strategires
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# src/api/auth/passport/jwt.strategy.ts | |
import { ExtractJwt, Strategy } from 'passport-jwt'; | |
import { PassportStrategy } from '@nestjs/passport'; | |
import { Injectable } from '@nestjs/common'; | |
import { ConfigService } from 'src/api/config/config.service'; | |
import { UsersProvider } from 'src/api/users/users.provider'; | |
import { JwtService } from '@nestjs/jwt'; | |
@Injectable() | |
export class JwtStrategy extends PassportStrategy(Strategy) { | |
constructor( | |
private readonly configService: ConfigService, | |
private readonly usersProvider: UsersProvider, | |
private readonly jwtService: JwtService, | |
) { | |
super({ | |
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), | |
ignoreExpiration: true, | |
secretOrKey: configService.getJWTSecret(), | |
}); | |
} | |
async validate(payload: any) { | |
const accessToken = this.jwtService.sign(payload); | |
if (await this.usersProvider.validateToken(accessToken, payload.sub)) { | |
return { userId: payload.sub, username: payload.username }; | |
} else { | |
throw new Error('Token validation error.'); | |
} | |
} | |
} | |
# src/api/auth/passport/local.strategy.ts | |
import { Strategy } from 'passport-local'; | |
import { PassportStrategy } from '@nestjs/passport'; | |
import { | |
Injectable, | |
UnauthorizedException, | |
BadRequestException, | |
} from '@nestjs/common'; | |
import { AuthProvider } from '../auth.provider'; | |
@Injectable() | |
export class LocalStrategy extends PassportStrategy(Strategy) { | |
constructor(private readonly authProvider: AuthProvider) { | |
super({ passReqToCallback: true }); | |
} | |
async validate(payload: any): Promise<any> { | |
const request = payload; | |
if (request.body && request.body.username && request.body.password) { | |
const user = await this.authProvider.validateUser( | |
request.body.username, | |
request.body.password, | |
); | |
if (!user) { | |
throw new UnauthorizedException(); | |
} | |
return user; | |
} else { | |
throw new BadRequestException(); | |
} | |
} | |
} | |
# src/api/auth/auth.module.ts | |
import { Module } from '@nestjs/common'; | |
import { AuthProvider } from './auth.provider'; | |
import { PassportModule } from '@nestjs/passport'; | |
import { JwtModule } from '@nestjs/jwt'; | |
import { JwtStrategy } from './passport/jwt.strategy'; | |
import { UserEntity } from 'src/implementations/entities/user.entity'; | |
import { TypeOrmModule } from '@nestjs/typeorm'; | |
import { ConfigModule } from '../config/config.module'; | |
import { ConfigService } from '../config/config.service'; | |
import { AuthController } from './auth.controller'; | |
import { UsersModule } from '../users/users.module'; | |
import { LocalStrategy } from './passport/local.strategy'; | |
@Module({ | |
imports: [ | |
ConfigModule, | |
TypeOrmModule.forFeature([UserEntity]), | |
PassportModule.register({ defaultStrategy: 'jwt' }), | |
JwtModule.registerAsync({ | |
imports: [ConfigModule], | |
useFactory: async (configService: ConfigService) => ({ | |
secret: configService.getJWTSecret(), | |
}), | |
inject: [ConfigService], | |
}), | |
UsersModule, | |
], | |
providers: [AuthProvider, JwtStrategy, LocalStrategy], | |
controllers: [AuthController], | |
exports: [AuthProvider], | |
}) | |
export class AuthModule {} | |
# src/api/auth/auth.controller.ts | |
import { | |
Controller, | |
Request, | |
Post, | |
UseGuards, | |
HttpException, | |
HttpStatus, | |
} from '@nestjs/common'; | |
import { AuthGuard } from '@nestjs/passport'; | |
import { AuthProvider } from './auth.provider'; | |
import { loggerService } from 'src/main'; | |
@Controller('auth') | |
export class AuthController { | |
constructor(private readonly authProvider: AuthProvider) {} | |
@UseGuards(AuthGuard('local')) | |
@Post('login') | |
async login(@Request() req: any) { | |
try { | |
return this.authProvider.login(req.user); | |
} catch (error) { | |
const errMsg = `There was a error logging in. Error: ${error}.`; | |
loggerService.error(errMsg); | |
throw new HttpException(errMsg, HttpStatus.UNAUTHORIZED); | |
} | |
} | |
@UseGuards(AuthGuard('jwt')) | |
@Post('logout') | |
async logout(@Request() req: any) { | |
try { | |
return this.authProvider.logout(req.user.userId); | |
} catch (error) { | |
const errMsg = `There was a error logging out. Error: ${error}.`; | |
loggerService.error(errMsg); | |
throw new HttpException(errMsg, HttpStatus.INTERNAL_SERVER_ERROR); | |
} | |
} | |
} | |
# src/api/auth/auth.provider.ts | |
import { Injectable } from '@nestjs/common'; | |
import { UsersProvider } from '../users/users.provider'; | |
import { JwtService } from '@nestjs/jwt'; | |
@Injectable() | |
export class AuthProvider { | |
constructor( | |
private readonly usersProvider: UsersProvider, | |
private readonly jwtService: JwtService, | |
) {} | |
public async validateUser(username: string, pass: string): Promise<any> { | |
return this.usersProvider.validateCredentials(username, pass); | |
} | |
public async login(user: any) { | |
const payload = { username: user.username, sub: user.id }; | |
const accessToken = this.jwtService.sign(payload); | |
await this.usersProvider.saveToken(accessToken, user.id); | |
return { | |
accessToken, | |
}; | |
} | |
public async logout(userId: number): Promise<boolean> { | |
return this.usersProvider.removeToken(userId); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment