들어가면서
Cookie, Session, Token, JWT, 인증과 인가와 같은 내용들에 대해서 공부를 하다보니 빼놓으면 섭섭한 개념이 있었다. 오늘 포스팅 내용인 OAuth이다. 대충 무엇인지 알고는 있었지만 자세하게 찾아보고 공부해본 적은 없었기에 이번에 공부한 내용을 공유하려고 한다!
OAuth란?
정의는?
인터넷 사용자들이 비밀번호를 제공하지 않고 다른 웹 사이트 상의 자신들의 정보에 대해 웹사이트나 애플리케이션의 접근 권한을 부여할 수 있는 공통적인 수단으로서 사용되는 접근 위임을 위한 개방형 표준
Open Authorization의 약자로, 쉽게 설명을 해보자면 우리가 어떠한 웹 사이트나 어플을 다운받아서 로그인을 할 때 회원가입을 진행하는 것이 아닌 카카오 로그인이나 네이버 로그인으로 대체하는 것이다.
즉, ID와 PW를 입력하는 것이 아니라 다른 외부 애플리케이션의 Open API의 ID와 PW를 입력하여 해당 애플리케이션이 인증 과정을 처리해주는 방식이다!
구성 요소는?
그렇다면 이 OAuth의 구성요소는 무엇이 있을까?
- 리소스 소유자(Resource Owner)
: 자원에 대한 접근 권한을 가진 사용자
- 클라이언트(Client)
: 리소스 소유자를 대신하여 자원에 접근하려는 애플리케이션 서버
- 리소스 서버(Resource Server)
: 보호된 리소스를 호스팅하는 서버
- 인증 서버(Authorization Server)
: 클라이언트를 인증하고 Access Token을 발급하는 서버
역사는?
OAuth 1.0
OAuth 1.0은 2007년에 등장하였으며 사용자 비밀번호를 직접 공유하지 않고 제 3자 애플리케이션이 사용자의 데이터를 안전하게 접근할 수 있는 방법이 무엇이 있을까? 라는 생각에서 개발이 진행되었다.
즉, 이 OAuth 1.0은 인터넷 상의 애플리케이션 간의 리소스 접근을 안전하게 처리하기 위해서 개발이 되었다!
주요 특징은 다음과 같다.
- 서명 기반 인증 : 요청에 서명을 추가하여 요청의 무결성을 보장, 이때 서명은 클라이언트 비밀과 요청 데이터를 기반으로 생성
- 비밀번호 공유 방지 : 사용자 비밀번호를 제3자 애플리케이션과 공유하지 않고도 리소스에 접근할 수 있게 함
다만 이 OAuth 1.0에는 다음과 같은 문제점도 존재했다.
- 복잡한 서명 프로세스
: 서명 계산이 복잡하여 구현하기 어렵고, 요청의 모든 부분을 서명해야함
- 보안 문제
: 서명 방식의 복잡성으로 인해 구현 오류가 발생할 수 있었고, 보안에 취약할 수 있음
OAuth 2.0
따라서 2012년 OAuth의 문제점을 개선한 OAuth 2.0이 등장하게 되었다.
OAuth 2.0은 OAuth 1.0의 복잡성을 줄이고 조금 더 간단한 인증 및 권한 부여 방식을 제공하며, 더 많은 권한 부여 방식과 확장성을 제공했다!
OAuth 2.0의 주요 특징은 다음과 같다.
- Token 기반 인증
: 서명 대신 Access Token을 사용하여 리소스 접근을 인증, 이로 인해 서명 계산의 복잡성을 줄이고, 다양한 Token 타입과 검증 방법을 지원
- 권한 부여 방식
: 여러 가지 권한 부여 흐름을 지원
ex) 권한 부여 코드, 암시적 승인, 자격 증명 승인, 클라이언트 자격 증명 등
- 유연성
: 다양한 클라이언트 애플리케이션과 보안 요구 사항을 지원하기 위해 더 많은 유연성을 제공
- Refresh Token
: Access Token이 만료된 후 새로운 Token을 발급받을 수 있는 Refresh Token을 도입하여 Session의 연속성을 제공
또한, OAuth 2.0의 확장으로 OIDC라는 것이 개발이 되었다!
OIDC란 OAuth 2.0 프로토콜을 기반으로 상위계층에서 간편하게 인증을 처리하며, 신원확인 서비스(IDP)를 통해 안전한 방식으로 사용자의 정보를 제공하는 방식이다. 이때 카카오, 네이버, 구글 등이 여기에 해당된다!
그럼 OIDC가 더 좋은 거 아니야? 기반으로 더 간편하게 인증한다며? 라고 생각할 수 있는데, 느낌이 살짝 다르다는 것을 알아야한다.
OIDC는 사용자의 인증 및 사용자의 정보를 제공하는 인증을 처리하기 위해서 만들어졌고, OAuth는 권한 허가인 인가를 처리하기 위해서 만들어진 표준 프로토콜인 것이다.
인증과 인가의 차이는 여기에서 자세히 알아보자!
OAuth 2.1
또한 OAuth 2.0의 복잡성을 줄이고 보안을 강화하기 위해서 2021년 OAuth 2.1이 등장했다!
OAuth 2.0의 주요 권장 사항과 보안 모범 사례 등을 통합하여 더 간단하고 일관된 표준을 제공한다.
OAuth 2.1의 주요 특징에 대해서 살펴보자.
- 단순화
: OAuth 2.0의 여러 권장 사항을 통합하여 더 간단하고 명확한 표준을 제공
- 보안 강화를 위한 조치
: 비밀번호 기반 승인(Resource Owner Password Credentials Grant)과 같은 오래된 방식을 폐기하거나 제한
- 보안 권장 사항
: HTTPS 사용을 강제하고, 클라이언트와 서버 간의 보안을 강화하기 위한 추가 권장 사항을 포함
그럼 지금은 뭘 쓰는데?
지금 이렇게 여러 버전이 나왔고, 결국 우리는 어떤 버전을 사용할지 선택을 해야한다.
새로운 거 쓰면 좋은 거 아니야? 라고 생각할 수 있지만, 새로운 것에는 적응의 기간이 필요한 법이다. 또한 개발자들은 안정화된 Release 버전을 사용하는 것을 선호한다.
현재는 OAuth 2.0을 주로 사용하는 추세이다. 그 이유는 다음과 같다.
- 채택된 표준
: 현대의 대부분의 웹 애플리케이션 및 API에서 채택된 표준이기에 다양한 서비스와의 호환성이 보장
- 유연성 및 확장성
: 다양한 권한 부여 흐름을 제공하며, 다양한 클라이언트 애플리케이션 및 리소스 서버 요구 사항을 충족할 수 있음
- Refresh Token
: Acess Token이 만료된 후에도 Session을 연속적으로 유지할 수 있도록 Refresh Token을 지원
- 구현 용이성
: 서명 기반 인증의 복잡성 없이, 상대적으로 간단하게 구현 가능
다만 그렇다고 OAuth 2.1을 아예 배제하라는 뜻은 아니다.
결국 OAuth 2.1은 OAuth 2.0의 개선된 버전으로 보안 강화를 목표로 하기 때문에 최신 보안 요구 사항과 권장 사항을 반영하기 위해 OAuth 2.1을 고려할 수 있으며, 특히 새로운 애플리케이션이나 서비스에서는 OAuth 2.1을 채택하는 것이 바람직할 수도 있다!
동작 방식은?
우리는 자주 사용하는 OAuth 2.0을 기준으로 설명을 진행하겠다!
OAuth 2.0는 인가의 동작을 하기 위해서 만들어졌다고 했다. 인가란 권한을 부여하는 과정이다. 따라서 클라이언트의 권한 부여 방식에 대해서 설명을 해보겠다.
현재 OAuth 2.0은 다양한 클라이언트 환경에 적합하도록 권한 부여 방식에 따른 프로토콜을 4가지 종류로 구분하여 제공하고 있다. 이에 대해서 하나씩 살펴보자.
- 권한 부여 코드 승인 (Authorization Code Grant)
- 가장 일반적인 승인 방식
- 사용자가 클라이언트를 승인하면, 인증 서버는 클라이언트에 권한 부여 코드를 제공
- 클라이언트는 이 코드를 사용하여 인증 서버로부터 Access Token을 받음
- 동작 방식

