보안

OAuth 2.0과 OpenID Connect로 안전하고 유연한 인증/인가 시스템 구축 실전 가이드

강코의 코딩 일기 2026. 6. 13. 20:06
반응형

OAuth 2.0과 OpenID Connect를 활용하여 안전하고 확장 가능한 인증/인가 시스템을 구축한 경험을 공유합니다. 실제 적용 사례와 함께 두 기술의 핵심 차이점, 구현 팁까지 상세히 다룹니다.

안녕하세요! 개발 블로그에서 실무 경험을 공유하는 (필자 이름 또는 가상의 개발자 페르소나)입니다. 서비스를 개발하다 보면 사용자 인증권한 관리는 늘 중요한 숙제로 다가옵니다. 특히 외부 서비스 연동이나 마이크로서비스 아키텍처 환경에서는 더욱 그렇죠. 사용자 비밀번호를 직접 관리하는 부담을 줄이면서도, 어떻게 하면 안전하고 유연하게 인증/인가 시스템을 구축할 수 있을까요? 바로 이때 OAuth 2.0OpenID Connect가 강력한 해답이 되어줍니다. 저는 실제로 이 두 기술을 조합하여 여러 시스템의 보안 수준을 한 단계 끌어올린 경험이 있습니다. 이 글에서는 그 과정에서 얻은 인사이트와 실용적인 팁들을 공유하고자 합니다.

OAuth 2.0과 OpenID Connect를 활용한 안전한 인증/인가 시스템 구축 - toddler hand, child's hand, hand, trust, hands, closeness, affection, hold tight, security, keep, support, prop up, connection, contact, close, relationship, connect, together, love, connect competition, trust, trust, trust, trust, trust, security, security, security, support, support, connection

Image by Myriams-Fotos on Pixabay

들어가며: 왜 OAuth 2.0OpenID Connect인가?

온라인 서비스는 점점 더 복잡해지고 다양한 플랫폼과 연동됩니다. 사용자들은 구글, 네이버, 카카오 등 익숙한 계정으로 로그인하길 원하고, 개발자들은 이러한 연동을 통해 서비스의 편의성을 높이고 싶어 합니다. 동시에, 서비스 간 자원 접근은 엄격하게 통제되어야 합니다. 예를 들어, 사용자의 동의 없이 특정 앱이 개인 정보를 가져가거나, 한 번의 계정 탈취로 모든 서비스가 위험에 빠지는 일은 없어야 하죠.

이러한 요구사항을 충족시키기 위해 등장한 것이 바로 OAuth 2.0OpenID Connect입니다. 두 기술은 서로 다른 목적을 가지고 있지만, 함께 사용될 때 시너지를 발휘하여 강력한 인증/인가 시스템을 구축할 수 있게 돕습니다.

  • OAuth 2.0: 권한 위임(Delegated Authorization)의 표준입니다. "사용자가 특정 서비스에게 내 정보를 대신 접근할 수 있는 권한을 부여한다"는 개념이죠. 예를 들어, 앱이 사용자의 동의를 얻어 구글 드라이브에 접근할 수 있도록 하는 것입니다.
  • OpenID Connect (OIDC): OAuth 2.0 위에 구축된 인증(Authentication) 계층입니다. "사용자가 누구인지"를 확인하는 데 초점을 맞춥니다. OAuth 2.0이 자원 접근 권한을 다룬다면, OpenID Connect사용자 신원을 확인하는 데 사용됩니다.

처음에는 이 두 가지 개념이 혼란스러울 수 있습니다. 저 역시 그랬습니다. 하지만 핵심은 간단합니다. OAuth 2.0은 '무엇을 할 수 있는지'에 대한 것이고, OpenID Connect는 '누가 하는지'에 대한 것이라는 점입니다. 이제 각 기술의 본질을 더 깊이 파고들어 보겠습니다.

OAuth 2.0, 그 본질을 이해하기: 권한 위임의 마법

OAuth 2.0은 사용자의 비밀번호를 직접 다루지 않고도, 타사 애플리케이션이 사용자를 대신하여 특정 리소스에 접근할 수 있는 권한을 안전하게 부여하는 프레임워크입니다. 즉, "인가(Authorization)"에 초점을 맞춥니다. 흔히 비유되는 것이 '발렛 파킹'입니다. 자동차 키(비밀번호)를 직접 넘겨주는 대신, 발렛 키(Access Token)를 넘겨주어 제한된 기능(주차, 이동)만 허용하는 것과 같습니다.

