Back

OAuth 2.0 & OpenID Connect: 개발자를 위한 완벽 가이드

"Google로 로그인" 기능을 구현하거나 타사 API를 연동해 본 적이 있다면 OAuth 2.0을 이미 접해보셨을 겁니다. 하지만 개발자들 사이에서도 가장 오해하기 쉽고 헷갈리는 주제 중 하나가 바로 OAuth입니다. "Implicit Flow", "Bearer Token", "OIDC" 같은 용어들이 난무하다 보니, 정확한 개념 없이 구현했다가 보안 취약점을 만들기도 하죠.

이 글에서는 OAuth 2.0과 OpenID Connect(OIDC)의 핵심 개념을 정리하고, 안전한 애플리케이션을 만들기 위해 꼭 알아야 할 내용들을 '딥 다이브' 해보겠습니다.

인증(Authentication) vs 인가(Authorization)

프로토콜을 살펴보기 전에, 가장 기본적이지만 중요한 두 개념을 구분해야 합니다.

  • 인증 (Authentication, AuthN): 당신은 누구인가요? (예: 신원 확인, 로그인)
  • 인가 (Authorization, AuthZ): 당신은 무엇을 할 수 있나요? (예: 특정 리소스 접근 권한 부여)

OAuth 2.0은 *인가(Authorization)*를 위한 프로토콜입니다. 애플리케이션이 사용자를 대신해 다른 서버의 리소스에 접근할 수 있게 해주죠.
반면, **OpenID Connect (OIDC)**는 OAuth 2.0 위에 구축된 인증(Authentication) 레이어입니다. 클라이언트가 사용자의 신원을 확인할 수 있게 해줍니다.

주요 역할 (Roles)

OAuth의 흐름을 이해하려면 등장인물들을 알아야 합니다.

  1. Resource Owner: 사용자 (바로 여러분).
  2. Client: 사용자의 계정에 접근하려는 애플리케이션 (웹 앱, 모바일 앱 등).
  3. Authorization Server: 로그인 화면을 제공하고 토큰을 발급하는 서버 (예: Google, Auth0, Kakao).
  4. Resource Server: 사용자의 데이터를 가지고 있는 API 서버.

토큰의 종류 (Tokens)

OAuth와 OIDC는 토큰 기반으로 동작합니다. 각 토큰의 용도를 명확히 아는 것이 중요해요.

Access Token (액세스 토큰)

리소스 서버의 문을 여는 열쇠입니다. 클라이언트는 이 토큰을 API 서버에 보내 데이터를 요청합니다. 보통 JWT (JSON Web Token) 형식을 많이 쓰지만, 랜덤한 문자열일 수도 있습니다.

  • 목적: 인가 (Authorization)
  • 대상: Resource Server

ID Token (OIDC 전용)

사용자의 정보(이름, 이메일, 프로필 사진 등)를 담고 있는 토큰입니다. 클라이언트가 "아, 이 사람이 로그인했구나"라고 식별하는 데 사용됩니다.

  • 목적: 인증 (Authentication)
  • 대상: Client
  • 형식: 항상 JWT

Refresh Token (리프레시 토큰)

Access Token은 보안상 유효기간이 짧습니다. 사용자가 매번 로그인을 다시 하지 않도록, 만료된 Access Token을 갱신할 때 사용하는 장기 토큰입니다.

꿀팁: JWT 디버깅하다가 눈 빠질 뻔한 적 있으시죠? Pockit JWT Decoder를 사용하면 브라우저에서 안전하게 토큰의 헤더와 페이로드를 뜯어볼 수 있습니다. 서버로 전송되지 않으니 안심하세요!

주요 흐름 (Grant Types)

"Grant Type"은 클라이언트가 Access Token을 얻는 방식을 말합니다. 상황에 맞는 적절한 방식을 선택하는 것이 보안의 핵심입니다.

1. Authorization Code Flow (with PKCE)

추천 대상: 서버 사이드 앱, SPA, 모바일 앱
현재 가장 권장되는 표준 방식입니다. 토큰을 바로 받는 대신 임시 "코드"를 받고, 이를 서버에서 토큰으로 교환합니다. **PKCE (Proof Key for Code Exchange)**를 더하면 코드 탈취 공격까지 막을 수 있어 매우 안전합니다.

  1. 클라이언트가 사용자를 인가 서버로 리다이렉트합니다.
  2. 사용자가 로그인하고 권한을 승인합니다.
  3. 인가 서버가 code와 함께 클라이언트로 다시 리다이렉트합니다.
  4. 클라이언트는 code + code_verifier를 보내 Access Token으로 교환합니다.

2. Client Credentials Flow

추천 대상: M2M (Machine-to-Machine) 통신
사용자의 개입 없이, 애플리케이션이 자기 자신의 리소스에 접근할 때 사용합니다. (예: 백엔드 데몬 작업)

  1. 클라이언트가 client_idclient_secret을 전송합니다.
  2. 인가 서버가 Access Token을 발급합니다.

3. Implicit Flow (사용 금지 🚫)

예전에는 SPA에서 많이 썼지만, 이제는 보안상 사용하지 말아야 합니다. URL에 토큰이 노출되기 때문에 탈취 위험이 매우 높습니다.

트러블슈팅 가이드

"redirect_uri_mismatch" 에러

가장 흔한 에러입니다. 요청 시 보낸 redirect_uri가 OAuth 제공자 설정에 등록된 주소와 정확히 일치해야 합니다. http vs https, 혹은 끝에 붙은 슬래시(/) 하나 차이로도 에러가 납니다.

"invalid_grant" 에러

이 에러는 보통 다음 중 하나입니다:

  • 인가 코드가 만료됨 (코드는 수명이 매우 짧습니다).
  • 이미 사용된 코드임.
  • 코드를 받을 때 쓴 redirect_uri와 교환할 때 쓴 redirect_uri가 다름.

마치며

OAuth 2.0과 OIDC는 현대 웹 개발의 필수 요소입니다. 인증과 인가의 차이를 이해하고, 상황에 맞는 Flow(가능하면 PKCE!)를 선택한다면 훨씬 더 안전하고 견고한 서비스를 만들 수 있습니다.

보안은 직접 구현하기보다 검증된 표준을 따르는 것이 정답입니다. 이 가이드가 여러분의 삽질을 조금이라도 줄여주길 바랍니다!

oauthsecurityauthenticationweb-developmentdeep-dive

관련 도구 둘러보기

Pockit의 무료 개발자 도구를 사용해 보세요