- 사용자 인증 요청
: 사용자가 애플리케이션(클라이언트)에 로그인하려고 할 때, 애플리케이션은 인증 서버(Authorization Server)로 redirection하여 사용자에게 로그인 및 권한 부여를 요청
- 권한 부여 코드 발급
: 사용자가 인증 서버에서 로그인하고 애플리케이션의 접근 요청을 승인하면, 인증 서버는 권한 부여 코드를 발급하여 애플리케이션으로 redirection
- Access Token 요청
: 애플리케이션은 권한 부여 코드를 사용하여 인증 서버에 Access Token을 요청
- Access Token 발급
: 인증 서버는 애플리케이션의 요청을 검증한 후 Access Token을 발급
- 리소스 접근
: 애플리케이션은 발급받은 Access Token을 사용하여 리소스 서버(Resource Server)에서 보호된 리소스에 접근
- 암시적 승인 (Implicit Grant)
- 자격증명을 안전하게 저장하기 힘든 클라이언트에게 최적화된 방식
ex) JavaScript 애플리케이션
- 클라이언트는 권한 부여 코드 없이 직접 Access Token을 받음
- 동작방식

- 사용자 인증 요청
: 사용자가 애플리케이션에 로그인하려고 할 때, 애플리케이션은 인증 서버로 redirection하여 사용자에게 로그인 및 권한 부여를 요청
- Access Token 발급
: 사용자가 인증 서버에서 로그인하고 애플리케이션의 접근 요청을 승인하면, 인증 서버는 Access Token을 발급하여 애플리케이션으로 redirection, 이 과정에서 권한 부여 코드가 생략
- 리소스 접근
: 애플리케이션은 받은 Access Token을 사용하여 리소스 서버에서 보호된 리소스에 접근
- 자격 증명 승인 (Resource Owner Password Credentials Grant)
- 사용자 자격 증명(사용자 이름 및 비밀번호)을 직접 사용하는 방식
- 주로 클라이언트와 리소스 소유자가 높은 신뢰 관계에 있을 때 사용
- 동작방식

