OAuthTokenResolver

OAuthTokenResolver

파이프라인 실행 시점에 OAuth 액세스 토큰을 해석하고, 다운스트림 컴포넌트(SharePoint·Google Drive의 retriever/fetcher 등)로 내보내 주는 컴포넌트예요.

출처: 문서

본문

OAuthTokenResolver는 파이프라인이 실행될 때 OAuth 액세스 토큰을 해석하고 access_token 출력 소켓으로 내보내요. MSSharePointRetriever, MSSharePointFetcher, GoogleDriveRetriever, GoogleDriveFetcher 같은 다운스트림 컴포넌트는 일반 연결로 이 토큰을 받아서, 어떻게 얻었는지는 알 필요가 없어요.

Resolver 자체는 얇은 래퍼예요. 실제 토큰을 얻는 작업은 토큰이 어디서 오는지를 정하는 **플러그형 토큰 소스(token source)**에 위임되죠. 이 분리 덕분에 파이프라인 나머지를 건드리지 않고 인증 전략(refresh-token 그랜트, 요청별 토큰 교환, 정적 장기 토큰)을 바꿔끼울 수 있어요.

토큰 소스

Resolver에 token_source 파라미터로 토큰 소스를 넘겨요. 모든 소스는 haystack_integrations.utils.oauth에서 임포트할 수 있어요.

소스 언제 쓰나 요청별 입력
OAuthRefreshTokenSource 저장된 refresh token을 기반으로 한 단일 고정 ID가 있고, 그 소스가 짧은 수명의 액세스 토큰으로 교환해서 캐시하게 하려 할 때 없음
OAuthTokenExchangeSource 여러 사용자(또는 여러 레플리카)를 서비스하면서, 영구 저장 없이 들어오는 요청별 사용자 어설션을 다운스트림 토큰으로 교환하려 할 때. RFC 8693 토큰 교환과 Microsoft의 on-behalf-of 흐름을 구현해요. subject_token
OAuthStaticTokenSource 프로바이더가 만료되지 않는 토큰을 발급하고, 이를 대역 외(out of band)로 관리할 때(예: Slack, Notion) 없음

구성한 소스가 요청별 자격 증명을 필요로 하면(OAuthTokenExchangeSource는 requires_subject_token = True로 설정), Resolver는 필수 subject_token 실행 입력을 선언해요. 이는 컨트롤러가 주입한 자격 증명(예: 들어오는 사용자 어설션)으로, 최종 사용자가 고르는 값이 아니에요. 구성 전용 소스(OAuthRefreshTokenSource, OAuthStaticTokenSource)에서는 Resolver가 실행 입력을 선언하지 않고 소스 노드로 동작해요.

Scopes는 프로바이더별로 달라요: 요청하는 OAuth scope는 다운스트림 서비스에 따라 달라져요. Microsoft Graph는 https://graph.microsoft.com/Files.Read.All 같은 scope가, Google Drive는 https://www.googleapis.com/auth/drive.readonly 같은 scope가 필요해요. 정확한 scope 값은 항상 아이덴티티 프로바이더 문서를 확인하세요.

설치

OAuth 통합을 설치해요.

pip install oauth-haystack

더 알아보기 (Learn more)

단독으로 쓰기

저장된 refresh token으로 토큰을 해석하려면 OAuthRefreshTokenSource를 써요. refresh token은 Secret API를 통해 환경 변수에서 읽어요.

from haystack.utils import Secret
from haystack_integrations.components.connectors.oauth import OAuthTokenResolver
from haystack_integrations.utils.oauth import OAuthRefreshTokenSource


resolver = OAuthTokenResolver(
    token_source=OAuthRefreshTokenSource(
        token_url="https://login.microsoftonline.com/common/oauth2/v2.0/token",
        client_id="aaa-bbb-ccc",
        refresh_token=Secret.from_env_var("MS_REFRESH_TOKEN"),
        scopes=[
            "https://graph.microsoft.com/Files.Read.All",
            "offline_access",
        ],
    ),
)

access_token = resolver.run()["access_token"]

장기·만료 없는 토큰을 발급하는 프로바이더라면 OAuthStaticTokenSource를 써요.

from haystack.utils import Secret
from haystack_integrations.components.connectors.oauth import OAuthTokenResolver
from haystack_integrations.utils.oauth import OAuthStaticTokenSource


resolver = OAuthTokenResolver(
    token_source=OAuthStaticTokenSource(token=Secret.from_env_var("SERVICE_TOKEN")),
)

access_token = resolver.run()["access_token"]

멀티 유저 백엔드에서는 OAuthTokenExchangeSource를 써요. 그러면 Resolver가 요청별 subject_token을 필요로 해요.

from haystack_integrations.components.connectors.oauth import OAuthTokenResolver
from haystack_integrations.utils.oauth import OAuthTokenExchangeSource


resolver = OAuthTokenResolver(
    token_source=OAuthTokenExchangeSource(
        token_url="https://login.microsoftonline.com/<tenant>/oauth2/v2.0/token",
        client_id="aaa-bbb-ccc",
        subject_token_param="assertion",
        grant_type="urn:ietf:params:oauth:grant-type:jwt-bearer",
        scopes=["https://graph.microsoft.com/Files.Read.All"],
        extra_token_params={"requested_token_use": "on_behalf_of"},
    ),
)

# `subject_token` is the incoming per-request user assertion, injected by your application.
access_token = resolver.run(subject_token="<incoming-user-assertion>")["access_token"]

파이프라인에서 쓰기

파이프라인에서는 Resolver의 access_token 출력을 하나 이상의 다운스트림 컴포넌트의 access_token 입력에 연결해요. 아래 예제는 Resolver를 MSSharePointRetriever에 연결해서, 실행 시점에는 검색어만 있으면 SharePoint를 검색하게 만들어요.

from haystack import Pipeline
from haystack.utils import Secret
from haystack_integrations.components.connectors.oauth import OAuthTokenResolver
from haystack_integrations.utils.oauth import OAuthRefreshTokenSource
from haystack_integrations.components.retrievers.microsoft_sharepoint import (
    MSSharePointRetriever,
)


pipeline = Pipeline()
pipeline.add_component(
    "resolver",
    OAuthTokenResolver(
        token_source=OAuthRefreshTokenSource(
            token_url="https://login.microsoftonline.com/common/oauth2/v2.0/token",
            client_id="aaa-bbb-ccc",
            refresh_token=Secret.from_env_var("MS_REFRESH_TOKEN"),
            scopes=[
                "https://graph.microsoft.com/Files.Read.All",
                "https://graph.microsoft.com/Sites.Read.All",
                "offline_access",
            ],
        ),
    ),
)

pipeline.add_component("retriever", MSSharePointRetriever(top_k=5))
pipeline.connect("resolver.access_token", "retriever.access_token")

result = pipeline.run({"retriever": {"query": "quarterly roadmap"}})
documents = result["retriever"]["documents"]

하나의 access_token 출력을 여러 다운스트림 입력에 연결할 수 있어요. 같은 토큰을 retriever와 fetcher 양쪽에 공급하는 전체 retrieve-then-fetch 파이프라인은 MSSharePointFetcher와 GoogleDriveFetcher 페이지를 참고하세요.