41일차 Node.js

정상희·2025년 5월 21일

코딩공부

목록 보기
51/60

현재 오즈코딩스쿨 강의를 통해 프론트엔드를 학습하고 있습니다.
본 포스트는 해당 강의에 대한 내용 정리를 목적으로 합니다.

OAuth 2.0

OAuth는 사용자의 비밀번호를 직접 공유하지 않고도 제3자 애플리케이션이 사용자 자원에 접근할 수 있도록 허용하는 인증 및 권한 부여 프로토콜이다.
OAuth는 보안성과 편의성을 동시에 확보하기 위한 수단이다. ID와 비밀번호를 직접 입력받는 대신, 권한을 위임하는 방식으로 작동하므로 사용자의 개인정보 유출 위험을 줄일 수 있다.

용어설명
Resource Owner리소스를 소유한 사용자이다.
Client사용자 대신 API에 접근하려는 제3자 애플리케이션이다.
Authorization Server인증을 처리하고 Access Token을 발급하는 서버이다.
Resource Server보호된 리소스를 보관하고, Access Token을 통해 접근을 허용하는 서버이다.
Access Token일정한 권한과 유효기간을 가진 인증 토큰이다.


1. OAuth 2.0 Kakao

1) 모듈설치

npm init -y
npm i express cors axios

node server 서버 확인(터미널)

2) 카카오 디벨로퍼 설정

  • 카카오 디벨로퍼

  • 애플리케이션 추가


  • 설정 > 카카오 로그인 ON


  • Redirect URI 입력


  • 동의 항목 설정

-앱 설정 > 앱 키 > REST API 키 사용

  • 비즈니스 인증 > 보안 > Client Secret

  • 문서 > 카카오 로그인 > REST API

  • 인가 코드

  • 토큰 받기

  • 사용자 정보 가져오기

  • 로그아웃

  • 문제점 error_code:'KOE320'

    .then이 하나가 빠짐...ㅠㅠ

axios.post('http://localhost:3000/kakao/login', {authorizationCode})
    .then((res) => { // 첫 번째 .then(): 인가 코드를 서버로 보내고 Access Token을 받는 단계
        console.log(res); // 서버 응답 전체를 콘솔에 출력 (디버깅에 유용)
        kakaoAccessToken = res.data; // 서버 응답 데이터를 kakaoAccessToken 변수에 할당.
                                     // 만약 서버가 { accessToken: '...' } 형태로 응답한다면 res.data.accessToken으로 접근해야 합니다.
        return axios.post('http://localhost:3000/kakao/userinfo', {kakaoAccessToken})
        .then((res) => res) // 두 번째 .then(): 받은 Access Token으로 사용자 정보를 요청하는 단계
                            // 이 .then((res) => res) 부분은 불필요합니다.
    })
    .then(res => renderUserInfo(res.data.profile_image, res.data.nickname)) // 최종 .then(): 사용자 정보를 받아 UI를 렌더링하는 단계
}

2. OAuth 2.0 Naver

1) 네이버 디벨로퍼 설정

추후 예정

3. 코드

login.js

const kakaoLoginButton = document.querySelector('#kakao')
const naverLoginButton = document.querySelector('#naver')
const userImage = document.querySelector('img')
const userName = document.querySelector('#user_name')
const logoutButton = document.querySelector('#logout_button')

function renderUserInfo(imgUrl = '', name = '') {
    userImage.src = imgUrl
    userName.textContent = name
}

const kakaoClientId = '7d91e2053ea405b28870316616b10058'
const redirectURI = 'http://127.0.0.1:5500'
let kakaoAccessToken = ''

// 카카오 로그인 버튼 클릭 시 로그인 페이지로 이동
kakaoLoginButton.onclick = () => {
    location.href = `https://kauth.kakao.com/oauth/authorize?client_id=${kakaoClientId}&redirect_uri=${redirectURI}&response_type=code`
}

// 페이지 로드 후 인증 코드가 있으면 로그인 처리
window.onload = () => {
    const url = new URL(location.href)
    const authorizationCode = url.searchParams.get('code')

    if (!authorizationCode) return  // 인증 코드 없으면 중단

    axios.post('http://localhost:3000/kakao/login', { authorizationCode })
        .then(res => {
            console.log('AccessToken 응답:', res)
            kakaoAccessToken = res.data
            return axios.post('http://localhost:3000/kakao/userinfo', { kakaoAccessToken })
        })
        .then(res => {
            const { profile_image, nickname } = res.data
            renderUserInfo(profile_image, nickname)
        })
        .catch(err => {
            console.error('카카오 로그인 에러:', err)
        })
}

// 로그아웃 버튼 클릭 시 처리
logoutButton.onclick = () => {
    axios.delete('http://localhost:3000/kakao/logout', {
        data: { kakaoAccessToken }
    })
    .then(res => {
        console.log('로그아웃 성공:', res.data)
        renderUserInfo('', '')
    })
    .catch(err => {
        console.error('로그아웃 에러:', err)
    })
}

server.js

const express = require('express')
const cors = require('cors')
const axios = require('axios')

const kakaoClientId = '7d91e2053ea405b28870316616b10058'
const redirectURI = 'http://127.0.0.1:5500'

const app = express()

app.use(cors({
    origin: ['http://localhost:5500','http://127.0.0.1:5500'],
    methods: ["OPTIONS", "POST", "DELETE"]
}))

app.use(express.json())

app.post('/kakao/login', (req, res) => {
    const authorizationCode = req.body.authorizationCode
    axios.post('https://kauth.kakao.com/oauth/token', {
        grant_type: 'authorization_code',
        client_id: kakaoClientId,
        redirect_uri: redirectURI,
        code: authorizationCode
    },
        {
            headers: {'Content-Type' : 'application/x-www-form-urlencoded;charset=utf-8'}
        }
    )
    .then(response => res.send(response.data.access_token))
})

app.post('/kakao/userinfo', (req, res) => {
    const { kakaoAccessToken } = req.body
    axios.get('https://kapi.kakao.com/v2/user/me', {
        headers: {
            Authorization: `Bearer ${kakaoAccessToken}`,
            'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'
        }
    })
    .then(response => res.json(response.data.properties))
})

app.delete('/kakao/logout', (req, res) => {
    const { kakaoAccessToken } = req.body
    axios.post('https://kapi.kakao.com/v1/user/logout', {}, {
        headers: {Authorization: `Bearer ${kakaoAccessToken}`}
    })
    .then(response => res.send('로그아웃 성공'))
})

app.listen(3000, () => console.log('서버 열림!'))
profile
UI/UX디자이너의 코딩 공부

0개의 댓글