🤖

본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.

⚠️

본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.

이미지 로딩 중...

OAuth 2.1 최신 기능 완벽 가이드 - 슬라이드 1/11
A

AI Generated

2025. 11. 5. · 18 Views

OAuth 2.1 최신 기능 완벽 가이드

OAuth 2.1의 최신 보안 기능과 모범 사례를 초급 개발자를 위해 쉽게 설명합니다. PKCE, 토큰 관리, 그리고 실전에서 바로 사용할 수 있는 예제를 포함합니다.


카테고리:JavaScript
언어:JavaScript
메인 태그:#OAuth
서브 태그:
#PKCE#Authorization#JWT#Security

들어가며

이 글에서는 OAuth 2.1 최신 기능 완벽 가이드에 대해 상세히 알아보겠습니다. 총 10가지 주요 개념을 다루며, 각각의 개념에 대한 설명과 실제 코드 예제를 함께 제공합니다.

목차

  1. PKCE_코드_챌린지_생성
  2. Authorization_Code_Flow_시작
  3. 인증_코드로_토큰_교환
  4. Refresh_Token_자동_갱신
  5. Bearer_Token_API_호출
  6. Token_만료_시간_체크
  7. State_파라미터_CSRF_방지
  8. Logout_토큰_무효화
  9. Scope_권한_요청
  10. 토큰_안전한_저장소_관리

1. PKCE 코드 챌린지 생성

개요

OAuth 2.1에서 필수가 된 PKCE(Proof Key for Code Exchange)의 코드 챌린지를 생성하는 방법입니다. 공개 클라이언트의 보안을 강화합니다.

코드 예제

async function generatePKCE() {
  const verifier = crypto.randomUUID() + crypto.randomUUID();
  const encoder = new TextEncoder();
  const data = encoder.encode(verifier);
  const hash = await crypto.subtle.digest('SHA-256', data);
  const challenge = btoa(String.fromCharCode(...new Uint8Array(hash)))
    .replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
  return { verifier, challenge };
}

설명

랜덤 문자열을 생성하고 SHA-256으로 해시한 뒤 Base64 URL 인코딩하여 코드 챌린지를 만듭니다. verifier는 저장하고 challenge는 인증 요청에 포함시킵니다.


2. Authorization Code Flow 시작

개요

PKCE를 포함한 OAuth 2.1 인증 코드 플로우를 시작합니다. 사용자를 인증 서버로 리다이렉트합니다.

코드 예제

async function startOAuthFlow() {
  const { verifier, challenge } = await generatePKCE();
  sessionStorage.setItem('code_verifier', verifier);

  const params = new URLSearchParams({
    response_type: 'code',
    client_id: 'your-client-id',
    redirect_uri: 'https://your-app.com/callback',
    code_challenge: challenge,
    code_challenge_method: 'S256'
  });
  window.location.href = `https://auth-server.com/authorize?${params}`;
}

설명

PKCE 값을 생성하고 verifier를 저장한 후, 인증 서버로 리다이렉트합니다. S256 방식으로 챌린지를 전달하여 보안을 강화합니다.


3. 인증 코드로 토큰 교환

개요

콜백에서 받은 인증 코드를 액세스 토큰으로 교환합니다. code_verifier를 함께 전송하여 PKCE를 완성합니다.

코드 예제

async function exchangeCodeForToken(code) {
  const verifier = sessionStorage.getItem('code_verifier');

  const response = await fetch('https://auth-server.com/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({
      grant_type: 'authorization_code',
      code: code,
      redirect_uri: 'https://your-app.com/callback',
      client_id: 'your-client-id',
      code_verifier: verifier
    })
  });
  return await response.json();
}

설명

저장해둔 code_verifier와 인증 코드를 전송하여 토큰을 받습니다. 서버는 verifier와 challenge를 검증하여 보안을 확인합니다.


4. Refresh Token 자동 갱신

개요

액세스 토큰이 만료되기 전에 refresh token을 사용하여 자동으로 새 토큰을 발급받습니다.

코드 예제

async function refreshAccessToken(refreshToken) {
  const response = await fetch('https://auth-server.com/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({
      grant_type: 'refresh_token',
      refresh_token: refreshToken,
      client_id: 'your-client-id'
    })
  });
  const tokens = await response.json();
  localStorage.setItem('access_token', tokens.access_token);
  return tokens;
}

설명

refresh token을 사용하여 사용자의 재인증 없이 새로운 액세스 토큰을 발급받습니다. 토큰을 안전하게 저장하여 API 호출에 사용합니다.


5. Bearer Token API 호출

개요

발급받은 액세스 토큰을 Authorization 헤더에 포함하여 보호된 API를 호출합니다.

코드 예제