- 사용자 자격 증명 제출
: 사용자가 애플리케이션에 로그인 시 사용자 이름과 비밀번호를 입력
- Access Token 요청
: 애플리케이션은 사용자의 자격 증명을 직접 사용하여 인증 서버에 Access Token을 요청
- Access Token 발급
: 인증 서버는 사용자의 자격 증명을 검증한 후 Access Token을 발급
- 리소스 접근
: 애플리케이션은 발급받은 Access Token을 사용하여 리소스 서버에서 보호된 리소스에 접근
- 클라이언트 자격 증명 승인 (Client Credentials Grant)
- 클라이언트가 자신의 자격 증명(Client ID 및 Client Secret)을 사용하여 Access Token을 요청
- 주로 서버 간 통신(M2M)에서 사용
- 동작방식

- 클라이언트 자격 증명 제출
: 클라이언트 애플리케이션이 자신의 자격 증명(Client ID와 Client Secret)을 사용하여 인증 서버에 Access Token을 요청
- Access Token 발급
: 인증 서버는 클라이언트의 자격 증명을 검증한 후 Access Token을 발급
- 리소스 접근
: 클라이언트 애플리케이션은 발급받은 Access Token을 사용하여 리소스 서버에서 보호된 리소스에 접근
OAuth와 JWT?
사실 어느 정도 감은 왔을 거라는 생각이 든다. Access Token과 Refresh Token을 보니 자연스럽게 떠오르는 단어가 있을 것이다. 바로 JWT이다.
OAuth 2.0 에서는 Access Token을 사용하여 클라이언트가 리소스 서버에 접근할 수 있는데 이 Access Token의 포맷으로 JWT가 널리 사용이 된다!
JWT에 대해서 간단하게 소개를 하자면 JWT는 JSON Web Token의 약자로 유저를 인증하고 식별하기 위한 Token이다.
JWT는 다음과 같은 장점이 있다.
- 자체 포함(Self-contained)
: Payload에 인증 정보와 Claim을 포함하여, 별도의 데이터 저장소에 의존하지 않고도 자체적으로 인증 정보를 담고 있음
- 서명 검증
: JWT는 서명되어 있어, 토큰의 무결성과 발급자를 검증할 수 있고, 리소스 서버는 Access Token의 유효성을 확인할 수 있음
- 확장성
: JWT는 JSON 포맷을 사용하여 다양한 정보를 Claim으로 포함 가능
이러한 장점들이 있기 때문에 JWT를 Access Token으로 사용하게 된다!
조금 더 자세하게 사용하는 예시를 들어보자면,
OAuth 2.0의 권한 부여 코드 승인에서 클라이언트 애플리케이션은 권한 부여 코드르 사용하여 Access Token을 요청하는데 이때 Access Token이 JWT 포맷이며, 클라이언트 애플리케이션은 이 JWT를 사용하여 리소스 서버에 접근하게 된다.
또한 OAuth 2.0의 암시적 승인에서 클라이언트 측 애플리케이션이 직접 Access Token을 받게 되는데 이때 Access Token의 형식이 JWT 포맷이다.
어떻게 구현하지?
필요한 라이브러리는?
실제로 OAuth 2.0을 Spring에서 구현하기란 쉽지 않다. 로직도 로직이지만 설정을 하는 부분에 있어서 많은 시간과 비용이 들기 때문이다. 많은 개발자들이 높은 장벽에 포기를 한 적도 있다고 한다..
하지만 Spring Security는 OAuth 2.0 프로토콜을 기반으로 애플리케이션에 OAuth 2.0 인증을 쉽게 통합할 수 있도록 지원한다. 따라서 Spring Security OAuth 2.0 모듈을 사용하면 우리가 원하는 소셜 로그인 또는 API 인증을 구현할 수 있는 것이다!
설정은 어떻게 하지?
그렇다면 어떻게 설정을 하고 구성을 할 수 있을까?
- 의존성 설정
: Maven 또는 Gradle을 사용하여 필요한 라이브러리를 프로젝트에 추가// Gradle 예시
dependencies {
// OAuth 2.0 클라이언트 기능을 제공하는 스타터
implementation 'spring-boot-starter-oauth2-client'
// OAuth 2.0 리소스 서버 기능을 제공하는 스타터
implementation 'spring-boot-starter-oauth2-resource-server'
}
- 애플리케이션 설정
- 애플리케이션 프로퍼티
: application.yml 또는 application.properties 파일에 OAuth2 제공자의 정보(예: 클라이언트 ID, 클라이언트 시크릿, 권한 부여 서버의 URL 등)를 설정
- Security Configuration
: Spring Security의 설정을 통해 OAuth2 클라이언트와 리소스 서버의 설정을 구성, 이를 통해 인증 서버와의 통신, JWT 검증 등의 설정 가능
- OAuth2 클라이언트 설정
- Authorization Server
: OAuth2 권한 부여 서버와의 통합을 위해 AuthorizationServerConfigurerAdapter를 상속받아 인증 서버를 설정, 이 설정은 클라이언트 애플리케이션이 권한 부여를 요청할 때 필요한 구성 요소를 제공
- Resource Server
: 리소스 서버의 설정을 통해 JWT를 검증하고 보호된 리소스에 접근할 수 있도록 설정, ResourceServerConfigurerAdapter를 상속받아 리소스 서버를 설정
- OAuth2 흐름 처리
- 다음의 4가지 중 하나의 흐름을 선택하여 그에 맞게 처리
- 권한 부여 코드 승인
: 사용자가 인증 서버에서 인증을 완료하면 권한 부여 코드가 발급, 클라이언트 애플리케이션은 이 코드를 사용하여 Access Token을 요청
- 암시적 승인
: 클라이언트 애플리케이션이 직접 Access Token을 받음
- 자격증명 승인
: 사용자가 자격 증명을 제공하고 클라이언트 애플리케이션이 Access Token을 요청
- 클라이언트 자격 증명 승인
: 클라이언트 애플리케이션이 자신의 자격 증명을 사용하여 Access Token을 요청
다른 라이브러리 및 도구는?
물론 OAuth를 구현하기 위해서는 Spring Security를 사용하는 것이 아닌 다른 라이브러리나 도구들을 사용하여 구현하는 방법도 존재한다.
- Apache Oltu
: OAuth 2.0 클라이언트 라이브러리로, Spring Security보다 더 낮은 수준에서 OAuth2 클라이언트를 구현할 수 있다. 그러나 Spring Security가 더 높은 수준의 추상화와 통합 기능을 제공하므로 주로 Spring 환경에서는 사용되지 않는다.
- Keycloak
: 인증 서버와 권한 부여 서버 기능을 제공하는 오픈소스 솔루션으로, Spring Boot와 통합하여 SSO(Single Sign-On) 및 권한 부여를 처리할 수 있다.
- Auth0
: 클라우드 기반 인증 및 권한 부여 플랫폼으로, Spring Boot 애플리케이션에 쉽게 통합할 수 있으며 OAuth2 및 OpenID Connect 지원을 제공한다.
다만, Spring Security는 Spring Boot 와의 통합이 원활하기 때문에 가장 널리 사용이 된다. 따라서 직접 세세한 설정을 하나씩 구현해보고 싶다고 한다면 위처럼 다른 라이브러리나 도구들을 사용하여 진행해도 된다!
정리하자면
OAuth는 인증 및 권한 부여를 위한 프로토콜이다!
OAuth 2.0의 동작 방식은 4가지가 있으며 각각의 특징을 기억해서 필요한 동작에 사용하자!