OAuth 2.0의 핵심 구성 요소와 흐름

OAuth 2.0은 다음 네 가지 핵심 역할로 구성됩니다.

  • Resource Owner (리소스 소유자): 보호된 리소스에 대한 접근 권한을 가진 사용자입니다. (예: 구글 계정 소유자)
  • Client (클라이언트): 리소스 소유자를 대신하여 보호된 리소스에 접근하려는 애플리케이션입니다. (예: 특정 사진 편집 앱)
  • Authorization Server (인가 서버): 리소스 소유자의 인증을 수행하고, 클라이언트에게 Access Token을 발급합니다. (예: 구글 로그인 서버)
  • Resource Server (리소스 서버): 보호된 리소스를 호스팅하며, Access Token을 사용하여 리소스 접근 요청을 수락합니다. (예: 구글 포토 API)

가장 일반적이고 보안성이 높은 Authorization Code Grant 흐름은 다음과 같습니다.

  1. 클라이언트가 리소스 소유자를 인가 서버로 리디렉션하여 권한 요청을 합니다. 이때 client_id, redirect_uri, scope, state 등의 파라미터를 포함합니다.
  2. 리소스 소유자는 인가 서버에서 로그인하고, 클라이언트가 요청하는 권한에 동의합니다.
  3. 인가 서버는 리소스 소유자의 동의를 받아 인가 코드(Authorization Code)를 클라이언트의 redirect_uri로 리디렉션하여 전달합니다.
  4. 클라이언트는 이 인가 코드를 인가 서버에 직접 전달하여 Access TokenRefresh Token을 요청합니다. 이때 client_secret을 사용하여 클라이언트의 신원을 확인합니다.
  5. 인가 서버는 인가 코드가 유효하면 Access TokenRefresh Token을 클라이언트에게 발급합니다.
  6. 클라이언트는 발급받은 Access Token을 사용하여 리소스 서버에 보호된 리소스 접근을 요청합니다.
  7. 리소스 서버는 Access Token의 유효성을 검증하고, 유효하다면 요청된 리소스를 클라이언트에게 제공합니다.

이 과정에서 중요한 것은 클라이언트가 사용자 비밀번호를 직접 다루지 않는다는 점입니다. Access Token은 특정 scope(접근 권한 범위)를 가지며, 짧은 유효 기간을 가집니다. Refresh TokenAccess Token이 만료되었을 때 새로운 Access Token을 얻기 위해 사용됩니다.

OpenID Connect, 인증의 표준: 사용자 신원 확인

OAuth 2.0이 '누가 무엇을 할 수 있는지(인가)'에 초점을 맞춘다면, OpenID Connect (OIDC)는 '누구인지(인증)'를 확인하는 데 초점을 맞춥니다. OIDCOAuth 2.0 프레임워크를 기반으로 구축되어, 인증 정보를 ID 토큰(ID Token)이라는 형태로 제공합니다. 즉, OAuth 2.0Access Token을 통해 리소스 접근 권한을 주지만, OIDCID Token을 통해 사용자 신원 정보를 제공하는 것입니다.

OpenID Connect의 핵심: ID 토큰

OIDC의 가장 핵심적인 요소는 ID 토큰입니다. ID 토큰JWT(JSON Web Token) 형식으로 구성되며, 사용자의 신원 정보(예: 사용자 ID, 이름, 이메일 등)를 포함합니다. ID 토큰은 인가 서버(여기서는 OpenID Provider라고 부름)에서 서명되어 클라이언트에게 전달되므로, 클라이언트는 이 토큰의 무결성과 신뢰성을 검증할 수 있습니다.

OIDC 흐름은 OAuth 2.0 Authorization Code Grant 흐름과 매우 유사하며, 몇 가지 차이점이 있습니다.

  1. 권한 요청 시 scopeopenid를 포함: OIDC를 사용하겠다는 명시적인 요청입니다. 보통 profile, email 등 추가적인 사용자 정보 요청 스코프도 함께 사용합니다.
  2. 인가 코드 교환 시 ID 토큰도 함께 발급: Access Token과 함께 ID 토큰이 발급됩니다.
  3. 클라이언트는 ID 토큰을 받아 서명을 검증하고, 토큰 내의 클레임(Claim)들을 파싱하여 사용자의 신원 정보를 확인합니다.

