OAuth 2026, 안전한 권한 위임과 인증 방식 완벽 가이드

OAuth: 안전한 권한 위임의 핵심

저도 처음 토이 프로젝트 만들 때 이런 삽질 한 번 했습니다. ‘오늘의 일기’라는 작은 웹사이트를 만들고 있었는데요. 사용자의 구글 캘린더에 그날 기분을 이모티콘으로 남기는, 딱 그 정도 기능이었어요.

문제는 구글 캘린더에 접근하려면 “그럼 구글 아이디랑 비밀번호를 받아야 하나?” 같은 생각이 스멀스멀 올라오더라고요. 근데 그거, 진짜 하면 안 됩니다. 제 허술한 웹사이트가 해킹이라도 당하면 사용자 구글 계정이 통째로 털릴 수도 있잖아요.

그때 저를 구해준 게 OAuth였어요. 비밀번호를 직접 받지 않고도, 필요한 범위의 권한만 안전하게 위임받는 방식이요. 요즘 우리가 “Google 계정으로 로그인”, “카카오로 계속하기” 버튼을 너무 당연하게 누르는데, 그 뒤에서 조용히 굴러가는 약속이 OAuth라고 보시면 됩니다.

쌩초보 때는 인증이니 인가니 단어부터 헷갈리는데요. 오늘은 그 부분부터 편하게 정리해볼게요.

OAuth란 무엇인가?

image

oauth란

OAuth(Open Authorization)는 말 그대로 ‘개방형 인가’를 위한 표준 규약입니다. 여기서 핵심은 인증(Authentication)이 아니라 인가(Authorization)라는 점이에요. 이거 한 번만 제대로 잡아두면, OAuth 흐름이 훨씬 덜 무섭게 느껴집니다.

OAuth는 ‘인증’이 아니라 ‘인가’를 위한 표준 규약입니다.

아래 표로 인증과 인가를 딱 갈라서 볼게요.

구분 인증 (Authentication) 인가 (Authorization)
목적 신원 확인 (본인이 맞는지 확인) 권한 확인 (특정 자원에 접근할 권한이 있는지 확인)
예시 아이디/비밀번호 입력, 생체 인식 (지문, 얼굴) 카드키 발급, 특정 앱에 구글 캘린더 접근 권한 부여
질문 “당신이 정말 본인이 맞나요?” “이 데이터를 조회하거나 이 기능을 써도 괜찮을까요?”
핵심 요소 신분 증명 (로그인 정보) 권한 위임 (액세스 토큰)

호텔로 비유하면 더 쉬워요. 프론트에서 신분증 보여주고 “제가 예약한 사람 맞아요” 확인받는 게 인증입니다. 그리고 직원이 마스터키 대신, 내 방만 열리는 카드키를 주죠. 그 카드키를 받는 게 인가예요.

OAuth는 사용자의 비밀번호(마스터키)를 앱이 들고 있지 않게 하면서, 대신 이런 식으로 제한된 권한만 주는 구조입니다.

> “이 앱이 내 구글 캘린더 정보에만 접근하는 건 허락할게요.”

이 카드키가 기술적으로는 토큰(Token)이고요. 보통 시간 제한이랑 권한 범위 제한이 걸려 있어서 훨씬 안전해집니다.

image

oauth 2.0 개념

OAuth 2.0은 2012년에 나온 두 번째 버전이고, 우리가 실무에서 말하는 OAuth는 거의 다 2.0이라고 보시면 됩니다. 1.0에 비해 훨씬 간결해졌고, 모바일 환경도 잘 지원하도록 정리됐어요.

OAuth 2.0은 이전 버전에 비해 간결해지고 역할 분리가 명확해진 게 핵심입니다.

OAuth 1.0은 요청마다 암호화 서명 만들고 붙이고… 이게 꽤 빡셌거든요. 2.0은 그걸 과감히 덜어내고, 대신 통신 자체를 HTTPS로 안전하게 하자는 쪽으로 갔습니다. 주소창 자물쇠 그거요.

