
저희가 사이트들 회원가입을 하다보면
이름을 입력하고 전화번호로 인증하고 그런 경우도 있지만
그냥 '구글로 로그인'처럼 다른 서비스의 계정을 이용해 로그인하는 경우도 있습니다. 오늘은 이 과정에서 사용되는 OAuth 인증·인가와 OIDC에 대해 알아보겠습니다.

OAuth(오픈 인증) : 오픈 인증은 사용자 계정의 로그인이나 비밀번호 없이도
애플리케이션이나 사진, 캘린더 또는 소셜 미디어 게시물과 같은 최종 사용자의 보호된 리소스에 액세스 할 수 있는 권한을 부여하는 개방형 표준 프레임워크입니다.
OAuth 프로토콜을 사용하면 사용자는 사용자 자격 증명을 공유하지 않고 이러한 애플리케이션에 계정 데이터에 대한 액세스 권한을 쉽게 부여할 수 있습니다.
그냥 이름 입력하고 비밀번호 입력해서 로그인하면 되는거 아닌가?
왜 그렇게 해야하지?
OAuth가 중요한 이유는 크게 두 개로 나눌 수 있습니다
1. 편함
2. 보안
이 부분은 OAuth가 "반드시 보안이 더 좋다"기 보다는, 정확히 왜 더 안전한지를 짚어보겠습니다.
OAuth를 쓰면?
구글, 카카오톡 등 한 곳에만 두니까 위험이 줄어듭니다.
이게 모든 사이트들보다 구글이나 카카오가 보안이 무조건 뛰어나다는 뜻이 아닌
상대적으로 내가 만든 작은 사이트보다 보안이 뛰어나다는 뜻입니다.
작은 사이트는 비번을 모름 : 작은 사이트들이 해킹을 당해도 OAuth를 사용해 구글 등으로 로그인하니 구글이 털리지 않는 이상 비밀번호는 털리지 않습니다.(로그인하는 사이트는 토큰만 받지 비밀번호 같은 정보는 안 받습니다.)
권한 세분화 / 취소 가능 : "이 앱에게 이메일만 보여주고, 게시글 작성 권한은 주지 마" 같은 식으로 접근 범위(scope)를 제한할 수 있고, 언제든 권한을 취소(revoke)할 수 있습니다.
사용자의 이름과 비밀번호에 의존하는 다른 프레임워크와 달리 OAuth는 액세스 토큰을 기반으로 하는 인증 프로토콜입니다.
액세스 토큰은 애플리케이션이 액세스할 수 있는 특정 리소스를 결정하는 정보입니다.
OAuth 프로토콜은 권한 부여 요청 프로세스의 각 구성 요소가 액세스 토큰을 승인, 정의 및 관리하는 방법을 정의합니다.

리소스 소유자 : 계정을 소유한 사용자, 해당 계정이 특정 보호된 리소스에 액세스할 수 있도록 동의합니다.
리소스 서버 : 사용자를 대신해 보호된 리소스를 저장하는 서버, OAuth 토큰을 수락하고 유효성 검사를 하고 사용자에게 데이터를 제공합니다.
고객(클라이언트) : 클라이언트는 액세스를 요청하는 애플리케이션, 웹사이트, API 또는 디바이스, 권한 부여 서버에 요청을 합니다. 클라이언트는 리소스에 액세스하는 데 사용할 수 있는 액세스 토큰을 받습니다.
권한 부여 서버 : OAuth 프로토콜을 구동하는 기본 서버입니다. 두 개의 엔드포인트를 운영하여 리소스 서버에 대한 액세스 권한을 부여합니다.
권한 부여 엔드포인트는 리소스 소유자에게 보호된 특정 리소스에 대한 동의를 제공하라는 메시지를 표시합니다. 그런 다음 토큰 엔드포인트는 OAuth 클라이언트로부터 토큰 요청을 수신하고 리소스에 대한 액세스 권한을 부여하는 새 액세스 토큰을 생성합니다.
범위 : 리소스 서버의 보호된 리소스에 대한 액세스 매개변수
예를 들어 리소스 소유자에게 이메일, 파일 또는 사진과 같은 데이터 액세스에 대한 동의를 요청할 수 있습니다. 범위는 클라이언트의 접근을 해당 항목으로만 제한합니다.

