OAuth 2.0 로그인 동작 과정 정리

  1. 클라이언트에서 API ID, 콜백 경로를 담아서 네이버/카카오 로그인 페이지로 GET 요청을 보낸다
  1. 사용자가 네이버/카카오 로그인 페이지에서 로그인을 진행한다

  2. 네이버/카카오에서 콜백 또는 redirect_uri로 인가 코드를 담아 GET 요청을 보낸다

  3. NaverStrategy, KakaoStrategy에서 자동으로 인가 코드를 담아 네이버/카카오 인증 서버에 요청을 보내 액세스 토큰, 리프레시 토큰, 프로필 정보를 응답 받는다.

  4. 응답 받은 프로필 정보를 각 Strategy의 validate에서 User에 담아 return한다

  5. Controller에 있는 naverSignIn, kakaoSignIn에서 GetUser를 통해 validate에서 전달된 네이버/카카오 사용자(user)의 정보를 얻는다

  6. Service에 있는 naverSignIn, kakaoSignIn에서 다음의 동작을 수행한다

  1. 로그인 API처럼 클라이언트에게 201 Created를 응답하고 Body에 액세스 토큰을 담아 응답한다

두 OAuth 로그인을 다음의 과정으로 구현하면 클라이언트 입장에서는 1번에 써있는 요청 하나만으로 로그인 API와 동일한 결과를 얻을 수 있습니다.

소셜 로그인 여부 칼럼의 추가 등 엔티티의 변경이 있어도 Strategy에서 담는 User의 정보에 해당 칼럼 값을 True로 변경만 하면 되고, 추가적으로 일반 사용자에게 해당 칼럼값을 False로 설정만 해주면 됩니다.

import {
  Entity,
  Column,
  PrimaryGeneratedColumn,
  CreateDateColumn,
  UpdateDateColumn,
  DeleteDateColumn,
  BaseEntity,
  OneToMany,
  Unique,
} from "typeorm";
import { premiumStatus, providerEnum } from "src/utils/enum";
import { Diary } from "../diaries/diaries.entity";
import { Shape } from "src/shapes/shapes.entity";

@Entity()
@Unique(["userId"])
export class User extends BaseEntity {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ length: 60 })
  userId: string;

  @Column()
  email: string;

  @Column({ length: 60 })
  password: string;

  @Column({ length: 20 })
  nickname: string;

  @Column({ default: 0 })
  credit: number;

  @Column({ type: "enum", enum: premiumStatus, default: premiumStatus.FALSE })
  premium: premiumStatus;

  @CreateDateColumn({ type: "datetime" })
  createdDate: Date;

  @UpdateDateColumn({ type: "datetime" })
  updatedDate: Date;

  @DeleteDateColumn({ type: "datetime" })
  deletedDate: Date;

  @Column({ type: "enum", enum: providerEnum, default: providerEnum.BYEOLSOOP })
  provider: providerEnum;

  @OneToMany(() => Diary, (diary) => diary.user)
  diaries: Diary[];

  @OneToMany(() => Shape, (shape) => shape.user)
  shapes: Diary[];
}