// ID 토큰 (JWT) 예시 (디코딩된 페이로드)
{
  "iss": "https://accounts.google.com", // 발행자 (OpenID Provider)
  "sub": "1234567890", // 고유한 사용자 식별자
  "aud": "YOUR_CLIENT_ID", // 수신자 (클라이언트 ID)
  "exp": 1678886400, // 만료 시간 (Unix timestamp)
  "iat": 1678882800, // 발행 시간 (Unix timestamp)
  "auth_time": 1678882700, // 인증 시간
  "nonce": "RANDOM_STRING", // Replay Attack 방지
  "name": "홍길동",
  "email": "hong.gildong@example.com",
  "email_verified": true,
  "picture": "https://example.com/profile/hong.jpg"
}

ID 토큰은 클라이언트가 사용자 인증을 직접 처리할 필요 없이, OpenID Provider가 인증한 정보를 신뢰할 수 있도록 해줍니다. 이는 특히 싱글 사인 온(Single Sign-On, SSO) 환경 구축에 매우 유용합니다.

OAuth 2.0과 OpenID Connect를 활용한 안전한 인증/인가 시스템 구축 - parrot, parrot ar drone, parrot ar drone 2, 0, drone, video, green video, green videos

Image by andri333 on Pixabay

OAuth 2.0OpenID Connect, 무엇이 다를까?

두 기술의 목적과 기능이 다르다는 것을 이해하는 것이 중요합니다. 아래 표는 이들의 주요 차이점을 요약한 것입니다.

구분 OAuth 2.0 OpenID Connect
주요 목적 권한 위임 (Authorization): 리소스 접근 권한 부여 인증 (Authentication): 사용자 신원 확인
무엇을 반환하는가? Access Token (선택적으로 Refresh Token) ID Token (JWT 형식), Access Token, Refresh Token
주요 사용처 타사 앱이 특정 API에 접근할 권한이 필요한 경우 (예: 구글 캘린더, 페이스북 사진) 사용자가 특정 서비스에 로그인할 때 신원을 확인해야 하는 경우 (예: 구글, 네이버, 카카오 로그인)
기반 기술 독립적인 프로토콜 OAuth 2.0 위에 구축된 계층
사용자 정보 직접적으로 사용자 신원 정보를 제공하지 않음 (보호된 리소스 접근을 통해 얻어야 함) ID 토큰 내에 사용자 신원 정보(클레임) 포함

결론적으로, 안전한 인증/인가 시스템을 구축하려면 이 두 가지를 함께 사용하는 것이 일반적이고 권장됩니다. OpenID Connect를 통해 사용자의 신원을 확인하고 로그인 처리한 후, OAuth 2.0Access Token을 사용하여 해당 사용자의 권한으로 보호된 리소스에 접근하는 방식입니다.

실제 시스템 구축 시 고려사항 및 적용 팁

이제 이론을 바탕으로 실제 시스템에 어떻게 적용할 수 있을지 몇 가지 팁을 공유하겠습니다. 저의 경험상, 이 부분에서 가장 많은 시행착오를 겪었습니다.

적절한 Grant Type 선택과 보안

OAuth 2.0에는 여러 Grant Type (권한 부여 방식)이 있습니다. 서비스의 특성과 클라이언트 유형에 따라 적절한 방식을 선택해야 합니다.

  • Authorization Code Grant: 가장 일반적으로 사용되며, 서버 사이드 웹 애플리케이션에 적합합니다. 인가 코드가 직접 클라이언트 브라우저에 노출되지 않고 백엔드 서버에서 Access Token으로 교환되므로 보안성이 가장 높습니다.
  • Authorization Code Grant with PKCE (Proof Key for Code Exchange): 모바일 앱이나 SPA(Single Page Application)와 같은 Public Client에 필수적입니다. client_secret을 안전하게 보관하기 어려운 환경에서 인가 코드 가로채기 공격(Authorization Code Interception Attack)을 방지하는 데 효과적입니다. 클라이언트가 인가 코드를 요청할 때 생성한 비밀 값(code_verifier)을 사용하여 Access Token 교환 시 다시 한 번 클라이언트의 신원을 확인합니다.
  • Client Credentials Grant: 사용자 개입 없이 서비스 간(machine-to-machine) 통신에 사용됩니다. 클라이언트 자체의 자격 증명(client_id, client_secret)으로 Access Token을 발급받아 리소스에 접근합니다.

