본문 바로가기
프로그램 (PHP,Python)

구글 OAuth 인증 토큰 저장 및 갱신 유지관리

by 날으는물고기 2024. 3. 22.

구글 OAuth 인증 토큰 저장 및 갱신 유지관리

Easy Google OAuth2 Authentication in Nodejs - DEV Community

구글 OAuth 연동을 사용하는 경우, 사용자가 자신의 구글 계정으로 인증을 할 때 생성되는 OAuth 키(토큰)를 저장하고 관리해야 합니다. 이 토큰은 사용자가 서비스에 대해 특정 권한을 부여했음을 나타내며, 이를 통해 사용자의 구글 계정 데이터에 접근할 수 있습니다.

 

보통 두 종류의 토큰을 관리해야 합니다.

  1. 액세스 토큰(Access Token): 짧은 유효기간을 가지며, 구글 API에 요청을 보낼 때 사용됩니다.
  2. 리프레시 토큰(Refresh Token): 액세스 토큰이 만료되었을 때 새 액세스 토큰을 받기 위해 사용됩니다. 리프레시 토큰은 긴 유효기간을 가지고 있거나 만료되지 않는 경우도 있습니다.

토큰을 안전하게 보관하는 것은 매우 중요합니다. 누군가가 이 토큰들을 탈취하면 사용자의 데이터에 접근할 수 있기 때문입니다. 따라서, 이런 토큰들을 데이터베이스에 저장할 때는 안전한 저장 방법을 사용해야 합니다. 예를 들어, 토큰을 암호화하여 저장하거나, 안전한 통신 채널을 통해서만 토큰을 전송해야 합니다.

 

토큰을 데이터베이스(DB)에 저장할 때 암호화하는 것은 좋은 보안 관행입니다. 액세스 토큰과 리프레시 토큰 같은 인증 정보는 사용자의 계정과 데이터에 접근할 수 있는 권한을 부여하기 때문에, 이런 정보가 노출될 경우 심각한 보안 위험이 발생할 수 있습니다. 따라서, 토큰을 암호화하여 저장하는 것은 다음과 같은 이유로 중요합니다.

  1. 데이터 유출 방지: 데이터베이스가 해킹당하거나 무단 접근을 받는 경우, 암호화된 토큰은 해커가 직접적으로 사용할 수 없으므로 정보의 유출을 방지할 수 있습니다.
  2. 규정 준수: 많은 국가와 업계에서는 개인 데이터를 보호하기 위한 규정을 시행하고 있습니다(예: GDPR, HIPAA). 이러한 규정은 개인 데이터를 암호화하는 것을 요구하거나 권장하기도 합니다.
  3. 사용자 신뢰 유지: 사용자 데이터를 안전하게 보호하는 것은 사용자 신뢰를 유지하는 데 중요합니다. 사용자 데이터를 적절히 보호하는 것은 서비스의 신뢰성을 높이는 요소 중 하나입니다.

토큰을 암호화할 때는 다음과 같은 점을 고려해야 합니다.

  • 암호화 알고리즘: 강력하고 검증된 암호화 알고리즘을 사용해야 합니다. 예를 들어, AES(Advanced Encryption Standard)는 널리 사용되고 안전한 알고리즘입니다.
  • 키 관리: 암호화 키는 안전하게 관리되어야 합니다. 키가 노출되면 암호화는 의미가 없어집니다.
  • 성능 고려: 암호화와 복호화 과정은 시스템의 성능에 영향을 줄 수 있습니다. 적절한 암호화 수준을 선택하면서도 시스템 성능을 유지하는 것이 중요합니다.

보안이 중요한 어떤 시스템에서든 사용자 인증 정보를 포함한 민감한 데이터를 암호화하여 저장하는 것은 매우 권장되는 방법입니다.

 

