devlog.
메뉴

카테고리

태그

개발

OAuth 2.0과 OIDC — 인증과 인가의 차이부터 소셜 로그인 원리까지

·16분 읽기·

"로그인은 OAuth로 구현했어요"라는 말을 자주 듣습니다. 그런데 OAuth는 원래 로그인(인증) 프로토콜이 아닙니다.

OAuth와 OIDC를 혼동하는 건 흔한 일입니다. 이 두 개념을 제대로 구분하고 소셜 로그인의 내부 동작을 따라가다 보면 JWT까지 자연스럽게 이어집니다.


인증 vs 인가#

가장 먼저 짚어야 할 개념입니다.

구분영어질문예시
인가Authorization너 뭘 할 수 있어?파일 접근 권한
인증Authentication너 누구야?로그인

OAuth 2.0은 인가(Authorization) 프로토콜입니다. "이 앱이 내 Google 캘린더에 접근해도 돼"를 처리합니다.

OIDC는 OAuth 2.0 위에 인증(Authentication) 레이어를 추가한 프로토콜입니다. "이 사람이 Google 계정 주인이 맞아"를 처리합니다.


OAuth 2.0 — 위임된 인가#

OAuth 2.0의 핵심은 사용자가 직접 비밀번호를 앱에 주지 않아도 된다는 점입니다.

예를 들어 "Google 캘린더 일정을 읽는 앱"을 만든다고 가정합니다. 예전에는 앱이 구글 아이디/비밀번호를 직접 받아 처리했습니다. OAuth는 이를 개선합니다.

  1. 사용자가 앱에서 "Google로 연결" 클릭
  2. Google 로그인 화면으로 리다이렉트
  3. 사용자가 Google에 직접 로그인 + 권한 허용
  4. Google이 앱에게 Access Token 발급
  5. 앱은 이 토큰으로 캘린더 API 호출

앱은 구글 비밀번호를 절대 알 수 없고, 허용된 범위(scope)만 접근할 수 있습니다.


Authorization Code Flow#

아래는 가장 흔하게 쓰이는 OAuth 흐름입니다.

사용자 → 앱: 로그인 요청
앱 → 인가 서버: 리다이렉트 (client_id, scope, redirect_uri, state)
사용자 → 인가 서버: 로그인 + 동의
인가 서버 → 앱: Authorization Code 전달 (redirect_uri로)
앱 → 인가 서버: Authorization Code + client_secret으로 토큰 요청
인가 서버 → 앱: Access Token + Refresh Token 발급
앱 → 리소스 서버: Access Token으로 API 호출

Authorization Code를 한 번 거치는 이유는 Access Token이 브라우저 URL에 노출되지 않도록 하기 위해서입니다.

이때 함께 넘기는 state 값은 CSRF 공격을 막기 위한 장치입니다. 앱이 요청 시 만든 랜덤 값을 인가 서버가 그대로 되돌려주고, 앱은 이 값이 일치하는지 확인해 위조된 콜백을 걸러냅니다.

아래는 Oracle에서 제공하는 Authorization Code Flow 다이어그램입니다.


Access Token과 Refresh Token#

토큰역할수명
Access TokenAPI 호출에 사용짧음 (보통 1시간)
Refresh TokenAccess Token 재발급김 (며칠~수개월)

Access Token이 만료되면 Refresh Token으로 새 Access Token을 발급받습니다. Refresh Token까지 만료되면 재로그인이 필요합니다.


OIDC — OAuth 위에 인증 레이어 추가#

OAuth 2.0만으로는 "이 토큰의 주인이 누구인지" 알 방법이 없습니다. OIDC는 이 문제를 ID Token으로 해결합니다.

OIDC는 OAuth 2.0 흐름에 ID Token을 추가로 발급합니다. ID Token은 JWT(JSON Web Token) 형식입니다.

Authorization Code Flow + ID Token 발급

JWT — ID Token의 구조#

ID Token(JWT)은 점(.)으로 구분된 세 부분으로 구성됩니다.

header.payload.signature

payload 부분에 사용자 정보(claims)가 담깁니다.