저는 주로 서버 사이드 애플리케이션에는 Authorization Code Grant를, 프론트엔드 단독으로 동작하는 SPA나 모바일 앱에는 PKCE를 적용한 Authorization Code Grant를 사용했습니다. 특히 PKCE는 이제 Public Client의 표준 보안 메커니즘으로 자리 잡았으므로, 적극적으로 도입하는 것을 권장합니다.

ID 토큰 검증과 Access 토큰 활용 전략

OpenID Connect를 통해 발급받은 ID 토큰은 반드시 서버 사이드에서 검증해야 합니다. 클라이언트에서만 검증하면 위변조된 토큰에 대한 취약점이 생길 수 있습니다. 검증 절차는 다음과 같습니다.

  1. ID 토큰의 서명 검증: OpenID Provider의 공개 키를 사용하여 ID 토큰의 서명을 검증합니다. 이를 통해 토큰이 변조되지 않았음을 확인합니다.
  2. iss (Issuer) 클레임 확인: 토큰을 발행한 OpenID Provider의 URL과 일치하는지 확인합니다.
  3. aud (Audience) 클레임 확인: 토큰의 대상이 우리 클라이언트의 client_id와 일치하는지 확인합니다.
  4. exp (Expiration Time) 클레임 확인: 토큰의 만료 시간을 확인하여 유효한 토큰인지 검사합니다.
  5. nonce (Replay Attack 방지) 클레임 확인: Authorization Code Grant 요청 시 보냈던 nonce 값과 ID 토큰에 포함된 nonce 값이 일치하는지 확인하여 Replay Attack을 방지합니다.

Access Token은 Bearer Token 방식으로 사용하며, Authorization: Bearer [Access Token] 헤더에 담아 리소스 서버에 요청합니다. Access Token은 짧은 유효 기간을 가지도록 설계하는 것이 보안상 유리합니다. 만료 시 Refresh Token을 사용하여 새로운 Access Token을 발급받는 방식으로 사용자 경험을 해치지 않으면서 보안을 강화할 수 있습니다. Refresh Token은 더 긴 유효 기간을 가지지만, 반드시 안전한 저장소(예: HttpOnly 쿠키)에 보관해야 합니다.

OAuth 2.0과 OpenID Connect를 활용한 안전한 인증/인가 시스템 구축 - man, face, facial recognition, biometric, identify, security, people, authentication, identification, database, scanning, facial recognition, facial recognition, facial recognition, facial recognition, facial recognition, biometric

Image by Tumisu on Pixabay

보안 위협과 대응 전략

