nestjs google, kakao Oauth

yy·2024년 5월 13일

사실 두개의 코드가 같아서 하나만 해결하면 다른 로그인은 쉽다.


1. 설치 명령어

//구글 oauth 
npm i @nestjs/passport passport passport-google-oauth20

//카카오 oauth 
npm i @nestjs/passport passport passport-kakao @types/passport-kakao

2. app.module.ts

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { AuthController } from './auth/auth.controller';
import { AuthModule } from './auth/auth.module';
import { ConfigModule } from '@nestjs/config';

@Module({
  imports: [ConfigModule.forRoot(), AuthModule],
  controllers: [AppController, AuthController],
  providers: [AppService],
})
export class AppModule {}

3. auth.controller.ts

import { Controller, Get, UseGuards, Res, Req } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

@Controller('auth')
export class AuthController {
  /* 구글 */
  @Get('google')
  @UseGuards(AuthGuard('google'))
  async googleLogin() { }

  @Get('google/callback')
  @UseGuards(AuthGuard('google'))
  async googleLoginCallback(@Req() req, @Res() res) {
    const jwt: string = req.user.jwt;
    if (jwt) res.redirect('http://localhost:3005/login/success/' + jwt);
    else res.redirect('http://localhost:3005/login/failure');
  }

  // google 에서 kakao로만 수정됐을뿐 달라진건 없다.
  /* 카카오 */
  @Get('kakao')
  @UseGuards(AuthGuard('kakao'))
  async kakaoLogin() { }

  @Get('kakao/callback')
  @UseGuards(AuthGuard('kakao'))
  async kakaoLoginCallback(@Req() req, @Res() res) {
    const jwt: string = req.user.jwt;
    if (jwt) res.redirect('http://localhost:3005/login/success/' + jwt);
    else res.redirect('http://localhost:3005/login/failure');
  }

  // 얘는 하나만 있어도 되는 모양.
  @Get('protected')
  @UseGuards(AuthGuard('jwt'))
  protectedResource() {
    return 'JWT is working!';
  }
}

4. strategty

//src/strategies/google.strategy.ts
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { PassportStrategy } from '@nestjs/passport';
import { Strategy } from 'passport-google-oauth20';

@Injectable()
export class GoogleStrategy extends PassportStrategy(Strategy, 'google') {
  constructor(private readonly configService: ConfigService) {
    super({
      clientID: configService.get('GOOGLE_CLIENT_ID'),
      clientSecret: configService.get('GOOGLE_CLIENT_SECRET'),
      callbackURL: configService.get('GOOGLE_CALLBACKURL'),
      passReqToCallback: true,
      scope: ['profile'], // 가져올 정보들
    });
  }

  async validate(
    request: any,
    accessToken: string,
    refreshToken: string,
    profile,
    done: any,
  ) {
    try {
      console.log(profile);

      const jwt = 'placeholderJWT';
      const user = {
        jwt,
      };
      done(null, user);
    } catch (err) {
      console.error(err);
      done(err, false);
    }
  }
}

//src/strategies/kakao.strategy.ts
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { PassportStrategy } from '@nestjs/passport';
import { Profile, Strategy } from 'passport-kakao';

@Injectable()
export class KakaoStrategy extends PassportStrategy(Strategy) {
  constructor(private readonly configService: ConfigService) {
    super({
      clientID: configService.get('KAKAO_CLIENT_ID'),
      clientSecret: configService.get('KAKAO_CLIENT_SECRET'),
      callbackURL: configService.get('KAKAO_CALLBACK_URL'),
    });
  }

  async validate(
    accessToken: string,
    refreshToken: string,
    profile: Profile,
    done: (error: any, user?: any, info?: any) => void,
  ) {
    try {
      const jwt = 'placeholderJWT';
      const user = {
        jwt,
      };
      done(null, user);
    } catch (error) {
      done(error);
    }
  }
}

5. auth.module.ts

import { Module } from '@nestjs/common';
import { AuthController } from './auth.controller';
import { PassportModule } from '@nestjs/passport';
import { GoogleStrategy } from 'src/strategies/google.strategy';
import { ConfigModule } from '@nestjs/config';
import { KakaoStrategy } from 'src/strategies/kakao.strategy';

@Module({
  imports: [PassportModule.register({ defaultStrategy: 'jwt' }), ConfigModule],
  controllers: [AuthController],
  providers: [GoogleStrategy, KakaoStrategy], 
})
export class AuthModule { }

주의사항

  1. providers: [GoogleStrategy, KakaoStrategy]를 안넣어주면 Error: Unknown authentication strategy "google"가 발생한다.

  1. redirectUrl 작성 시 홈페이지와 .env에 내용과 동일하게 적어야함.(당연함)

  1. 카카오 KAKAO_CLIENT_ID

  1. 카카오 KAKAO_CLIENT_SECRET







참고 블로그
https://velog.io/@jinony/Nest.js%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-OAuth-2.0-%EA%B5%AC%ED%98%84
https://velog.io/@leemhoon00/Nestjs-JWT-%EC%9D%B8%EC%A6%9D-%EA%B5%AC%ED%98%84

profile
시간이 걸릴 뿐 내가 못할 건 없다.

0개의 댓글