그리고 OAuth 2.0이 이해하기 쉬운 이유 중 하나가, 등장인물을 네 가지로 딱 나눠놨다는 점이에요. 저도 이거 보고 흐름이 정리되더라고요.

  1. 리소스 소유자 (Resource Owner)사용자입니다. 데이터의 주인이죠.
  2. 클라이언트 (Client)는 그 데이터에 접근하려는 입니다. (예: ‘오늘의 일기’ 웹사이트)
  3. 리소스 서버 (Resource Server)는 데이터가 실제로 있는 서버입니다. (예: 구글 캘린더 API 서버)
  4. 인가 서버 (Authorization Server)는 사용자 동의 받고, 액세스 토큰을 발급해주는 서버입니다. (예: 구글 로그인/동의 화면)

역할이 이렇게 나뉘어 있으면, 서비스가 커져도 책임 분리가 잘 돼서 운영이 편해집니다. 실무에서 “설계 잘 됐다” 싶은 것들 보면 대체로 이런 식으로 경계가 깔끔하더라고요.

image

OAuth의 버전별 특징은 무엇인가요?

image

oauth 2.0

구글, 페이스북, 네이버, 카카오 같은 데가 다 쓰는 방식이라 사실상 표준입니다. 여기서 핵심은 토큰이 두 종류라는 거예요. 액세스 토큰(Access Token)이랑 리프레시 토큰(Refresh Token)이요.

왜 굳이 둘로 나누냐면, 보안이랑 편의성 둘 다 챙기려는 거라고 보시면 됩니다.

표로 한 번 비교해볼게요.

구분 액세스 토큰 (Access Token) 리프레시 토큰 (Refresh Token)
목적 보호된 자원에 실제 접근하는 데 사용 액세스 토큰 만료 시 재발급 용도
유효 기간 매우 짧음 (예: 1시간) 매우 김 (예: 몇 주 또는 몇 달)
저장 위치 클라이언트 (앱 메모리 등) 클라이언트 (보안 저장소), 인가 서버 (DB)
보안 주의 탈취 시 피해 최소화를 위해 짧은 유효 기간 필수 철저하게 안전하게 보관되어야 합니다 (민감한 정보)

핵심은 액세스 토큰과 리프레시 토큰, 이 두 개가 한 팀으로 움직인다는 겁니다.

액세스 토큰만 있으면 만료될 때마다 사용자가 계속 로그인해야 해서 UX가 박살 나요. 그래서 리프레시 토큰을 길게 들고 있다가, 액세스 토큰이 만료되면 조용히 재발급 받는 구조로 갑니다. 대신 리프레시 토큰은 진짜 민감해서, 보관을 대충 하면 사고 납니다. 이건 “나중에”가 아니라 “언젠가” 터져요.

OAuth 2.0은 환경에 따라 여러 인가 흐름(Grant Type)을 제공하는데요. 실무에서 가장 표준이고 안전하다고 보는 건 인가 코드 승인 방식(Authorization Code Flow)이고, 요즘은 여기에 PKCE까지 붙이는 게 정석입니다. 조금 귀찮아도 보안 쪽은 안전한 길로 가는 게 결국 덜 삽질하더라고요.

image

Table of Contents

oauth2

이것이랑 그것은 그냥 줄여 부르는 말 차이이고, 기술적으로는 같은 걸 가리킵니다. API 호출할 때는 보통 액세스 토큰을 HTTP 요청의 Authorization 헤더에 Bearer 방식으로 넣습니다. 이런 형태죠.

Authorization: Bearer <토큰값>

Bearer는 “이 토큰을 가진 사람에게 권한을 주세요” 정도로 이해하시면 됩니다.

> “이 토큰을 소지한 이에게 권한을 허락해 주세요.”

요즘은 액세스 토큰 형식으로 JWT(JSON Web Token)도 많이 씁니다. JWT의 장점은 API 서버가 매번 인가 서버에 “이 토큰 진짜예요?” 물어보지 않고, 서명 검증만으로 유효성을 확인할 수 있다는 점이에요. 응답도 빨라지고, 인가 서버 부담도 줄고요.