아무리 좋은 기술도 올바르게 사용하지 않으면 취약점이 발생할 수 있습니다. OAuth 2.0OpenID Connect 환경에서 발생할 수 있는 주요 보안 위협과 대응 전략은 다음과 같습니다.

  • Redirect URI Manipulation (리디렉션 URI 조작): 공격자가 redirect_uri를 조작하여 인가 코드ID 토큰을 가로채는 공격입니다.
    • 대응: 인가 서버에 사전 등록된 redirect_uri만 허용하고, 정확히 일치하는 경우에만 리디렉션을 수행해야 합니다. 와일드카드는 가능한 한 사용하지 않거나 매우 제한적으로 사용해야 합니다.
  • CSRF (Cross-Site Request Forgery): 공격자가 사용자 모르게 위조된 요청을 보내는 공격입니다.
    • 대응: state 파라미터를 사용해야 합니다. 클라이언트가 인가 요청 시 고유한 state 값을 생성하여 인가 서버로 보내고, 인가 코드와 함께 반환된 state 값이 일치하는지 검증해야 합니다.
  • Token Theft (토큰 탈취): Access Token이나 Refresh Token이 탈취되는 경우입니다. XSS(Cross-Site Scripting) 공격 등을 통해 발생할 수 있습니다.
    • 대응: Access Token의 유효 기간을 짧게 설정하고, Refresh Token은 HttpOnly 속성의 보안 쿠키에 저장하여 JavaScript 접근을 막는 것이 좋습니다. 또한, 토큰을 클라이언트 사이드의 로컬 스토리지에 저장하는 것은 XSS 공격에 취약하므로 지양해야 합니다.
  • Code Interception Attack (인가 코드 가로채기 공격): Public Client에서 인가 코드가 탈취되어 공격자가 Access Token을 발급받는 공격입니다.
    • 대응: 앞서 언급한 PKCE(Proof Key for Code Exchange)를 반드시 적용해야 합니다.
  • Client Secret Exposure (클라이언트 시크릿 노출): client_secret이 노출되면 심각한 보안 문제가 발생합니다.
    • 대응: client_secret절대로 클라이언트 코드에 포함되어서는 안 됩니다. 반드시 백엔드 서버에서 안전하게 관리하고, API 호출 시에만 사용해야 합니다. 버전 관리 시스템에 올리거나 외부에 노출되지 않도록 환경 변수, 비밀 관리 서비스 등을 활용해야 합니다.

이러한 보안 위협에 대한 이해와 적절한 대응책 마련은 안전한 인증/인가 시스템 구축의 핵심입니다. 단순히 프로토콜을 구현하는 것을 넘어, 발생 가능한 공격 시나리오를 미리 예측하고 방어하는 자세가 중요합니다.

마치며: 더 안전하고 효율적인 미래를 위한 선택

지금까지 OAuth 2.0OpenID Connect를 활용하여 안전한 인증/인가 시스템을 구축하는 방법에 대해 알아보았습니다. 두 기술은 각각 권한 위임사용자 인증이라는 명확한 목적을 가지고 있으며, 함께 사용될 때 강력한 시너지를 발휘합니다.

제가 직접 시스템에 적용해 본 결과, 초기 학습 곡선은 다소 가파르지만, 일단 제대로 이해하고 나면 다음과 같은 이점을 얻을 수 있었습니다.

  • 보안성 강화: 사용자 비밀번호를 직접 다루지 않아 비밀번호 유출 위험을 줄이고, Access TokenID Token의 엄격한 검증을 통해 시스템의 전반적인 보안 수준을 높일 수 있습니다.
  • 확장성 및 유연성: 다양한 외부 서비스(소셜 로그인)와의 연동이 쉬워지며, 마이크로서비스 아키텍처 환경에서 서비스 간 인가 처리를 표준화할 수 있습니다.
  • 사용자 경험 개선: 익숙한 외부 계정으로 로그인할 수 있어 사용자 편의성이 향상됩니다.

물론, 이 모든 과정을 완벽하게 구현하는 것은 쉽지 않습니다. 하지만 이 글에서 다룬 핵심 개념과 실전 팁들이 여러분의 인증/인가 시스템 구축 여정에 조금이나마 도움이 되기를 바랍니다. 특히 PKCE, state 파라미터, nonce 파라미터 등은 반드시 적용해야 할 필수 보안 요소라는 점을 다시 한번 강조하고 싶습니다.

더 안전하고 효율적인 웹 서비스를 만들기 위한 여정은 계속됩니다. 혹시 OAuth 2.0이나 OpenID Connect를 적용하면서 겪었던 어려움이나 성공적인 경험이 있으시다면 댓글로 공유해주세요. 함께 배우고 성장하는 기회가 되었으면 좋겠습니다. 감사합니다!

📌 함께 읽으면 좋은 글

  • [커리어 취업] 개발자 이력서와 포트폴리오: 서류 합격률을 높이는 실전 작성 전략
  • [기술 리뷰] Redux, Zustand, Recoil, Jotai 비교 분석: 리액트 상태 관리 라이브러리 선택 가이드
  • [커리어 취업] 시니어 개발자 핵심 역량과 커리어 로드맵: 성장 가이드

이 글이 도움이 되셨다면 공감(♥)댓글로 응원해 주세요!
궁금한 점이나 다루었으면 하는 주제가 있다면 댓글로 남겨주세요.

반응형