OAuth2.0과 OIDC

띠용·2025년 12월 11일

우테코 7기 BE

목록 보기
11/14
post-thumbnail

OAuth 등장 배경

내가 사용자의 구글 메일을 대신 읽어주는 서비스를 개발했다치자. 사용자는 그 서비스에 구글 계정 ID/PW를 입력해야 한다. 그래야 내 서비스가 사용자의 메일을 읽어줄 것 아닌가.

  • 이는 구글 계정의 ID/PW 관리 책임이 내 서비스로 넘어가는 것이다.
  • 구글 입장에서는 힘들게 보안 체계를 구축해놨더니 엉뚱한 앱에서 ID/PW가 뚫릴 수도 있는 노릇이며
  • 우리 서비스 입장에서도 사용자의 구글 ID/PW를 보관하는 것은 부담스럽다.

그래서 OAuth가 등장했다.

Id Provider가 애플리케이션과 사용자 비밀번호를 공유하지 않고도 애플리케이션이 사용자 자원에 접근할 수 있도록 하는 인가 프레임워크

OAuth 1.0과 2.0

  • 핵심 차이는 HTTPS이다.
    • 1.0때는 HTTPS가 아니어도 메시지 위변조를 막기위해 복잡한 메시지 암호화를 해야했지만
    • 2.0부터 HTTPS를 강제하여 이러한 과정을 생략했다.



OAuth 2.0 역할 정의

  1. Resource Owner (자원 소유자)
    • (ex. 사용자)
    • 프로필, 이메일, 주문 내역 등 자원의 실제 주인

  1. Client (클라이언트 앱, 서비스)
    • 사용자가 쓰는 우리의 앱 (ex. 우리 서버, 프론트)
    • 사용자 대신 자원에 접근하고 싶어하는 주체

  1. Authorization Server (인가 서버)
    • 로그인/권한 동의를 처리하고, 토큰을 발급해주는 서버
    • Resource Server와 섞여 있을 때도 있지만 개념 상 분리
    • ex. 카카오 인가 서버 https://kauth.kakao.com

  1. Resource Server(자원 서버, API 서버)
    • 실제 데이터를 가지고 있는 서버
    • 유효한 access token을 가진 요청만 받아준다.
    • ex. 카카오 API 서버, 구글 API 서버


인가 유형 (Grant Type)

  1. Authorization Code
  2. Client Credentials
  3. Implicit
  4. Resource Owner Password Credentials

1번이 웹/모바일 환경에서의 가장 표준이고, 2번은 서버 ↔ 서버 간에 자주 사용된다고 한다.

나머지는 거의 사용하지 않는다고 한다. 최근에는 몇 개 더 나왔다던데 그냥 이런 것도 있다~만 알아두면 될 것 같다.



Authorization Code 흐름

1. 클라이언트 → 우리 서버로 로그인 요청을 한다.

  • 요청 예시

    GET https://api.fittoring.com/kakao/login


2. 우리 서버는 요청을 인증 서버 Authorization Server 로 리다이랙트한다.

이때 중요한 파라미터들이 있다.

  • client_id : 인가 서버에 등록된 우리 앱의 ID
  • redirect_uri : 인가 서버가 인가 코드를 보내줄 콜백 주소. (보통 앱 서버 콜백 API)
  • state : CSRF 방지용 랜덤값
    • 서버가 생성하여 세션 등에 저장하고 콜백과 검증
  • 요청 예시
    GET https://kauth.kakao.com/oauth/authorize
      ?response_type=code
      &client_id=OUR_CLIENT_ID
      &redirect_uri=https://our-service.com/auth/kakao/callback
      &state=random_string

3. 사용자가 인가 서버로부터 로그인 페이지를 응답 받고, 로그인/인가 동의


4. 인가 서버 → 우리 서버로 Authorization Code 발급

  • 2번에서 넘겼던 state 값도 같이 온다.
    • 요청 예시
      GET https://api.fittoring.com/kakao/callback?code=AUTH_CODE&state=random_string

5. 우리 서버 → 인가 서버로 code 를 포함해 토큰(access token)을 요청

  • 이 토큰이 있으면 자원 서버로 사용자 정보를 요청할 수 있다.
    • 요청 예시

      POST https://kauth.kakao.com/oauth/token      
      Content-Type: application/x-www-form-urlencoded
      
       grant_type=authorization_code
       &client_id=OUR_CLIENT_ID
       &redirect_uri=https://our-service.com/auth/kakao/callback
       &code=AUTH_CODE
    • 응답 예시

      {
        "access_token": "xxx",
        "token_type": "bearer",
        "expires_in": 3600,
        "refresh_token": "yyy",
        "scope": "profile_nickname account_email"
      }