JWT는 JSON 데이터를 담은 토큰이라, 느낌상 ‘디지털 신분증’에 가깝습니다. 누가 발급했는지, 언제까지 유효한지, 어떤 권한(scope)인지 같은 게 들어 있고, 서명이 있어서 위조가 어렵습니다.

oauth2.0

이 명칭도 결국 같은 프로토콜을 부르는 말입니다. 복잡한 암호화 서명 대신 HTTPS를 믿는 쪽으로 가면서 구현 난이도가 내려갔고요. 그리고 이게 “딱 하나의 규칙”이라기보단 확장 가능한 프레임워크라서, PKCE나 Device Flow 같은 것들이 계속 붙으면서 발전 중입니다.

저도 사이드로 사진 정리 앱 만들면서(구글 포토 연동) 이걸 제대로 처음 붙여봤는데요. 로그인 버튼 누르면 구글 동의 화면으로 넘어가고, 동의 끝나면 제 서버로 authorization_code가 돌아오는 그 흐름이 처음엔 되게 신기하더라고요.

그 코드로 토큰 엔드포인트를 때려서 access_token이랑 refresh_token 받았을 때는 “오 된다” 싶었고요. 처음엔 프론트에서 다 처리하려다가 보안 이슈를 뒤늦게 깨닫고, 백엔드에서 토큰을 관리하는 구조로 바꿨던 것도 아직 기억납니다. 이런 삽질 한 번 하고 나면 OAuth가 남 얘기가 아니게 돼요.

oauth 2.1

OAuth 2.1은 지금 개발 진행 중인 다음 버전입니다. 완전 새로 만드는 느낌이라기보단, 지난 10여 년 운영하면서 쌓인 보안 모범 사례를 표준에 박아 넣은 ‘개선판’에 가깝습니다. 개발자가 실수하기 쉬운 구간을 줄이고, 기본값부터 더 안전하게 가자는 방향이에요.

변경점은 대략 이런 쪽입니다.

PKCE(Proof Key for Code Exchange) 필수화는 이제 “권장”이 아니라 “무조건”에 가까워졌고요.
Implicit Flow 완전 제거도 들어갔습니다. 이건 보안적으로 너무 약했어요.
리다이렉트 URI 정확히 일치도 더 엄격해졌습니다. https://.example.com 같은 와일드카드 등록을 막고, 등록된 주소랑 정확히 일치할 때만 코드가 가게 하는 식이죠.
리프레시 토큰 순환(Refresh Token Rotation) 권장도 많이들 챙기는 흐름입니다.

개인적으로 PKCE가 기본 사양이 된 건 진짜 반가운 변화예요. 모바일 앱이나 SPA 만들 때 “이거 시크릿 못 숨기는데…” 같은 고민을 꽤 덜어주거든요.

image

OAuth는 어떻게 인증(인가) 방식을 사용하나요?

image

oauth 인증

현업에서 “OAuth 인증”이라고 많이 말하긴 하는데, 엄밀히는 반쯤만 맞는 표현입니다. OAuth의 본질은 인증이 아니라 인가예요. OAuth 자체는 “이 사람이 김민준 맞나요?”를 증명해주기보단, “이 앱이 김민준 님 캘린더에 접근해도 되나요?” 같은 권한 동의에 집중합니다.

근데 현실에서는 “Google 계정으로 로그인”처럼 인증 용도로도 많이 쓰이죠. 원리는 이렇습니다. 앱이 OAuth로 액세스 토큰을 받고, 그 토큰으로 사용자 정보 API를 호출해서 이메일이나 이름을 가져옵니다. 그리고 “구글이 토큰을 줬다는 건, 구글에서 로그인은 이미 끝난 사용자겠지” 하고 신뢰하는 방식이에요.

