Authlib 공식 문서 - [Web OAuth Clients]

Soobin Kim·2024년 2월 27일

공부

목록 보기
11/15

Authlib

  • Authlib는 OAuth 및 OpenID Connect 클라이언트와 서버를 구축하는 데 사용되는 Python 라이브러리이다.
  • OAuth 1.0, OAuth 2.0, JWT 등을 포함하여 RFC의 일반적인 구현을 제공한다.

OpenID Connect

정의

  • OIDC는 인증 및 인가를 위한 표준 프로토콜로, 클라이언트 애플리케이션과 인증 서버 간의 안전하고 효율적인 통신을 지원한다.
  • OAuth 2.0 프로토콜 위에 구축되어 있다.
  • 웹 및 모바일 애플리케이션에서 사용자를 인증하는 데 사용하여 사용자의 인증 및 인가 데이터를 안전하게 전송한다.

동작

  • 클라이언트 애플리케이션(예: 웹 애플리케이션, 모바일 앱 등)과 인증 서버(예: Google, Facebook, Okta 등) 간의 상호 작용을 정의한다.
  • 사용자는 클라이언트 애플리케이션을 통해 인증 서버에 로그인하고, 클라이언트 애플리케이션은 인증 서버로부터 인증된 사용자에 대한 정보를 안전하게 수신한다.

목차

Web OAuth Clients

  1. OAuth 2.0을 사용한 로그인
  2. OAuth 리소스 접근
  3. OAuth 2.0 개선
  4. OpenID Connect & 사용자 정보

먼저, OAuth 클래스를 생성한다.

# for Starlette framework
from authlib.integrations.starlette_client import OAuth

oauth = OAuth()

1. OAuth 2.0을 사용한 로그인

  • 예시: GitHub OAuth 2.0 서비스

첫째: 원격 애플리케이션을 oauth.register 메소드를 통해 OAuth 레지스트리에 등록한다.

oauth.register(
    name='github',  # 원격 애플리케이션의 이름
    client_id='{{ your-github-client-id }}',
    client_secret='{{ your-github-client-secret }}',
    access_token_url='https://github.com/login/oauth/access_token',
    access_token_params=None,
    authorize_url='https://github.com/login/oauth/authorize',
    authorize_params=None,
    api_base_url='https://api.github.com/',
    client_kwargs= {
        'scope': 'profile',
    },
)

원격 애플리케이션에 접근하는 방법:

github = oauth.create_client('github')
# or 
github = oauth.github

인증을 위한 경로

  • OAuth 레지스트리 설정 후, 다음 두 개의 경로를 생성한다.
    ① 인증을 위해 서드파티 공급자(GitHub)로 리디렉션할 경로
    ② access token과 프로필을 가져오기 위해 재리디렉션할 경로

  • 예시

def login(request):
    github = oauth.create_client('github')
    redirect_uri = 'https://example.com/authorize'
    return github.authorize_redirect(request, redirect_uri)

def authorize(request):
    token = oauth.github.authorize_access_token(request)
    resp = oauth.github.get('user', token=token)
    resp.raise_for_status()
    profile = resp.json()
    # do something with the token and profile
    return '...'

클라이언트 인증 방법

  • access token을 가져올 때 권한 부여 서버는 클라이언트 인증을 요구하며, Authlib는 RFC7591에 정의된 세 가지 기본 방법을 제공한다.

    • client_secret_basic
    • client_secret_post
    • none
  • 그러나 원격 공급자가 위 방법을 모두 지원하지 않는 경우, 자체 인증 방법을 등록해야 한다.

from authlib.oauth2.rfc7523 import ClientSecretJWT

oauth.register(
    'name',
    ...
    client_auth_methods=[
        ClientSecretJWT(token_endpoint),  # client_secret_jwt
    ]
)

2. OAuth 리소스 접근

  • 사용자의 리소스에 액세스하고 싶을 경우, access token을 사용하여 리소스를 가져온다.
  • 예시: 로그인한 사용자의 트위터 타임라인 표시 또는 GitHub 레포지토리 표시
  • 이 경우, 나중에 사용하기 위해 데이터베이스에 액세스 토큰을 저장할 필요가 있다.
  • 따라서 access token을 검사하고 승인 받는 경로에서 access token을 데이터베이스에 저장하는 로직이 추가될 것이다.
def get_twitter_tweets(request):
    token = OAuth1Token.find(
        name='twitter',
        user=request.user
    )
    # API URL: https://api.twitter.com/1.1/statuses/user_timeline.json
    resp = oauth.twitter.get('statuses/user_timeline.json', token=token.to_token())
    resp.raise_for_status()
    return resp.json()