구글 OAuth 동의 화면을 통해 사용자가 권한을 수락하면, 구글은 해당 계정에 대한 토큰을 발행하여 제공합니다. 이 과정은 다음과 같이 진행됩니다.

  1. 사용자 인증 요청: 사용자가 OAuth를 통해 로그인을 시도하면, 먼저 구글의 로그인 및 동의 화면으로 리다이렉트됩니다. 이 화면에서는 사용자에게 어떤 정보에 대한 접근을 허용할 것인지 물어봅니다.
  2. 동의: 사용자가 필요한 권한에 대해 동의하면, 구글은 이를 인증하고 사용자의 동의를 기반으로 토큰을 생성합니다.
  3. 토큰 발행: 구글은 애플리케이션에 액세스 토큰(access token)과 리프레시 토큰(refresh token)을 발급합니다. 액세스 토큰은 짧은 유효 기간을 가지고 있으며, 구글 API에 요청을 보낼 때 사용됩니다. 리프레시 토큰은 액세스 토큰이 만료되었을 때 사용하여 새 액세스 토큰을 요청할 수 있으며, 훨씬 더 긴 유효 기간을 가집니다.
  4. API 접근: 발급된 액세스 토큰을 사용하여 구글 API에 접근하고, 사용자가 동의한 범위 내에서 데이터를 요청하거나 작업을 수행할 수 있습니다.

이 토큰은 사용자의 구글 계정과 관련된 작업을 수행할 수 있는 권한을 앱에 부여합니다. 따라서, 이 토큰을 안전하게 관리하고 보호하는 것이 중요합니다.

 

리프레시 토큰이 만료되거나 무효화되면, 사용자로부터 다시 동의를 받아야 새로운 액세스 토큰과 리프레시 토큰을 발급받을 수 있습니다. 리프레시 토큰은 일반적으로 액세스 토큰보다 훨씬 긴 유효 기간을 가지지만, 몇 가지 상황에서 만료되거나 무효화될 수 있습니다.

  • 리프레시 토큰에는 만료 기간이 설정되어 있으며, 그 기간이 지나면 새로운 토큰을 발급받기 위해 사용자 인증이 다시 필요할 수 있습니다.
  • 사용자가 구글 계정의 보안 설정을 변경하거나 애플리케이션에 대한 접근 권한을 취소하는 경우 리프레시 토큰이 무효화될 수 있습니다.
  • 구글이 보안상의 이유로 리프레시 토큰을 무효화시킬 수 있습니다.

리프레시 토큰이 만료되거나 무효화되면, 애플리케이션은 더 이상 사용자 대신 구글 API에 요청을 자동으로 보낼 수 없게 됩니다. 이 경우, 애플리케이션이 사용자에게 다시 로그인하도록 요청하거나 필요한 권한에 대해 다시 동의를 받아야 합니다. 그 후, 새로운 액세스 토큰과 리프레시 토큰이 발급되어 API와의 소통이 다시 가능해집니다.

 

따라서, 애플리케이션은 리프레시 토큰의 유효성을 주기적으로 확인하고, 만료나 무효화가 감지될 경우 적절한 사용자 인터페이스를 통해 사용자에게 필요한 조치를 안내해야 합니다.

 

구글 OAuth 토큰을 주기적으로 체크하고 자동으로 갱신하는 방법은 주로 액세스 토큰의 유효 기간을 모니터링하고, 만료 전에 리프레시 토큰을 사용하여 액세스 토큰을 갱신하는 과정을 자동화하는 것을 포함할 수 있습니다.

1. 액세스 토큰의 만료 시간 확인

  • 구글에서 액세스 토큰을 발급할 때, expires_in 필드를 통해 토큰의 유효 기간(초 단위)을 알려줍니다. 애플리케이션은 이 정보를 사용하여 액세스 토큰의 만료 시간을 계산하고 저장해야 합니다.

2. 만료 전 자동 갱신 로직 구현

  • 애플리케이션은 액세스 토큰이 만료되기 전에, 예를 들어 몇 분 전에 자동으로 갱신 작업을 수행하도록 스케줄링해야 합니다. 이를 위해 백엔드 서버에서 타이머나 스케줄링 작업을 설정할 수 있습니다.

3. 리프레시 토큰으로 액세스 토큰 갱신

  • 만료 시간이 다가오면, 애플리케이션은 저장된 리프레시 토큰을 사용하여 구글의 토큰 갱신 엔드포인트에 요청을 보내 새 액세스 토큰을 받아야 합니다. 요청은 다음과 같은 형태가 될 수 있습니다.
    POST /oauth2/v4/token HTTP/1.1
    Host: www.googleapis.com
    Content-Type: application/x-www-form-urlencoded
    
    client_id=YOUR_CLIENT_ID&
    client_secret=YOUR_CLIENT_SECRET&
    refresh_token=YOUR_REFRESH_TOKEN&
    grant_type=refresh_token
  • 이 요청에 대한 응답으로, 구글은 새 액세스 토큰과 해당 토큰의 expires_in 값을 반환합니다. 애플리케이션은 이 새 토큰과 만료 시간을 저장하고, 이전 토큰을 대체해야 합니다.

