Github Authentication

Odyssey·2025년 4월 9일

Next.js_study

목록 보기
45/58
post-thumbnail

2025.4.9 수요일의 공부기록

이 글에서는 Next.js 환경에서 GitHub 계정을 이용해 로그인(OAuth)을 구현하는 방법을 단계별로 상세히 설명한다.


GitHub OAuth 앱 등록하기

GitHub 로그인을 구현하려면 먼저 GitHub에 OAuth 앱을 등록해야 한다.

항목예시
Application namemy-app (자유롭게 설정)
Homepage URLhttp://localhost:3000
Authorization callback URLhttp://localhost:3000/github/complete

등록이 완료되면 Client IDClient Secret을 발급받게 된다.

이 값은 .env 파일에 다음과 같이 저장하여 안전하게 관리한다.

GITHUB_CLIENT_ID=발급받은_클라이언트_ID
GITHUB_CLIENT_SECRET=발급받은_클라이언트_SECRET

OAuth 권한 부여 및 Scope 설정

GitHub OAuth는 앱에 허용할 권한(scope)을 설정할 수 있다.
자주 쓰이는 권한은 다음과 같다.

Scope설명
read:user사용자 프로필 읽기
user:email사용자의 이메일 주소 접근
repo사용자의 저장소 접근

전체 OAuth scope 목록을 참조하여 필요한 권한만 설정하도록 한다.


GitHub OAuth 흐름 간단 정리

OAuth 로그인 흐름은 다음과 같은 순서로 진행된다.

  1. 사용자가 로그인 버튼 클릭 시 GitHub 로그인 페이지로 리다이렉트된다.
  2. GitHub에서 사용자가 로그인과 권한을 승인하면 설정된 콜백 URL로 인증 코드(code)를 보낸다.
  3. 앱은 이 인증 코드를 사용해 GitHub에서 액세스 토큰(access token)을 얻는다.
  4. 얻은 액세스 토큰을 사용하여 GitHub API를 호출하여 사용자 정보를 얻는다.

📌 GitHub OAuth 흐름 문서


Next.js Route Handlers로 OAuth 구현하기

Next.js의 Route Handlers를 활용하면 서버측에서 손쉽게 OAuth 처리를 구현할 수 있다.
HTTP 메서드(GET, POST 등)를 다루는 별도의 API 엔드포인트를 설정한다.

/github/start (로그인 시작)

app/github/start/route.ts

export function GET() {
  const baseUrl = "https://github.com/login/oauth/authorize";
  const params = {
    client_id: process.env.GITHUB_CLIENT_ID!,
    scope: "read:user user:email",
    allow_signup: "true",
  };

  const formattedParams = new URLSearchParams(params).toString();
  const finalUrl = `${baseUrl}?${formattedParams}`;

  return Response.redirect(finalUrl);
}

/github/complete (로그인 완료 후 처리)

app/github/complete/route.ts

import db from "@/lib/db";
import { getSession } from "@/lib/session";
import { notFound, redirect } from "next/navigation";
import { NextRequest } from "next/server";

export async function GET(request: NextRequest) {
  const code = request.nextUrl.searchParams.get("code");

  if (!code) {
    return notFound();
  }

  // 액세스 토큰 요청
  const accessTokenParams = new URLSearchParams({
    client_id: process.env.GITHUB_CLIENT_ID!,
    client_secret: process.env.GITHUB_CLIENT_SECRET!,
    code,
  }).toString();

  const accessTokenURL = `https://github.com/login/oauth/access_token?${accessTokenParams}`;

  const accessTokenResponse = await fetch(accessTokenURL, {
    method: "POST",
    headers: { Accept: "application/json" },
  });

  const { error, access_token } = await accessTokenResponse.json();

  if (error) {
    return new Response("OAuth 인증 오류 발생", { status: 400 });
  }

  // 사용자 프로필 정보 요청
  const userProfileResponse = await fetch("https://api.github.com/user", {
    headers: {
      Authorization: `Bearer ${access_token}`,
    },
  });

  const { id, avatar_url, login } = await userProfileResponse.json();

  // GitHub 사용자 ID로 기존 사용자 조회
  let user = await db.user.findUnique({
    where: { github_id: id.toString() },
    select: { id: true },
  });

  // 신규 가입인 경우
  if (!user) {
    user = await db.user.create({
      data: {
        github_id: id.toString(),
        avatar: avatar_url,
        username: login, // 중복 방지를 위한 별도의 처리 필요 (ex. 고유한 접두사 추가)
      },
      select: { id: true },
    });
  }

  // 세션 생성 후 로그인 처리
  const session = await getSession();
  session.userId = user.id;
  await session.save();

  return redirect("/profile");
}

OAuth 인증 코드 오류 처리

OAuth 인증 코드를 재사용하거나 시간이 지나 만료된 코드를 사용할 경우 다음과 같은 오류가 발생한다.

{
  "error": "bad_verification_code",
  "error_description": "The code passed is incorrect or expired."
}

이 오류를 해결하려면 다시 GitHub OAuth 프로세스를 시작하여 새로운 인증 코드를 받아와야 한다.

OAuth 인증 코드 오류 문서 참고


Next.js 15 버전에서 fetch 기본 캐싱 변경사항

Next.js 15부터 fetch의 기본 캐시 옵션이 변경되었다.

  • 이전(15 이전): 기본값 force-cache (캐싱됨)
  • 현재(15 이상): 기본값 no-store (캐싱되지 않음)

따라서 별도 캐싱 옵션을 설정하지 않아도 최신 데이터를 즉시 받아오게 된다.

Next.js 15 fetch 문서


정리

  • GitHub OAuth로 로그인 기능을 구현하기 위해 앱을 등록하고 인증 과정을 설정한다.
  • Next.js의 Route Handlers를 활용하여 OAuth를 깔끔하게 처리할 수 있다.
  • 인증 코드 오류 등 OAuth 프로세스 중 발생할 수 있는 문제와 해결법을 숙지한다.
  • OAuth 로그인 시 사용자 이름 중복 방지 등 추가적인 처리가 필요하다.

0개의 댓글