def get_github_repositories(request):
    token = OAuth2Token.find(
        name='github',
        user=request.user
    )
    # API URL: https://api.github.com/user/repos
    resp = oauth.github.get('user/repos', token=token.to_token())
    resp.raise_for_status()
    return resp.json()

데이터베이스 설계

class OAuth2Token(Model):
    name = String(length=40)
    token_type = String(length=40)
    access_token = String(length=200)
    refresh_token = String(length=200)
    expires_at = PositiveIntegerField()
    user = ForeignKey(User)

    def to_token(self):
        return dict(
            access_token=self.access_token,
            token_type=self.token_type,
            refresh_token=self.refresh_token,
            expires_at=self.expires_at,
        )

사용자 OAuth 토큰 가져오기

  • OAuth 토큰을 가져오는 방법과 관련된 내용

첫째: 개발자가 직접 토큰을 조회하는 방법

  • 사용자의 요청(request)을 기반으로 특정한 OAuth2 토큰을 검색하고, 이를 사용하여 특정 원격 애플리케이션에 대한 요청을 보낸다.
  • 다음과 같이 access token 매개변수를 원격 리소스 서버 요청 메소드에 전달할 수 있다.
token = OAuth2Token.find(name='github', user=request.user)
oauth.github.get(url, token=token)
oauth.github.post(url, token=token)
oauth.github.put(url, token=token)
oauth.github.delete(url, token=token)
  • 위 방식은 모든 요청에서 데이터베이스에 access token을 쿼리하는 것이므로, 효율적이지 않다.
  • 따라서 fetch_token 함수를 사용하여 access token을 등록하고 현재 사용자의 access token을 자동으로 가져오는 방법을 사용한다.
def fetch_twitter_token(request):
    token = OAuth1Token.find(
        name='twitter',
        user=request.user
    )
    return token.to_token()

def fetch_github_token(request):
    token = OAuth2Token.find(
        name='github',
        user=request.user
    )
    return token.to_token()

# we can registry this ``fetch_token`` with oauth.register
oauth.register(
    'twitter',
    # ...
    fetch_token=fetch_twitter_token,
)
oauth.register(
    'github',
    # ...
    fetch_token=fetch_github_token,
)
  • 하지만 위 방식 또한 모든 원격 애플리케이션마다 fetch_token 함수를 개발자가 작성해야 하므로 번거로운 것은 마찬가지다.
  • 더 효율적인 방식을 위해서 다음과 같이 모든 원격 애플리케이션에 대한 토큰을 가져오는 공통된 방법을 작성한다.
def fetch_token(name, request):
    model = OAuth2Token

    token = model.find(
        name=name,
        user=request.user
    )
    return token.to_token()

# 위 fetch_token 함수로 OAuth 레지스트리 초기화
oauth = OAuth(fetch_token=fetch_token)
  • OAuth 레지스트리 등록 후, 토큰을 가져오는 방법을 설정하여 개발자가 HTTP 요청에 토큰을 직접 전달할 필요 없이, 요청 객체(request)를 통해 토큰을 자동으로 가져오도록 한다.
def get_twitter_tweets(request):
    resp = oauth.twitter.get('statuses/user_timeline.json', request=request)
    resp.raise_for_status()
    return resp.json()

3. OAuth 2.0 개선

OAuth 1.0은 프로토콜인 반면, OAuth 2.0은 프레임워크이다.

자동 토큰 갱신

  • OAuth 2.0에서 토큰은 만료될 수 있는데, 만약 refresh_token 값이 존재한다면, Authlib은 **토큰이 만료된

    경우 자동으로 갱신하는 기능**을 지원한다.

OAuth 2.0 코드 챌린지

  • 코드 챌린지 방법으로 PKCE(Proof Key for Code Exchange)를 사용할 수 있다. 이를 통해 더욱 안전하게 인증을 처리할 수 있다.

OAuth 2.0 규정 준수 수정

  • OAuth 2.0 규정 준수에 따라 개발자들이 시스템을 개선할 수 있는 방법들이 있다.

4. OpenID Connect & 사용자 정보

  • OpenID Connect는 사용자 인증을 위한 레이어로, OAuth 2.0 위에서 동작한다.
  • 인증을 통해 사용자의 id_token을 받고 이를 기반으로 사용자 정보를 추출할 수 있다.

userinfo_endpoint

  • userinfo_endpoint를 호출하여 사용자의 정보(이메일, 이름 등)를 받아온다.

id_token 파싱

  • OpenID Connect 프로토콜에서 전달되는 id_token은 JWT 형식으로, 이 토큰을 파싱하여 사용자의 정보를 확인할 수 있다.

이와 같이 OAuth 및 OpenID Connect 인증 시스템을 설정하여 안전한 인증 흐름을 구현할 수 있다.

0개의 댓글