async function callProtectedAPI(endpoint) {
  const token = localStorage.getItem('access_token');

  const response = await fetch(`https://api.example.com${endpoint}`, {
    method: 'GET',
    headers: {
      'Authorization': `Bearer ${token}`,
      'Content-Type': 'application/json'
    }
  });

  if (response.status === 401) {
    await refreshAccessToken(localStorage.getItem('refresh_token'));
    return callProtectedAPI(endpoint);
  }
  return await response.json();
}

설명

Bearer 토큰을 헤더에 포함하여 API를 호출합니다. 401 오류 시 자동으로 토큰을 갱신하고 재시도합니다.


6. Token 만료 시간 체크

개요

JWT 토큰의 만료 시간을 확인하여 사전에 갱신이 필요한지 판단합니다.

코드 예제

function isTokenExpiringSoon(token, bufferSeconds = 300) {
  try {
    const payload = JSON.parse(atob(token.split('.')[1]));
    const expiryTime = payload.exp * 1000;
    const currentTime = Date.now();
    const timeUntilExpiry = expiryTime - currentTime;

    return timeUntilExpiry < bufferSeconds * 1000;
  } catch {
    return true;
  }
}

설명

JWT 토큰을 디코딩하여 만료 시간(exp)을 확인합니다. 만료 5분 전에 미리 갱신하도록 하여 API 호출 중 토큰 만료를 방지합니다.


7. State 파라미터 CSRF 방지

개요

state 파라미터를 사용하여 CSRF(Cross-Site Request Forgery) 공격을 방지합니다.

코드 예제

function startOAuthWithState() {
  const state = crypto.randomUUID();
  sessionStorage.setItem('oauth_state', state);

  const params = new URLSearchParams({
    response_type: 'code',
    client_id: 'your-client-id',
    redirect_uri: 'https://your-app.com/callback',
    state: state
  });
  window.location.href = `https://auth-server.com/authorize?${params}`;
}

function validateState(returnedState) {
  const savedState = sessionStorage.getItem('oauth_state');
  return savedState === returnedState;
}

설명

랜덤 state 값을 생성하여 저장하고 인증 요청에 포함시킵니다. 콜백에서 동일한 값이 반환되는지 확인하여 공격을 차단합니다.


8. Logout 토큰 무효화

개요

로그아웃 시 서버에서 토큰을 무효화하고 로컬 저장소를 정리합니다.

코드 예제

async function logout() {
  const token = localStorage.getItem('access_token');

  try {
    await fetch('https://auth-server.com/revoke', {
      method: 'POST',
      headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
      body: new URLSearchParams({
        token: token,
        client_id: 'your-client-id'
      })
    });
  } finally {
    localStorage.removeItem('access_token');
    localStorage.removeItem('refresh_token');
    sessionStorage.clear();
  }
}

설명

서버의 revoke 엔드포인트로 토큰 무효화를 요청하고, 로컬에 저장된 모든 토큰과 세션 데이터를 삭제합니다.


9. Scope 권한 요청

개요

필요한 최소한의 권한(scope)만 요청하여 보안을 강화하고 사용자 신뢰를 얻습니다.

코드 예제

function requestSpecificScopes(scopes) {
  const params = new URLSearchParams({
    response_type: 'code',
    client_id: 'your-client-id',
    redirect_uri: 'https://your-app.com/callback',
    scope: scopes.join(' '),
  });

  // 예: ['read:user', 'write:posts']
  window.location.href = `https://auth-server.com/authorize?${params}`;
}

// 사용 예시
requestSpecificScopes(['read:user', 'read:email']);

설명

앱에 필요한 권한만 명확히 지정하여 요청합니다. 불필요한 권한을 요청하지 않아 사용자 개인정보를 보호하고 승인율을 높입니다.


10. 토큰 안전한 저장소 관리

개요

토큰을 안전하게 저장하고 관리하는 클래스입니다. XSS 공격으로부터 보호합니다.

코드 예제

class SecureTokenStorage {
  static setTokens(accessToken, refreshToken) {
    // HttpOnly 쿠키 사용 권장, 데모용 localStorage
    localStorage.setItem('access_token', accessToken);
    localStorage.setItem('refresh_token', refreshToken);
    localStorage.setItem('token_timestamp', Date.now().toString());
  }

  static getAccessToken() {
    return localStorage.getItem('access_token');
  }

  static clearTokens() {
    localStorage.removeItem('access_token');
    localStorage.removeItem('refresh_token');
  }
}

설명

토큰을 중앙에서 관리하는 클래스를 만들어 일관성을 유지합니다. 프로덕션에서는 HttpOnly 쿠키나 서버 세션 사용을 권장합니다.


마치며

이번 글에서는 OAuth 2.1 최신 기능 완벽 가이드에 대해 알아보았습니다. 총 10가지 개념을 다루었으며, 각각의 사용법과 예제를 살펴보았습니다.

관련 태그

#OAuth #PKCE #Authorization #JWT #Security

#OAuth#PKCE#Authorization#JWT#Security#JavaScript

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.