다만 로그인(인증)을 제대로 표준으로 하고 싶으면, 더 정석이 있습니다. OpenID Connect(OIDC)요. OIDC는 OAuth 2.0 위에 인증을 얹은 표준이고, 여기서는 액세스 토큰 말고도 ID 토큰(ID Token)을 추가로 받습니다. 이 ID 토큰에 신원 정보가 표준화된 형태로 들어 있고 서명도 되어 있어서, 앱이 토큰 검증만으로 “인증 완료”를 더 깔끔하게 처리할 수 있어요.

저도 예전엔 OAuth만으로 로그인 구현하고 “끝” 했는데, OIDC로 ID 토큰까지 써보면 확실히 마음이 편해집니다.

image

oauth2 인증방식

OAuth는 환경에 따라 여러 인가 흐름(Flow)을 제공합니다. 그래서 내 앱 특성에 맞는 걸 고르는 게 중요해요. 근데 쌩초보 입장에서는 선택지가 많으면 더 무섭죠.

요즘 기준으로는 PKCE 붙인 인가 코드 승인 방식이 가장 안전하고, 가장 많이 쓰는 정석입니다.

대표적인 흐름은 이런 느낌이에요.

PKCE를 사용한 인가 코드 승인 방식 (Authorization Code Flow with PKCE)는 서버 있는 웹앱은 물론이고, 모바일 앱이나 SPA에서도 사실상 이걸 쓰는 게 맞습니다. 액세스 토큰이 브라우저에 직접 노출되는 걸 막고, 안전한 통신으로 교환하게 만들어요.
클라이언트 자격증명 승인 방식 (Client Credentials Flow)은 사용자 없이 서버 대 서버로 붙을 때 씁니다. 예를 들면 우리 백엔드가 다른 서비스 API를 호출하는 상황이요.
기기 인가 승인 방식 (Device Authorization Flow)은 TV나 콘솔처럼 입력이 불편한 기기에서 쓰는 방식입니다.

실무에서는 진짜 대부분, 거의 99%는 Authorization Code Flow with PKCE로 갑니다. 다른 것들은 특수 케이스가 아니면 굳이 고민할 일이 많지 않더라고요.

image

oauth 2.0 인증 방식

그랜트 타입들을 조금 더 비교해보면, 왜 어떤 건 사라지고 어떤 게 표준이 됐는지 감이 옵니다.

그랜트 타입 특징 현재 권장 여부
인가 코드 승인 (Authorization Code Grant) 가장 기본적이고 안전한 방식입니다. 서버를 가진 웹 애플리케이션을 위해 설계되었고, 액세스 토큰이 브라우저에 직접 노출되지 않게 해서 보안성이 높습니다. PKCE와 같이 쓰면 더 안전해요. 권장
암시적 승인 (Implicit Grant) 예전 SPA에서 쓰던 방식인데, 액세스 토큰이 브라우저로 바로 넘어가서 탈취 위험이 큽니다. 리프레시 토큰도 못 쓰는 등 약점이 많아서 지금은 사실상 금지입니다. 사용 금지
자원 소유자 암호 자격증명 승인 (Resource Owner Password Credentials Grant) 사용자 아이디/비밀번호를 앱에 직접 입력하는 방식입니다. OAuth 철학이랑 정면으로 충돌해서, 지금은 권장되지 않습니다. 사용 금지
클라이언트 자격증명 승인 (Client Credentials Grant) 사용자 없이 서버 대 서버 통신에서 씁니다. (예: 백엔드가 다른 서비스 API 호출) 권장
  1. 인가 코드 승인 (Authorization Code Grant)은 기본 중의 기본이고, 서버가 있는 웹앱에서 특히 안전합니다.
  2. 암시적 승인 (Implicit Grant)은 예전엔 쓰기도 했는데, 지금은 절대 쓰면 안 되는(deprecated) 쪽으로 정리됐습니다. OAuth 2.1에서는 아예 빠졌고요.
  3. 자원 소유자 암호 자격증명 승인 (Resource Owner Password Credentials Grant)은 “비밀번호를 제3자에게 주지 않는다”는 OAuth 기본 철학이랑 충돌합니다. 예외적으로 공식 앱 같은 케이스가 있었지만, 지금은 거의 안 씁니다.
  4. 클라이언트 자격증명 승인 (Client Credentials Grant)은 사용자 없는 M2M 통신에서 여전히 유효합니다.