4. 예외 처리

  • 리프레시 토큰이 만료되었거나 무효화된 경우, 자동 갱신 시도는 실패할 것입니다. 이 경우, 애플리케이션은 사용자에게 다시 로그인하도록 요청해야 합니다. 애플리케이션은 이런 상황을 감지하고 적절히 대응할 수 있도록 예외 처리 로직을 구현해야 합니다.

구현 팁

  • 갱신 로직을 구현할 때는 액세스 토큰의 만료 시간을 정확히 계산하고, 네트워크 지연이나 서버의 시간 차이를 고려하여 여유를 두고 갱신 요청을 보내는 것이 좋습니다.
  • 보안을 위해, 리프레시 토큰과 클라이언트 비밀(client_secret)은 서버 측에서 안전하게 관리되어야 합니다. 클라이언트 사이드에서 이러한 값을 다루지 않도록 주의해야 합니다.

자동 갱신 메커니즘을 통해 애플리케이션의 사용자 경험을 개선하고, 서비스의 연속성을 보장하는 동시에 보안을 유지해야 합니다.

 

보유하고 있는 토큰들에 대해 유효 기간이 7일 이내로 남아 있는지 체크하고 필요한 경우 갱신하는 프로세스를 구현하기 위해 몇 가지 주요 단계를 따라야 합니다. 아래의 절차는 일반적으로 백엔드 시스템에서 실행되며, 구글 OAuth 토큰과 같은 인증 토큰을 관리하는 데 사용됩니다.

1. 토큰 만료 시간 저장

  • 토큰을 처음 받을 때, expires_in 필드(토큰의 유효 기간, 초 단위)와 함께 현재 시간을 기록해 토큰의 만료 시간을 계산하고 데이터베이스에 저장합니다. 만료 시간은 보통 현재 시간에 expires_in 값을 더해 계산됩니다.

2. 만료 기간 체크 로직 구현

  • 데이터베이스에 저장된 토큰의 만료 시간을 주기적으로 체크하는 로직을 구현합니다. 이 로직은 백그라운드 작업(예: 크론 작업)으로 설정할 수 있습니다.

3. 갱신 조건 확인

  • 현재 날짜와 시간을 기준으로 만료 시간이 7일 이내인 토큰을 찾습니다. 이를 위해 현재 시간에서 7일 후의 시간을 계산하고, 이 시간과 토큰의 만료 시간을 비교합니다.

4. 토큰 갱신

  • 만료 기간이 7일 이내로 남은 토큰에 대해, 리프레시 토큰을 사용하여 구글 OAuth 토큰 갱신 API를 호출하고 새 토큰 정보를 받습니다.

5. 새 토큰 저장

  • 새로 발급받은 토큰과 그 만료 시간을 데이터베이스에 업데이트합니다.

 

아래는 Python을 사용한 간단한 예제 코드입니다. 실제 환경에서는 데이터베이스 조회 및 업데이트 로직을 구현해야 합니다.

import datetime
import requests

# 가정: 데이터베이스에서 토큰 정보를 불러오는 함수
def get_tokens():
    # 데이터베이스 로직을 구현하여 토큰 정보를 불러옵니다.
    # 여기서는 예시로 몇 가지 토큰 정보를 반환합니다.
    return [
        {"token": "token1", "refresh_token": "refresh_token1", "expires_at": datetime.datetime(2024, 2, 25)},
        {"token": "token2", "refresh_token": "refresh_token2", "expires_at": datetime.datetime(2024, 3, 1)},
    ]

# 토큰 갱신 함수
def refresh_token(refresh_token):
    payload = {
        'client_id': 'YOUR_CLIENT_ID',
        'client_secret': 'YOUR_CLIENT_SECRET',
        'refresh_token': refresh_token,
        'grant_type': 'refresh_token',
    }
    response = requests.post('https://www.googleapis.com/oauth2/v4/token', data=payload)
    if response.status_code == 200:
        return response.json()  # 새 토큰 정보 반환
    else:
        return None

