[Dimelo Project] passport-github scope email이 없을 경우

Suyeon Pi·2022년 2월 24일
0

Dimelo

목록 보기
14/22

https://velog.io/@suyeonpi/Dimelo-Project-passport-local-google-github-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EA%B5%AC%ED%98%84-nest.js

이전 포스팅에서 나는 passport를 이용해서 github로그인을 구현하였다.

이전 코드 :

@Injectable()
export class GithubStrategy extends PassportStrategy(Strategy, 'github') {
  constructor(private authService: AuthService) {
    super({
      clientID: process.env.GITHUB_CLIENT_ID,
      clientSecret: process.env.GITHUB_SECRET,
      callbackURL: 'http://localhost:3000/api/auth/github/callback',
      scope: ['user:email'], // user의 email에 접근가능하는 권한
    });
  }

  async validate(
    _accessToken: string,
    _refreshToken: string,
    profile: any,
    done: VerifyCallback,
  ): Promise<any> {
    const { id, avatar_url, name, email } = profile._json;
// 깃헙에서 반환하는 profile._json에서 필요한 정보 빼서 새로운 객체 만듬
    const githubUser: GithubLoginUserDto = {
      githubId: +id,
      email,
      imageUrl: avatar_url,
    };
    const user = await this.authService.githubSignUp(githubUser);
// 새로운 만든 객체를 바탕으로 새로운 user 만들고 해당 user를 done해서 serialize한다
    done(null, user);
  }
}

깃허브에서 반환하는 profile에서 githubId, email, avatar_url을 이용해서 새로운 유저를 만들었다.
하지만 profile에서 email을 반환하지 않는 문제가 있었다.


알고보니 깃허브 세팅에서 public email을 설정하지 않으면 email을 반환하지 않는다는 것을 알았다..
나는 public email을 설정해놔서 당연히 이메일이 반환될줄 알았지만 새로 계정을 파서 public email을 설정하지 않고 로그인해보니 email을 반환하지 않아서 회원가입 로직에서 에러가 났다.

구글은 당연히 email을 반환하기 때문에 문제가 없었지만 github같은 경우는 email을 반환하지 않을 수도 있다. 그래서 회원가입 로직을 수정해야했다.

이메일이 없는 깃헙 로그인은 로그인 성공 후 이메일값을 받을까 했지만.. 빠른 회원가입을 원하는 유저가 Oauth로그인을 할 것이기 때문에 이중으로 이메일값을 또 검증하는 것은 빠른회원가입을 원하는 유저에게 불편할 것이라 생각들었다.

그래서 이메일이 없는 유저는 이메일을 Null로 받도록 하였다.
우리 사이트에서 email은 그렇게 중요한 요소가 아니기 때문이다. email은 단지 우리사이트에서 회원가입한 유저들을 위한 것이고 Oauth회원들은 email없이 로그인이 가능하다. 그리고 email이 없는 깃헙 유저는 githubId로 해당 유저를 조회할 수 있기 때문에 User의 email을 nullable로 수정하였다.

나중에 email이 없는 깃헙회원은 이메일을 등록하고 싶을때 프로필 수정페이지에서 이메일 연동기능? 을 만드는 것도 하나의 방법이라고 생각한다.


수정한 코드 :

// github.strategy.ts
  async validate(
    _accessToken: string,
    _refreshToken: string,
    profile: any,
    done: VerifyCallback,
  ): Promise<any> {
    const { id, avatar_url, email } = profile._json;
    const githubUser: GithubLoginUserDto = {
      githubId: +id,
      email: email ? email : null, // 이메일이 없을 경우 null
      imageUrl: avatar_url,
    };
    const user = await this.authService.githubSignUp(githubUser);
    done(null, user);
  }
async githubSignUp(user: GithubLoginUserDto) {
   const foundGithub = await this.usersRepository.findOne({
     where: { email: user.email, githubId: user.githubId, deletedAt: null },
     select: ['id', 'email', 'nickname', 'imageUrl'],
   });

   if (foundGithub) {
     return foundGithub;
   }

   if (user.email) {
     // 이메일이 있는 경우, 유저테이블에 같은 이메일이 있는 경우 깃허브 아이디 연동
     const found = await this.usersRepository.findOne({
       where: { email: user.email, deletedAt: null },
     });

     if (found) {
       found.githubId = user.githubId;
       const { id, email, nickname, imageUrl } =
         await this.usersRepository.save(found);
       return {
         id,
         email,
         nickname,
         imageUrl,
       };
     }
   }

   const { id, email, nickname, imageUrl } = await this.usersRepository.save(
     user,
   );
   return { id, email, nickname, imageUrl };
 }
profile
Stay hungry, Stay foolish!

0개의 댓글