6. 우리 서버 → 자원 서버로 access token을 이용해 사용자 정보(카카오id, 닉네임 등) 요청

  • 요청 예시
    GET https://kapi.kakao.com/v2/user/me

7. 자원 서버에서 받은 사용자 정보를 기반으로 우리 서버 자체 로그인 처리

  • 서비스 세션 or JWT 발급하여 로그인 처리한다.
    • accecss token으로 /userinfo를 요청해보고 응답이 잘 오면 ‘카카오가 인증한 사용자’라고 해석하여 우리 서비스가 로그인을 해주는 방식이다.

여기까지가 OAuth로 소셜 로그인을 구현하는 흐름이다. 간단히 정리하면 아래와 같다.

  1. 인증 서버에서 Access Token을 받는다. (인가)
  2. Access Token에는 사용자에 대한 정보가 없다. 따라서 Access Token으로 리소스 서버에 사용자 정보를 요청해서 ID/이메일 등의 정보를 가져온다. (인증)


OIDC

엄밀히 말하면 위의 과정은 불완전하다.

OAuth는 인가 프레임워크일뿐 인증 방법을 표준화 해두지 않았다.

인가 서버로부터 사용자 정보를 요청할 수 있는 권한(access token)을 받은 것이고, 이 토큰이 누구의 것인지 확인하는 인증의 과정이 없기 때문이다. 이것은 아래의 문제를 야기했다.

  1. 불필요한 네트워크 왕복을 동반한다. 대부분의 서비스는 사용자 정보를 필요로 하기 때문에 인증 서버에서 접근 권한을 얻은 후에 리소스 서버에 사용자 정보를 요청해야 했다.

  2. IdP(Id Provider, 구글 카카오 등)마다 사용자 정보를 응답하는 형식이 달라 개발자가 고생한다.


이러한 문제를 해결하기 위해 OAuth 위에 표준화된 인증 레이어를 올려놓은 것이 OIDC이다.

Q. 사용자가 직접 구글,카카오 로그인을 했는데 인증 된 거 아닌가?

IdP입장에서는 사용자를 인증한 것이 맞다. 그런데 우리 서버에서는 아직 사용자의 신원을 확인하지 않았다.

만약 리소스 서버에 사용자 정보를 요청하는 과정에서 사용자의 access token을 중간에 가로챈 공격자가 자신의 access token을 넣으면

  • 사용자는 공격자의 정보를 들고 우리 서버에 로그인 하게 될 것이다. OIDC를 활용해 이런 문제를 예방할 수 있다.


OIDC는 OAuth 위에 id_token 이라는 JWT로 인증 과정을 얹은 것이다.

OIDC를 활성화하면 위의 인가 코드 흐름 5.에서 access token과 함께 id_token도 받게 된다.

클라이언트는 이 id_token의 유효성만 확인하면 별도의 API 호출 없이 사용자의 핵심 신원 정보(Claim)를 즉시 얻을 수 있다.

OAuth와 OIDC

OAuth는 인가 프로토콜, OIDC는 OAuth에 인증을 추가한 인증·인가 프로토콜이다.

OAuth가 체크인 시, 호텔 카드키를 받는 과정이라면

OIDC는 체크인 시, 호텔 카드키와 신분증을 받는 과정이다.

OAuth와 OIDC 동작 차이

기본적으로 OAuth 플로우 위에서 돌아가지만 몇 가지 차이가 있다.

  1. scope 추가
    • 인증 요청 시, 기본 OAuth 스코프 외에 openid 스코프를 반드시 포함해야 한다. 이는 "OIDC 인증을 수행하겠다"는 의도를 IDP에게 명시적으로 알리는 것입니다.
  1. 검증 의무: ID 토큰은 JWT 형식이므로, 클라이언트 서버는 다음과 같은 암호학적 검증을 수행해야 한다.
    • 서명(Signature) 검증: IDP의 공개 키를 사용하여 토큰이 변조되지 않았고 IDP가 발급한 것이 맞는지 확인
    • iss (Issuer) 클레임 확인: 토큰 발급자가 우리가 예상한 IDP가 맞는지 확인
    • aud (Audience) 클레임 확인: 토큰의 수신자가 우리 서버의 client_id가 맞는지 확인 (가장 중요)
    • exp (Expiration) 클레임 확인: 토큰이 만료되지 않았는지 확인

현재는 OAuth에 OIDC를 얹어 사용하는 것이 IdP를 통한 인증과 인가의 표준이라고 할 수 있다.

0개의 댓글