Nex.js에서 어떻게 Gihub Login을 할 수 있는지 작성해보았다.
프로필 -> settings -> Developer Settings -> OAuth Apps
Authorization callback URL은 github에서 로그인 후 어디로 돌아가는지 지정해주는 곳이다.
다 만들면 Client ID와 Client secrets을 얻을 수 있다. 얻은 다음 이 2가지를 .env 파일에 추가해주면 된다.
NEXT_PUBLIC_GITHUB_CLIENT_ID=
GITHUB_CLIENT_SECRET=
const Login = () => {
// github으로 로그인 code 받기
// 예) code=4bf42ada452ddda0e66d
const loginWithGithub = () => {
window.location.assign(
`https://github.com/login/oauth/authorize?client_id=${process.env.NEXT_PUBLIC_GITHUB_CLIENT_ID}`
);
};
return (
<button onClick={loginWithGithub}>login</button>
)
}
export default Login;
로그인 링크를 활용해서 로그인에 액세스 할 수 있다.
그러면 URL에 코드 매개변수가 생긴다.
http://localhost:3000/login?code=a70b2a78e6e9144241e8
이렇게 하면 코드 매개변수를 가져올 수 있다.
useEffect(() => {
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
const codeParam = urlParams.get("code");
console.log(codeParam);
}, []);
이제 이 code를 사용해서 github api와 통신해서 AccessToken을 얻을 수 있게된다.
api 폴더 안에 getAccessToken폴더를 생성한다.
url에서 code를 가져와 https://github.com/login/oauth/access_token
를 통해서 AccessToken를 호출한다.
그리고 가져온 AccessToken를 NextResponse
로 클라이언트에게 보내준다.
import { NextRequest, NextResponse } from 'next/server';
export const GET = async (request: NextRequest, response: NextResponse) => {
try {
const requestUrl = new URL(request.nextUrl);
const code = requestUrl.searchParams.get('code');
const baseUrl = 'https://github.com/login/oauth/access_token';
const config = {
client_id: process.env.NEXT_PUBLIC_GITHUB_CLIENT_ID || '',
client_secret: process.env.GITHUB_CLIENT_SECRET || '',
code: code || '',
};
const params = new URLSearchParams(config).toString();
const finalUrl = `${baseUrl}?${params}`;
const data = await fetch(finalUrl, {
method: 'POST',
headers: {
Accept: 'application/json',
},
});
const json = await data.json();
return new NextResponse(JSON.stringify(json), {
status: 200,
headers: {
'Access-Control-Allow-Origin': '*',
},
});
} catch (error) {
console.log(error);
return new NextResponse('Internal Server Error', { status: 500 });
}
};
api 폴더 안에 getUserData 폴더를 생성한다.
https://api.github.com/user
github api를 통해서 유저 데이터를 가져올 수 있다.
import { NextResponse, NextRequest } from 'next/server';
export const GET = async (request: NextRequest, response: NextResponse) => {
try {
// Authorization 헤더를 가져오기
const authorizationHeader = request.headers.get('Authorization');
console.log(authorizationHeader);
if (!authorizationHeader) {
return new NextResponse('Authorization header is missing', {
status: 401,
});
}
const data = await fetch('https://api.github.com/user', {
method: 'GET',
headers: {
Authorization: authorizationHeader,
},
});
const json = await data.json();
return new NextResponse(JSON.stringify(json), {
status: 200,
headers: {
'Access-Control-Allow-Origin': '*',
},
});
} catch (error) {
console.log(error);
return new NextResponse('Internal Server Error', { status: 500 });
}
};
"use client";
import axios from "axios";
import React, { useEffect, useState } from "react";
interface UserDataProps {
id: number;
login: string;
}
const Login = () => {
const [isRerender, setIsRerender] = useState(false);
const [userDate, setUserData] = useState<UserDataProps>({ id: 0, login: '' });
const token = typeof window !== 'undefined' && localStorage.getItem("accessToken");
// github으로 로그인 code 받기
// 예) code=4bf42ada452ddda0e66d
const loginWithGithub = () => {
window.location.assign(
`https://github.com/login/oauth/authorize?client_id=${process.env.NEXT_PUBLIC_GITHUB_CLIENT_ID}`
);
};
const getUserData = async () => {
const config = {
headers: {
Authorization: `Bearer ${token}`,
},
};
const userResponse = await axios.get(
`/api/getUserData`,
config
);
const user = userResponse.data;
setUserData(user);
};
useEffect(() => {
// url에 있는 code 가져오기
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
const codeParam = urlParams.get("code");
console.log(codeParam);
if (codeParam && token === null) {
const getAccessToken = async () => {
await fetch(
`/api/getAccessToken?code=${codeParam}`,
{ method: "GET" }
)
.then((response) => {
return response.json();
})
.then((data) => {
console.log(data);
if (data.access_token) {
localStorage.setItem("accessToken", data.access_token);
setIsRerender(!isRerender);
}
});
};
getAccessToken();
}
}, []);
return (
<div>
{typeof window !== "undefined" && localStorage.getItem("accessToken") ? (
<div>
<p>accessToken이 있습니다</p>
<button
onClick={() => {
typeof window !== "undefined" &&
localStorage.removeItem("accessToken");
setIsRerender(!isRerender);
}}
>
Log out
</button>
<div>
<p>Github User Data</p>
<button onClick={getUserData}>Get Data</button>
<div>
<p>ID: {userDate.login}</p>
</div>
</div>
</div>
) : (
<div>
<p>로그인 해주세요</p>
<button onClick={loginWithGithub}>login</button>
</div>
)}
</div>
);
};
export default Login;