정리하면, 요즘 웹/앱 개발에서는 Authorization Code Flow with PKCE가 거의 정답에 가깝습니다. 이걸로 가면 큰 사고 날 확률이 확 내려가요.

서비스들이 서로 데이터를 주고받는 시대라, “안전하게 연결하는 법”은 선택이 아니라 필수입니다. OAuth는 그 연결을 표준화해서 안전하게 만들어주는 열쇠 같은 존재고요. 처음엔 용어가 낯설어서 막막한데, 한 번 흐름이 보이기 시작하면 생각보다 금방 익숙해집니다. 중간에 삽질해도 정상이에요. 막히는 포인트 있으면 그 부분만 딱 집어서 같이 풀어보면 됩니다.

image

FAQ

Q1: OAuth와 OpenID Connect(OIDC)의 가장 큰 차이점은 무엇인가요?

A: 목적이 다릅니다. OAuth 2.0은 특정 자원에 접근할 수 있는 권한, 즉 액세스 토큰을 주는 인가에 초점이 있어요. OpenID Connect(OIDC)는 OAuth 2.0 기반으로 인증을 표준화한 프로토콜이고, ID 토큰으로 신원 정보를 다룹니다. 소셜 로그인처럼 “로그인”이 목적이면 OIDC가 더 정석입니다.

Q2: 액세스 토큰과 리프레시 토큰은 왜 둘 다 필요한가요?

A: 보안이랑 편의성 둘 다 챙기려고요. 액세스 토큰은 API 호출용이라 유효기간을 짧게 잡는 게 일반적입니다. 근데 그것만 있으면 만료될 때마다 사용자가 계속 로그인해야 해서 불편하죠. 그래서 리프레시 토큰을 길게 들고 있다가, 액세스 토큰이 만료되면 재로그인 없이 재발급 받습니다. 대신 리프레시 토큰은 민감해서 보관을 정말 조심해야 합니다.

Q3: PKCE(Proof Key for Code Exchange)는 무엇이며 왜 중요한가요?

A: PKCE는 ‘픽시’라고 읽고요. 모바일 앱이나 SPA처럼 클라이언트 시크릿을 숨기기 어려운 환경에서, 인가 코드 가로채기 공격을 막는 장치입니다. 앱이 요청 시작할 때 code_verifier를 만들고, 해시한 code_challenge를 먼저 보냅니다. 나중에 토큰 교환할 때 원본 code_verifier를 같이 보내서, 인가 서버가 “처음 요청한 앱이 맞네”를 확인하는 구조예요.

Q4: ‘Implicit Flow’ 방식이 더 이상 권장되지 않는 이유는 무엇인가요?

A: 액세스 토큰이 URL 프래그먼트(#)로 브라우저에 직접 전달되는 방식이라 유출 위험이 큽니다. 브라우저 기록, 로그, 리퍼러 같은 데로 새기 쉬워요. 리프레시 토큰도 못 받아서 만료되면 다시 인증해야 하고요. 그래서 지금은 Authorization Code Flow with PKCE로 가는 걸 강하게 권장합니다. OAuth 2.1에서는 아예 제거됐습니다.

Q5: OAuth 2.0과 앞으로 나올 OAuth 2.1의 가장 큰 차이점은 무엇인가요?

A: 2.1은 새로 발명했다기보단, 2.0을 운영하면서 쌓인 보안 베스트 프랙티스를 표준에 통합한 개선판에 가깝습니다. PKCE를 필수로 더 강하게 가져가고, Implicit Flow를 제거하는 등 기본적으로 더 안전한 선택을 하게 만드는 방향으로 정리되고 있습니다.

댓글 남기기