{
  "sub": "1234567890",
  "name": "Jaejun",
  "email": "jaejun@example.com",
  "iss": "https://accounts.google.com",
  "aud": "my-app-client-id",
  "exp": 1714000000,
  "iat": 1713996400
}
claim의미
sub사용자 고유 ID
iss토큰 발급자
aud토큰 수신 대상 (내 앱)
exp만료 시각

여기서 가장 흔히 오해하는 부분이 있습니다. JWT는 암호화(encryption)가 아니라 인코딩(encoding) 입니다. payload는 base64url로 인코딩될 뿐이라 jwt.io 같은 도구에 붙여넣으면 누구나 내용을 그대로 읽을 수 있습니다.

세 번째 조각인 signature가 하는 일은 내용을 숨기는 게 아니라 위변조를 막는 것입니다. 서버는 서명을 검증해 토큰이 발급 후 조작되지 않았는지만 확인합니다.

실무에서는? JWT에 비밀번호·주민번호 같은 민감정보를 넣으면 안 됩니다.
인코딩일 뿐 암호화가 아니므로, 토큰을 가로챈 사람이 곧바로 내용을 읽을 수 있습니다.


PKCE — Authorization Code 탈취 방어#

일반 Authorization Code Flow는 client_secret을 서버에서 안전하게 보관하는 게 전제입니다.

그런데 SPA(React 등)나 모바일 앱은 client_secret을 숨길 방법이 없습니다. 이때 PKCE(Proof Key for Code Exchange) 를 사용합니다.

앱: code_verifier(랜덤 문자열) 생성
앱: code_verifier를 SHA-256 해시한 code_challenge 생성 (method=S256)
앱 → 인가 서버: code_challenge 포함해서 인가 요청
인가 서버 → 앱: Authorization Code 발급
앱 → 인가 서버: Authorization Code + code_verifier로 토큰 요청
인가 서버: code_verifier를 해시해서 code_challenge와 대조 → 일치 시 토큰 발급

client_secret 없이도 Authorization Code 탈취 공격을 막을 수 있습니다.

실무에서는? PKCE는 더 이상 SPA·모바일 전용이 아닙니다.
최신 OAuth 2.1 가이드는 client_secret을 안전하게 보관할 수 있는 서버 사이드 앱을 포함해 모든 클라이언트에 PKCE 적용을 권장합니다.


OAuth vs OIDC — 언제 뭘 쓰나#

목적프로토콜
외부 서비스 API 접근 권한 위임OAuth 2.0
소셜 로그인 (사용자 신원 확인)OIDC
둘 다OIDC (OAuth 위에 구현됨)

"Google로 로그인" 버튼이 있는 서비스는 모두 OIDC를 사용합니다.


실무 — Next.js에서 소셜 로그인 구현#

Next.js에서는 Auth.js(구 NextAuth.js) 를 사용하면 OAuth/OIDC 흐름을 직접 구현하지 않아도 됩니다. 아래는 현재 표준인 Auth.js v5 기준 설정입니다.

// auth.ts
import NextAuth from 'next-auth'
import Google from 'next-auth/providers/google'

export const { handlers, auth, signIn, signOut } = NextAuth({
  providers: [Google],
})
// app/api/auth/[...nextauth]/route.ts
import { handlers } from '@/auth'

export const { GET, POST } = handlers

clientId·clientSecret은 각각 AUTH_GOOGLE_ID·AUTH_GOOGLE_SECRET 환경 변수로 자동 인식되며, 내부적으로 Authorization Code Flow + PKCE를 처리해 줍니다.


정리#

개념설명
OAuth 2.0인가 프로토콜 — 권한 위임
OIDC인증 프로토콜 — OAuth 2.0 위에 ID Token 추가
Authorization Code Flow가장 안전한 OAuth 흐름 — 서버 사이드 앱에 적합
Access TokenAPI 호출용, 수명 짧음
Refresh TokenAccess Token 재발급용, 수명 김
ID Token (JWT)사용자 신원 정보 담긴 토큰 (암호화 아닌 인코딩)
PKCEAuthorization Code 탈취 방어 — 모든 클라이언트에 권장
Auth.js (NextAuth)Next.js에서 OAuth/OIDC 구현을 추상화한 라이브러리