애플리케이션에 액세스 토큰을 제공하는 절차를 권한 부여(권한 부여 흐름)라고 합니다.
code_verifier를 생성하고 이를 기반으로 code_challenge를 생성code_challenge를 저장한 뒤 인가 코드를 발급code_verifier를 함께 전달| 구분 | SSO | OAuth |
|---|---|---|
| 역할 | 인증 (사용자가 누구인지 확인) | 인가 (무엇에 접근 가능한지 부여) |
| 방식 | ID 공급자(IdP) + SAML 등 사용, 사용자 이름/비밀번호로 신원 확인 | 사용자를 인증하지 않고 리소스 접근 권한만 부여 |
| 관계 | SSO가 OAuth를 활용해 인증된 사용자를 여러 앱/서비스에 쉽게 연결하기도 함 | — |
readygsm-server는 구글과 카카오 로그인을 지원합니다.
전체적인 흐름은 다음과 같습니다.
사용자
↓
구글 / 카카오 로그인
↓
인가 코드(code) 발급
↓
Ready GSM 백엔드
↓
Access Token 요청
↓
사용자 정보 조회
↓
회원 조회 또는 생성
↓
Spring Security 인증
↓
Session 생성
프론트엔드가 사용자를 구글/카카오 로그인 화면으로 보내고 동의를 받습니다
구글/카카오가 프론트엔드에 인가 코드(code)를 반환합니다.
프론트엔드는 이 코드를 백엔드의 POST /api/v1/auth/{provider}로 전달합니다.
백엔드가 이 코드를 가지고 구글/카카오의 토큰 엔드포인트에 직접 요청해 액세스 토큰으로 교환합니다.
액세스 토큰으로 사용자 정보(이메일)를 조회하고, DB에서 회원을 찾거나 새로 가입시킵니다.
로그인 처리 후 HTTP Session에 인증 정보를 저장하여 로그인 상태를 유지합니다.
@PostMapping("/{provider}")
public ResponseEntity<Void> oauthLogin(
@PathVariable String provider,
@RequestBody OAuthCodeRequest request,
HttpServletRequest httpRequest
) {
oAuthAuthenticationService.execute(
provider,
request.code(),
request.redirectUri(),
httpRequest
);
return ResponseEntity.ok().build();
}
백엔드는 provider에 따라 Google 또는 Kakao Provider를 선택하고, 인가 코드를 이용해 Access Token과 사용자 정보를 가져옵니다.
OAuthProvider provider =
oAuthProviderFactory.getProvider(providerName);
UserAuthInfo userAuthInfo =
provider.getUserAuthInfo(code, redirectUri);
getUserAuthInfo() 내부에서 인가 코드로 Access Token을 발급받고, 발급받은 Access Token으로 사용자 정보(이메일)를 가져옵니다.
여기서 getUserAuthInfo()에는 인가 코드와 redirectUri도 함께 전달합니다.
Ready GSM에서는 로컬, 개발, 상용 환경 등 여러 환경에서 로그인을 진행할 수 있기 때문에 환경별 redirect_uri를 미리 허용 목록으로 관리합니다. 프론트엔드가 전달한 redirect_uri가 허용 목록에 포함되어 있는지 검증한 후, 해당 URI를 사용해 토큰 교환을 진행합니다.

GoogleTokenResponse tokenResponse =
googleTokenClient.getToken(
code,
googleOAuthProperties.clientId(),
googleOAuthProperties.clientSecret(),
redirectUri
);
GoogleUserInfoResponse userInfoResponse =
googleUserInfoClient.getUserInfo(
tokenResponse.accessToken()
);
가져온 이메일과 Provider 정보를 이용해 Ready GSM의 회원을 조회합니다. 회원이 없다면 새로 생성합니다.
OAuth 사용자 정보
↓
회원 조회
↓
있음 → 로그인
없음 → 회원 생성
회원 정보를 바탕으로 Spring Security의 인증 객체를 만들고, SecurityContext를 HTTP Session에 저장하여 로그인 상태를 유지합니다.
인가 코드
↓
Access Token
↓
사용자 정보 조회
↓
회원 조회 / 생성
↓
Spring Security 인증
↓
HTTP Session 저장
↓
로그인 완료
즉 Ready GSM에서는 Google과 Kakao에서 Access Token을 발급받고, 이를 이용해 사용자 정보를 조회합니다. 이후 전달받은 사용자 정보로 Ready GSM의 자체 회원을 조회하거나 생성하고, Spring Security의 SecurityContext를 HTTP Session에 저장하여 로그인 상태를 관리합니다.