OIDC 를 이용한 구글 소셜 로그인 과정
Authorization Code를 활용하는 구글 소셜 로그인을 실행하기 까지 유저, 프론트엔드, 백엔드, OpenID Connect 프로바이더 사이에 어떤 과정을 거치는지 설명해 주세요.
원래의 로그인 과정이라면?
유저 : 회원가입 시 전송한 아이디(또는 이메일), 비밀번호 등 인증 정보를 입력하여 로그인 버튼을 누른다.
프론트엔드 (클라이언트) : 유저가 입력한 정보를 담아 로그인 api 요청을 보낸다.
백엔드 (서버) : 클라이언트가 보낸 정보가 서버 DB에 있는지 확인하고 토큰을 생성해 클라이언트에게 전송한다.
클라이언트 : 서버에서 받은 인증 토큰을 로컬스토리지나 쿠키에 저장.
이후 유저가 보호된 리소스에 접근할때 Authorization 헤더에 담아 백엔드에 보내 인증을 유지
구글 소셜 로그인
- 준비
구글의 OAuth API 를 사용하기 위해 Google Cloud에서 클라이언트 키를 발급
1. 서비스가 사용자로부터 제공받아야할 구글 계정 정보를 설정한다.
(scope : 이메일 주소, 개인정보, openId등..)
2. 클라이언트 ID (클라이언트 키) 생성
승인된 리디렉션 URI 설정
- 유저
유저가 정보를 입력하고 로그인 버튼을 누르면 클라이언트(브라우저)는 구글에 OAuth 서버에 인증 요청을 보낸다.
- 클라이언트
브라우저에서 구글 로그인 창을 호출하는 URL
https://accounts/google.com/o/oauth2/v2/auth
위 url에 필수 파라미터를 추가한다.
- client_id : 앞서 발급받은 ClientID
- redirect_url : 앞서 Google Cloud에서 설정해주었던 리다이렉트 url
- response_type : code로 고정(인가 코드를 통한 로그인 방식을 사용할 것이므로)
- scope: 토큰 발급 이후 유저 정보에서 어떤 항목을 조회할 것인지(email, profile 등)
클라이언트에서 리다이렉트해주어야 할 url은 다음과 같은 형태가 됩니다.
//Authorization Code Flow
import qs from "qs";
const CLIENT_ID = "<자신의 애플리케이션이 발급받은 클라이언트 아이디>";
const REDIRECT_URI = "http://localhost:8080/oauth2/callback/google"; // Google Cloud에 등록된 Redirect URI
const AUTHORIZE_URI = "https://accounts.google.com/o/oauth2/v2/auth";
// 구글 인증을 요청하는 URL을 만듦
const queryStr = qs.stringify({
client_id: CLIENT_ID,
redirect_uri: REDIRECT_URI,
response_type: "code", // Authorization Code를 요청
scope: "openid profile email", // 요청할 범위 (사용자 프로필, 이메일)
access_type: "offline", // 리프레시 토큰을 받기 위해 offline 설정
prompt: "consent", // 사용자에게 동의를 요구하는 창 표시
});
const loginUrl = `${AUTHORIZE_URI}?${queryStr}`;
window.location.href = loginUrl; // 사용자를 구글 로그인 페이지로 리디렉션
qs : JavaScript의 쿼리 문자열을 쉽게 생성하고 파싱하기 위한 라이브러리
Implicit Flow : 토큰을 클라이언트에 직접 전달
- 클라이언트에서 직접 Access Token 및 ID Token을 받아오는 방식입니다.
- 사용자가 로그인하면 구글이 클라이언트(프론트엔드)에 바로 Access Token과 ID Token을 전달합니다.
- 이 방식은 보안성이 떨어질 수 있습니다. 클라이언트가 직접 토큰을 처리하기 때문에 민감한 정보가 브라우저에 노출됩니다. 이를 악의적인 사용자가 탈취할 가능성이 존재합니다.
- Implicit Flow는 보통 서버가 없는 순수 클라이언트 애플리케이션이나 **SPA(Single Page Application)**에서 주로 사용되었으나, 현재는 권장되지 않는 방식입니다.
//Implicit Flow
import qs from "qs";
const CLIENT_ID = "<자신의 애플리케이션이 발급받은 클라이언트 아이디>";
const AUTHORIZE_URI = "https://accounts.google.com/o/oauth2/v2/auth";
const queryStr = qs.stringify({
client_id: CLIENT_ID,
redirect_uri: window.location.href,
response_type: "token id_token",
scope: "openid profile email",
nonce:
Math.random().toString(36).substring(2, 15) +
Math.random().toString(36).substring(2, 15),
});
로그인 창에서 계정을 선택하면 위에서 설정한 리디렉션 uri로 넘어감
http://localhost:8080/login/oauth2/code/google?code={인가코드}&scope=email+profile+...
쿼리 파라미터의 인가코드(Authorization Code)를 로그인 요청과 함께 서비스 서버에 전달한다.
- 백엔드
- 클라이언트가 전달한 인가 코드를 가지고 구글 OAuth API를 호출하여 Access Token + ID 토큰을 요청해야 한다.
- 이 토큰을 가지고 사용자의 구글 계정 정보를 요청하고
(회원가입이 되어있지 않을때) 서비스 DB에 회원 레코드를 추가 - 서버의 Access Token(JWT 또는 세션 토큰) 을 생성해서 클라이언트에 반환 : 인증 완료
두 가지 Access 토큰이 있어 헷갈리지 말자!
구글 소셜 로그인한 사용자의 구글 계정정보를 가져올수있도록 구글에서 발급한 Access토큰
우리 서비스를 이용하기 위해 필요한 사용자 인증 토큰 : 서버 Access 토큰
로그인 완료!
전체 플로우를 보면 아래와 같다
이미지 및 내용 출처 : https://velog.io/@bdd14club/백엔드-2.-구글-소셜-로그인-구현하기
OIDC
내용 출처 : https://www.daleseo.com/google-oidc/
OpenID Connect는 OAuth 2.0을 확장한 표준
현재 구글 뿐만 아니라 많은 글로벌 플랫폼들이 다른 서비스에게 사용자 인증을 제공을 위해 사용하고 있는 프토토콜
OpenID Connect는 기본적으로 OAuth 프로토콜을 기반으로 작동하는 프로토콜이기 때문에 기술적으로 사용하는 방법이 매우 유사하지만 사용하는 목적에서는 큰 차이가 있습니다.
OIDC는 인증(Authentication)을 위해서 사용하고, OAuth는 인가(Authroization)를 위해서 사용합니다. 다시말해, OIDC는 다른 플랫폼을 통해서 사용자가 누구인지를 확인하기 위해서 사용하는 반면에, OAuth는 해당 플랫폼에 저장된 사용자의 데이터에 접근하기 위해서 사용합니다.
따라서, OAuth의 목적은 다른 플랫폼의 다른 API를 호출하기 위해서 access token을 확보하는 것입니다. 하지만 OIDC의 경우, 사용자의 개인 정보가 담긴 id token을 확보라는 다른 목적을 가지고 있습니다.
ID Token의 내용:
- iss: 토큰 발급자 (구글)
- sub: 유저의 고유 ID
- aud: 클라이언트 ID
- exp: 토큰의 만료 시간