# 토큰 체크 및 갱신 로직
def check_and_refresh_tokens():
    tokens = get_tokens()
    for token_info in tokens:
        # 현재 시간에서 7일 후의 날짜 계산
        seven_days_later = datetime.datetime.now() + datetime.timedelta(days=7)
        # 토큰 만료 시간이 7일 이내인지 확인
        if token_info["expires_at"] <= seven_days_later:
            # 토큰 갱신
            new_token_info = refresh_token(token_info["refresh_token"])
            if new_token_info:
                # 새 토큰 정보로 데이터베이스 업데이트
                # 데이터베이스 업데이트 로직 구현 필요
                print(f"토큰이 갱신되었습니다: {new_token_info['access_token']}")
            else:
                print("토큰 갱신 실패")

check_and_refresh_tokens()

이 코드는 크게 3부분으로 구성되어 있습니다. 데이터베이스에서 토큰 정보를 불러오는 부분, 토큰을 갱신하는 부분, 그리고 토큰 만료 기간을 체크하고 필요한 경우 갱신하는 로직입니다. 실제 구현에서는 데이터베이스와의 연동이 필요하며, 예외 처리 및 로깅 등의 추가적인 고려가 필요할 수 있습니다.

 

사용자가 시스템에 접근할 때마다 토큰 갱신 프로세스를 실행하는 방식은 실제 사용자 경험과 시스템의 효율성 측면에서 종종 선호됩니다. 이 접근 방식은 사용자가 활성 상태일 때만 토큰을 갱신하여 불필요한 토큰 갱신 요청을 줄이고, 시스템 자원을 보다 효율적으로 사용할 수 있게 합니다.

 

아래는 사용자가 시스템에 접근할 때마다 토큰 갱신 로직을 실행하는 예제 코드입니다. 이 예제는 사용자가 시스템에 요청을 할 때마다 사용자의 토큰 만료 시간을 체크하고, 만료가 임박했거나 만료된 경우 새로운 토큰으로 갱신하는 프로세스를 구현합니다.

import datetime
import requests

# 사용자의 토큰 정보를 반환하는 함수 (예시)
def get_user_token_info(user_id):
    # 데이터베이스에서 사용자 ID에 해당하는 토큰 정보를 조회합니다.
    # 여기서는 예시로 하드코딩된 값을 반환합니다.
    return {
        "access_token": "access_token_value",
        "refresh_token": "refresh_token_value",
        "expires_at": datetime.datetime.now() + datetime.timedelta(days=1),  # 예시 만료 시간
    }

# 토큰 갱신 함수
def refresh_token(refresh_token):
    payload = {
        'client_id': 'YOUR_CLIENT_ID',
        'client_secret': 'YOUR_CLIENT_SECRET',
        'refresh_token': refresh_token,
        'grant_type': 'refresh_token',
    }
    response = requests.post('https://www.googleapis.com/oauth2/v4/token', data=payload)
    if response.status_code == 200:
        new_token_info = response.json()
        # 새 토큰 정보와 만료 시간 업데이트 로직 구현 필요
        # 예: 데이터베이스에 새 토큰 정보 저장
        return new_token_info
    else:
        return None

# 사용자 요청 처리 함수
def handle_user_request(user_id):
    token_info = get_user_token_info(user_id)
    now = datetime.datetime.now()

    # 토큰 만료 시간이 현재 시간보다 이전인지 확인
    if token_info["expires_at"] <= now:
        # 토큰 갱신
        new_token_info = refresh_token(token_info["refresh_token"])
        if new_token_info:
            print("토큰이 성공적으로 갱신되었습니다.")
            # 새 토큰 정보로 업데이트 로직 구현 필요
        else:
            print("토큰 갱신 실패. 사용자 재인증이 필요합니다.")
            # 재인증 요청 로직 구현 필요
    else:
        print("토큰이 유효합니다.")

# 예제 사용자 요청 시뮬레이션
user_id = "example_user_id"
handle_user_request(user_id)

이 코드는 다음 과정을 따릅니다.

  1. 토큰 정보 조회: 사용자의 토큰 정보를 데이터베이스나 저장소에서 가져옵니다.
  2. 토큰 만료 체크: 현재 시간과 토큰의 만료 시간을 비교하여 토큰이 만료되었는지 확인합니다.
  3. 토큰 갱신: 만료된 경우, 리프레시 토큰을 사용하여 새 액세스 토큰을 요청하고 받아옵니다.
  4. 토큰 정보 업데이트: 새로운 토큰 정보를 저장소에 저장합니다.

데이터베이스 조회 및 업데이트, 예외 처리, 로깅 등을 적절히 추가하여 안정성과 유지보수성을 높여야 합니다.

728x90

댓글