OAuth(Open Authorization) 는 사용자가 자신의 자격증명(비밀번호 등)을 주지 않고 제 3자 어플리케이션이 서버 리소스에 접근할 수 있게 하는 표준 프로토콜 입니다.
OAuth 는 다음의 요소로 이루어져 있습니다.
| 구성요소 | 설명 | 예 |
|---|---|---|
| Resource Owner | 리소스(개인정보 등) 의 주인 | 쇼핑몰 사용자 |
| Client | 리소스 접근을 요청하는 앱 | 쇼핑몰 |
| Authorization Server | 인증토큰 및 발급 서거 | 구글, 카카오 |
| Resource Server | 서버 리소스 | 구글, 카카오에 등록된 사용자 정보 |
OAuth 2.0은 OAuth 1.0의 단점을 보완한 방식으로 오늘날 OAuth 프로토콜의 표준입니다.
OAuth 1.0은 매 요청마다 암호화 연산을 수행해야 하므로 구현이 복잡하지만 매우 안정적이며, 하나의 인증 절차만 지원했습니다.
반면 OAuth 2.0은 다양한 인증 방식을 지원하고, HTTPS에 의존하여 보안을 보장하므로 별도의 서명이 필요하지 않습니다.
이로 인해 개발이 단순하고 확장성이 뛰어난 방식으로 널리 사용되고 있습니다.
OAuth 2.0은 Authorization Code, Implicit, Client Credentials, Resource Owner Password Credentials, Refresh Token 등의 인증 절차를 지원하며, 이 중 가장 안정적인 방식으로 Authorization Code 방식이 주로 사용됩니다. Authorization Code 방식은 Resource Owner가 인증 화면에서 리소스 사용을 직접 허가하고, Authorization Server와 Client 간의 리다이렉션을 거친 후 Resource Server가 Client에게 리소스를 제공하는 구조로 동작합니다.
모바일 앱에서 OAuth2 인증을 사용하는 경우에는 웹과 달리 별도의 리다이렉션 URL을 사용하지 않고, 앱 내부에서 인증 흐름을 처리하는 특수한 구조로 구현됩니다. 모바일 환경에서는 Google SDK 또는 Firebase SDK가 인증 절차를 직접 처리하여 토큰만 반환하며, 주요 OAuth 설정은 OS와 관계없이 Firebase 콘솔에서 일괄적으로 관리됩니다. 다만, Android는 SHA 키를, iOS는 번들 ID와 URL Scheme을 등록하는 등 각 OS 별로 필요한 식별 정보만 추가로 설정해주면 됩니다.
클라이언트는 OAuth 2.0을 통해 발급받은 Access Token을 사용하여 리소스 서버에서 사용자 정보를 조회합니다.
조회된 사용자 정보를 기반으로 자사몰에서 활용할 사용자 데이터를 생성하고 이를 자사 서버에 등록합니다.
다음은 웹 어플리케이션 Google OAuth 2.0 연동 가이드 입니다.
가장 먼저 해야 할 일은 구글 클라우드 콘솔 에서 클라이언트를 등록하는 것입니다.
해당 콘솔에 사용자 등록을 한 후 API 및 서비스 > OAuth 동의 화면에 들어갑니다.
클라이언트를 클릭한 후 클라이언트 만들기 화면에 들어갑니다.
어플리케이션 유형에 웹 어플리케이션을 선택합니다.
이름은 식별을 위한 이름을 기록하면 되고
승인된 리다이렉션 URI 는 자사 클라이언트 서버와 인증 리다이렉션을 하기 위한 엔드포인트 입니다.
인증처리를 할 때 구글 인증서버가 리다이렉션 URI 로 인증코드를 전송하고 자사클라이언트는 정해진 규칙에 맞는 응답을 전송해주어야 인증토큰이 발급됩니다.
모두 작성하였으면 만들기를 클릭합니다.
만들기를 클릭하면 다음과 같이 클라이언트 ID 와 클라이언트 보안 비밀번호가 발급됩니다.
사용자 승인이 완료되면 구글은 미리 작성된 리다이렉션 URI 로 코드를 전송합니다.
앞서 리다이렉션 URI 를 http://localhost:8080/auth/google 로 작성하였으니 이와 동일한 엔드포인트를 직접 장성해주어야 합니다.
해당 엔드포인트는 내부적으로 https://oauth2.googleapis.com/token 호출하여 실제 사용 가능한 인증토큰을 발급하도록 작성되어야 합니다.
@RestController
@RequiredArgsConstructor
class HandleGoogleOauth2Controller {
@GetMapping("/auth/google")
public ResponseEntity<?> handleGoogleCallback(
@RequestParam("code") String code) {
RestClient client = RestClient.create();
MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
formData.add("code", code);
formData.add("client_id", "발급받은 클라이언트 아이디");
formData.add("client_secret", "발급받은 클라이언트 보안 비밀번호");
formData.add("redirect_uri", "http://localhost:8080/auth/google");
formData.add("grant_type", "authorization_code");
GoogleTokenResponse tokenResponse = client.post()
.uri("https://oauth2.googleapis.com/token")
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE)
.body(formData)
.retrieve()
.body(GoogleTokenResponse.class);
return ResponseEntity.ok(GoogleTokenResponse);
}
@Data
static class GoogleTokenResponse {
private String access_token;
private String id_token;
private String scope;
private String token_type;
private Long expires_in;
}
}
리다이렉션 URI 를 작성한 API 서버를 로컬에 실행한 후 구글 인증코드 발급을 위한 엔드포인트를 호출하여 실제 인증토큰을 발급받아 보겠습니다.
구글 코드 발급을 위한 엔드포인트는 다음과 같습니다.
https://accounts.google.com/o/oauth2/v2/auth
?client_id=발급받은클라이언트ID
&redirect_uri=http://localhost:8080/auth/google
&response_type=code
&scope=email%20profile%20openid
&prompt=consent
| 파라미터 | 설명 |
|---|---|
| client_id | Google Cloud Console에서 발급받은 OAuth 클라이언트 ID |
| redirect_uri | 구글 인증 후 사용자를 리디렉션할 콜백 URL (서버의 /auth/google) |
| response_type | code 고정값 — Authorization Code Flow를 사용 |
| scope | 요청할 사용자 정보 권한 : email, profile, openid (공백은 %20으로 인코딩됨) |
| prompt | consent으로 설정하면 매번 동의 화면을 강제로 표시 (테스트 시 유용) |
사용자 인증 및 리다이렉트 URI 에 문제가 없다면 다음의 응답을 받아볼 수 있습니다.
{
"access_token": "인증토큰",
"id_token": "아이디토큰",
"scope": "https://www.googleapis.com/auth/userinfo.email openid https://www.googleapis.com/auth/userinfo.profile"
"token_type": "Bearer",
"expires_in": 3599
}
| 파라미터 | 설명 |
|---|---|
| access_token | 인증토큰 |
| id_token | 아이디 토큰 |
| scope | 스코프 |
| token_type | 토큰 타입 (Bearer) |
| expires_in | 토큰 만료 시간 |
제공되는 정보중 access_token 으로 구글 사용자 조회 API 를 호출하면 구글 사용자에 대한 정보를 조회할 수 있습니다. 조회된 정보를 이용하여 내부 DB 에 사용자를 등록하거나 로그인 처리하면 하면 됩니다.
@RestController
class GetGoogleUserDataController {
@PostMapping("/auth")
public ResponseEntity<?> getUserInfo(
@RequestHeader String googleAccessToken) {
RestClient client = RestClient.create();
GoogleUserInfo userInfo = client.get()
.uri("https://www.googleapis.com/oauth2/v2/userinfo")
.header(HttpHeaders.AUTHORIZATION, googleAccessToken)
.retrieve()
.body(GoogleUserInfo.class);
/*
todo:
실제 사용하는 경우 응답되는 정보를 기반으로
내부 DB 에 사용자 등록/로그인 처리를 합니다.
*/
return ResponseEntity.ok(userInfo);
}
@Data
static class GoogleUserInfo {
private String id;
private String email;
private Boolean verified_email;
private String name;
private String given_name;
private String family_name;
private String picture;
private String locale;
}
}
참고로 구글에서는 id_token 을 제공하여 토큰 자체에 사용자 정보를 주는 방식을 제공합니다.
이는 구글 JWT 암호키를 이용해 복호화하여 사용 가능합니다.
그러나 이 방법은 전통적인 OAuth2 인증 방식이 아니므로 이번 글에서는 생략 하였습니다.