Frame.io Python SDK — 인증 가이드

이 가이드는 Frame.io Python SDK(frameio)를 사용하여 Frame.io API로 인증하는 방법을 설명합니다. Frame.io V4 API는 Adobe의 OAuth 2.0 ID 플랫폼인 Adobe IMS(Identity Management Service)를 사용합니다. 이 문서는 Python 개발자를 위한 독립형 참조 문서입니다. 아래의 모든 코드 예제와 흐름은 frameio 패키지에만 해당됩니다.


Python SDK의 인증 유형

Python SDK는 4가지 인증 옵션을 지원합니다.

방법사용 사례사용자 상호 작용?클라이언트 시크릿 필요?
정적 토큰빠른 스크립트, 테스트 또는 이미 토큰이 있는 경우아니요아니요
서버 간 인증백엔드 서비스, cron 작업, 자동화아니요
웹 앱서버측 앱(Flask, Django, FastAPI)
SPA(PKCE)브라우저 앱, CLI 또는 시크릿을 저장할 수 없는 앱아니요
서버 간 인증을 사용하면 앱이 사용자 상호 작용 없이 서비스 계정으로 작동할 수 있습니다. Adobe Admin Console을 통해 관리되는 Frame.io V4 계정에서만 사용할 수 있습니다. 웹 앱SPA를 사용하면 앱이 특정 사용자 역할을 수행할 수 있습니다. 둘 다 내부적으로 Adobe IMS를 사용합니다. 사용자가 앱을 인증하면 SDK가 결과 코드를 토큰으로 교환합니다. Python SDK는 IMS /authorize/v2/token/v3 흐름을 처리합니다. 웹 앱의 경우 클라이언트 시크릿이 필요하고, SPA의 경우 PKCE를 대신 사용합니다.

Adobe의 네이티브 앱 자격 증명은 사용자 지정 URI 스키마 핸들러(예: adobe+<hash>://…</hash>)가 OS 레벨에서 리디렉션을 가로막도록 요구합니다. Python은 이러한 핸들러를 등록하는 표준 방법이 없으므로, Python SDK는 NativeAppAuth 클래스를 제공하지 않습니다. 사용자 대화형 Python 앱의 경우 로컬 콜백 서버(예: Flask 또는 FastAPI)와 함께 WebAppAuth를 사용하세요. 대화형이 아닌 워크로드의 경우 ServerToServerAuth를 사용하세요.


서비스 계정 사용자

서버 간 인증을 사용할 때 애플리케이션은 서비스 계정 사용자 역할을 합니다. 이는 서비스를 대신하여 작업을 수행할 수 있는 고유한 계정 유형입니다. 이 계정은 Frame.io의 다른 사용자에게 표시됩니다. 서비스 계정이 작업을 수행하면 UI에 해당 이름이 표시됩니다. Adobe Admin ConsoleDeveloper Console을 통해 서비스 계정 액세스 권한을 부여하고 취소할 수 있습니다. 서비스 계정 이름은 Frame.io UI에서 관리됩니다. 기본적으로 첫 번째 S2S 연결의 이름은 Service Account User, 두 번째는 Service Account User 2 등으로 지정됩니다.


빠른 시작

사전 요구 사항

  1. Adobe Developer Console자격 증명:
  • 클라이언트 ID — 모든 OAuth 흐름에 필요 - 클라이언트 시크릿 — 서버 간 및 웹 앱 흐름에 필요 - 리디렉션 URI — 웹 앱 및 SPA 흐름에 필요하며, Adobe 프로젝트에 등록되어야 함
  1. SDK 설치:
$pip install frameio

방법 선택

  • 사용자가 개입하지 않습니까? 서버 간(ServerToServerAuth) 방식을 사용하세요.
  • 사용자가 개입하며 시크릿을 저장할 수 있습니까? 웹 앱(WebAppAuth) 방식을 사용하세요.
  • 사용자가 개입하지만 시크릿을 저장할 수 없습니까? SPA(SPAAuth) 방식을 사용하세요.

액세스 토큰

(다른 OAuth 시스템 또는 이전 교환(예: API 탐색기)에서 발급받은) 액세스 토큰이 이미 있는 경우 이를 직접 전달할 수 있습니다.

1from frameio import Frameio
2
3client = Frameio(token="YOUR_ACCESS_TOKEN")

이것이 가장 간단한 방식이지만, 토큰은 결국 만료되며 SDK가 이를 대신 새로 고쳐주지 않습니다.

이전 개발자 토큰

아직 Adobe Admin Console을 통해 관리되지 않는 V4 마이그레이션 계정의 경우, Frame.io 개발자 사이트에서 발급받은 이전 개발자 토큰을 계속 사용할 수 있습니다. 반드시 x-frameio-legacy-token-auth 헤더를 포함하고 이를 true로 설정해야 합니다.

1from frameio import Frameio
2
3client = Frameio(
4 token="YOUR_LEGACY_DEVELOPER_TOKEN",
5 headers={"x-frameio-legacy-token-auth": "true"},
6)

이전 개발자 토큰은 만료되지 않지만 이는 임시적인 전환 메커니즘입니다. 새로운 통합 및 프로덕션 워크로드의 경우 아래의 OAuth 2.0 흐름 중 하나를 사용하는 것이 좋습니다. 자세한 내용은 마이그레이션 가이드를 참조하세요.


서버 간 방식(클라이언트 자격 증명)

사용자 상호 작용 없이 Frame.io 액세스가 필요한 백엔드 서비스 및 스크립트에 이 방식을 사용하세요. 이 흐름은 Adobe Admin Console을 통해 관리되는 Frame.io V4 계정에서만 사용할 수 있습니다. 애플리케이션은 사용자 개입 없이 서비스 계정 사용자로 인증됩니다.

1 from frameio import Frameio
2 from frameio.auth import ServerToServerAuth
3
4 auth = ServerToServerAuth(
5 client_id="YOUR_CLIENT_ID",
6 client_secret="YOUR_CLIENT_SECRET",
7 )
8
9 client = Frameio(token=auth.get_token)

이것이 전부입니다. auth.get_token은 모든 요청에서 SDK가 호출하는 콜러블 오브젝트입니다. 현재 토큰이 여전히 유효하면 즉시 반환됩니다. 토큰이 만료될 예정이면 먼저 완벽하게 투명한 방식으로 새 토큰을 가져옵니다.

작동 방식

클라이언트 자격 증명(클라이언트 ID + 시크릿)은 절대 만료되지 않습니다. 보안 관리를 위해 수동으로만 순환시킵니다. S2S는 수동 개입 없이 사실상 영구적이고 중단 없는 API 액세스를 제공합니다.

내부 동작 방식:

  1. 첫 번째 API 호출 시, get_tokenclient_credentials 권한 부여를 사용하여 Adobe IMS에 새 액세스 토큰을 요청합니다.
  2. 토큰은 메모리에 캐시됩니다. 개별 액세스 토큰은 만료(일반적으로 24시간)되지만 이는 자동으로 처리됩니다.
  3. 캐시된 토큰이 새로 고침 버퍼(기본값: 만료 60초 전) 내에 있으면, SDK는 동일한 클라이언트 자격 증명을 사용하여 새 토큰을 자동으로 가져옵니다.
  4. 새로 고침 토큰은 관여하지 않습니다. 클라이언트 자격 증명 자체가 수명이 긴 시크릿이며, 이를 통해 언제든 새 액세스 토큰을 발행할 수 있습니다.

명시적 인증

(예를 들어 시작 시 잘못된 자격 증명에 대해 빠르게 실패 처리를 하기 위해) 즉시 토큰을 가져오려는 경우는 다음과 같습니다.

1auth = ServerToServerAuth(client_id="...", client_secret="...")
2auth.authenticate() # raises AuthenticationError if credentials are invalid
3client = Frameio(token=auth.get_token)

웹 앱(권한 부여 코드)

사용자가 자신의 Adobe ID로 로그인하는 서버 측 애플리케이션에 이 방식을 사용하세요. 이 흐름에는 클라이언트 시크릿이 필요하며, 이는 서버에 안전하게 저장되어야 합니다.

1

사용자를 Adobe IMS로 리디렉션

1 auth.refresh() # fetches a new access token using the refresh token
2

콜백 처리

Adobe IMS가 사용자를 redirect_uri로 리디렉션하면 codestate 매개변수를 추출합니다. 저장한 내용과 state가 일치하는지 확인한 다음, 코드를 토큰으로 교환합니다.

1 auth.refresh() # fetches a new access token using the refresh token

이는 권한 부여 코드를 액세스 토큰 및 새로 고침 토큰으로 교환하고 두 가지를 내부적으로 저장합니다.

3

클라이언트 사용

1 from frameio import Frameio
2
3 client = Frameio(token=auth.get_token)

이것이 전부입니다. 이 시점부터 get_token이 토큰 수명 주기를 자동으로 관리합니다. 액세스 토큰의 만료가 임박하면 SDK는 새로 고침 토큰을 사용하여 새 토큰을 가져옵니다. 사용자 상호 작용이 필요하지 않습니다.

전체 Flask 예제

1import secrets
2from flask import Flask, redirect, request, session
3from frameio import Frameio
4from frameio.auth import WebAppAuth
5
6app = Flask(__name__)
7app.secret_key = secrets.token_bytes(32)
8
9auth = WebAppAuth(
10 client_id="YOUR_CLIENT_ID",
11 client_secret="YOUR_CLIENT_SECRET",
12 redirect_uri="http://localhost:5000/callback",
13)
14
15@app.route("/login")
16def login():
17 state = secrets.token_urlsafe(32)
18 session["oauth_state"] = state
19 return redirect(auth.get_authorization_url(state=state))
20
21@app.route("/callback")
22def callback():
23 if request.args.get("state") != session.pop("oauth_state", None):
24 return "Invalid state parameter", 403
25
26 auth.exchange_code(code=request.args["code"])
27
28 client = Frameio(token=auth.get_token)
29 accounts = client.accounts.index()
30 return f"Authenticated — {len(accounts.data)} account(s) accessible."

단일 페이지 앱 / PKCE(권한 부여 코드 + PKCE)

클라이언트 시크릿을 안전하게 저장할 수 없는 브라우저 기반 애플리케이션, 데스크톱 앱, 또는 CLI 도구에 이 방식을 사용하세요. 이 흐름은 PKCE(RFC 7636)를 사용하여 권한 부여 코드 교환을 보호합니다.

1

권한 부여 URL 생성

1 from frameio.auth import SPAAuth
2
3 auth = SPAAuth(
4 client_id="YOUR_CLIENT_ID",
5 redirect_uri="https://yourapp.com/callback",
6 )
7
8 import secrets
9 state = secrets.token_urlsafe(32)
10
11 result = auth.get_authorization_url(state=state)
12 # result.url -> redirect the user here
13 # result.code_verifier -> store this securely until the callback

get_authorization_url은 (PKCE code_challenge가 임베드된) 전체 URL 및 다음 단계에서 필요한 code_verifier가 포함된 AuthorizationUrlResult를 반환합니다.

2

검증자를 사용하여 코드 교환

사용자가 다시 리디렉션된 경우:

1 auth.exchange_code(
2 code="CODE_FROM_CALLBACK",
3 code_verifier=result.code_verifier,
4 )
3

클라이언트 사용

1 from frameio import Frameio
2
3 client = Frameio(token=auth.get_token)

이것이 전부입니다. 새로 고침은 웹 앱 방식과 동일하게 작동하며, SDK가 새로 고침 토큰을 자동으로 사용합니다. 차이점은 SPA 흐름이 공개 클라이언트용으로 설계되었기 때문에 새로 고침 중에 클라이언트 시크릿이 전송되지 않는다는 점입니다.


Async 사용

모든 인증 클래스에는 Async 접두사가 붙은 비동기 대응 클래스가 있습니다. 위의 코드 예시에는 해당하는 경우 SyncAsync 탭이 포함되어 있습니다.

SyncAsync
ServerToServerAuthAsyncServerToServerAuth
WebAppAuthAsyncWebAppAuth
SPAAuthAsyncSPAAuth
API는 동일합니다. get_authorization_url은 동기식(I/O 불필요)으로 유지되는 반면, exchange_code, refresh, revoke, get_token은 모두 async입니다. 비동기 클래스는 AsyncFrameio와 함께 사용하세요.

수동 토큰 새로 고침

웹 앱 및 SPA 흐름의 경우, SDK는 get_token을 통해 토큰을 자동으로 새로 고칩니다. 명시적인 제어가 필요한 경우 refresh()를 직접 호출할 수 있습니다.

1 auth.refresh() # fetches a new access token using the refresh token

이 기능은 자동 새로 고침 버퍼에 의존하는 대신 중요한 작업을 앞두고 강제로 새로 고치고자 할 때 유용합니다.


토큰 지속성

모든 인증 클래스는 재시작 시에도 토큰 상태를 유지할 수 있도록 export_tokens()import_tokens()를 지원합니다. 웹 앱 및 SPA 흐름의 경우 액세스 토큰과 새로 고침 토큰이 기본적으로 메모리에 상주하므로 이는 특히 중요합니다. 이를 유지하지 않으면 애플리케이션이 다시 시작될 때 사용자가 재인증을 해야 합니다. 서버 간(S2S) 방식의 경우 지속성은 선택 사항이지만(클라이언트 자격 증명으로 항상 새 토큰을 발행할 수 있음), 캐시된 토큰을 가져오면 시작 시 한 번의 추가 왕복을 피할 수 있습니다.

내보내기 및 가져오기

1# After exchange_code(), save the token state
2token_data = auth.export_tokens()
3# token_data is a dict: {"access_token": "...", "refresh_token": "...", "expires_at": 1234567890.0}
4# Save it to your database, file, or secret store
5
6# On next startup, restore it
7auth.import_tokens(token_data)
8client = Frameio(token=auth.get_token)
9# The SDK will automatically refresh if the token is near expiry

on_token_refreshed를 활용한 자동 지속성

토큰이 새로 고쳐질 때마다 자동으로 유지하려면 on_token_refreshed 콜백을 사용합니다.

1import json
2from pathlib import Path
3
4TOKEN_FILE = Path("tokens.json")
5
6def save_tokens(tokens: dict):
7 TOKEN_FILE.write_text(json.dumps(tokens))
8
9auth = WebAppAuth(
10 client_id="...",
11 client_secret="...",
12 redirect_uri="...",
13 on_token_refreshed=save_tokens,
14)
15
16# On startup, restore if available
17if TOKEN_FILE.exists():
18 auth.import_tokens(json.loads(TOKEN_FILE.read_text()))

콜백은 export_tokens()와 동일한 사전 형태를 수신하며, 토큰 새로 고침이 성공할 때마다 실행됩니다. 비동기 클래스의 경우 on_token_refreshed는 일반 함수이거나 비동기 함수일 수 있습니다. 두 가지 모두 지원됩니다.


토큰 해지

사용자를 로그아웃하고 Adobe IMS에서 해당 토큰을 무효화하려면 다음을 실행합니다.

1auth.revoke()

이는 액세스 토큰 및 새로 고침 토큰 모두에 대해 최선의 노력으로 Adobe IMS에 해지 요청을 보낸 다음 모든 로컬 토큰 상태를 지웁니다. 해지 후에는 사용자가 다시 인증을 거쳐야 합니다.

비동기 클래스의 경우 await await auth.revoke()를 사용합니다.


오류 처리

모든 인증 오류는 FrameioAuthError에서 상속되므로, 이를 포괄적으로 잡거나 특정 케이스를 분리하여 처리할 수 있습니다.

1from frameio.auth import (
2 FrameioAuthError,
3 AuthenticationError,
4 TokenExpiredError,
5 ConfigurationError,
6 NetworkError,
7 RateLimitError,
8)
9
10try:
11 auth.exchange_code(code="...")
12except TokenExpiredError:
13 # The refresh token has expired; redirect the user to sign in again
14 pass
15except AuthenticationError as e:
16 # Token exchange failed
17 print(f"Error: {e.error_code} - {e.error_description}")
18except NetworkError:
19 # Timeout or connection failure (after retries)
20 pass
21except RateLimitError as e:
22 # 429 from Adobe IMS; retry after e.retry_after seconds
23 pass
24except FrameioAuthError:
25 # Catch-all for any other auth error
26 pass

오류 참조

예외발생 조건
ConfigurationError구성이 누락되었거나 유효하지 않음(예: 비어 있는 client_id, HTTPS가 아닌 리디렉션 URI)
AuthenticationErrorAdobe IMS에서 토큰 교환 또는 새로 고침 거부(.error_code.error_description 속성 포함)
TokenExpiredError새로 고침 토큰 자체가 만료됨. 사용자가 다시 인증해야 함
NetworkError모든 재시도 후에도 HTTP 시간 초과 또는 연결 실패 발생
RateLimitErrorAdobe IMS에서 429를 반환함. 백오프 지침을 위해 .retry_after 확인 필요
PKCEErrorPKCE 확인 실패(SPA 흐름)

프로덕션 환경에서 만료된 새로 고침 토큰 처리하기

웹 앱 및 SPA 흐름의 경우 새로 고침 토큰은 결국 만료됩니다. 이 경우 get_tokenTokenExpiredError를 발생시킵니다. 이를 잡아내어 사용자를 권한 부여 흐름을 통해 다시 리디렉션해야 합니다.

1from frameio.auth import TokenExpiredError
2
3try:
4 client = Frameio(token=auth.get_token)
5 assets = client.files.list(project_id="...")
6except TokenExpiredError:
7 # Clear persisted tokens and redirect user to login
8 auth.revoke()
9 return redirect("/login")

구성 참조

모든 인증 클래스는 다음 선택적 매개변수를 허용합니다.

매개 변수Default설명
범위흐름별 기본값공백으로 구분된 OAuth 권한입니다. S2S의 기본값은 openid AdobeID frame.s2s.all이며, 사용자 대면 흐름의 기본값은 openid email profile offline_access additional_info.roles입니다.
ims_base_urlhttps://ims-na1.adobelogin.comAdobe IMS 기본 URL입니다. 스테이징 또는 비프로덕션 환경을 위해 이를 재정의할 수 있습니다.
http_clientNone사용자 지정 httpx.프록시, mTLS, 또는 연결 풀링을 위한 Client(또는 httpx.AsyncClient)입니다.
timeout30토큰 엔드포인트 호출에 대한 HTTP 요청 시간 제한(초 단위)입니다.
max_retries2일시적인 오류(5xx, 시간 초과) 발생 시 최대 재시도 횟수입니다. 속도 제한 재시도(429)는 별도로 추적됩니다.
refresh_buffer60사전 새로 고침을 트리거하기 위해 토큰이 만료되기 전까지 남은 시간(초 단위)입니다.
on_token_refreshedNone토큰 새로 고침이 성공할 때마다 실행되는 콜백입니다. access_token, refresh_token, expires_at이 포함된 사전을 수신합니다.

스테이징 환경

ims_base_url을 재정의하여 스테이징 Adobe IMS 인스턴스를 지정합니다. 또한 프로그래밍 방식으로 프로덕션 값을 참조해야 하는 경우 SDK는 DEFAULT_IMS_BASE_URL(https://ims-na1.adobelogin.com)을 내보냅니다.

1auth = ServerToServerAuth(
2 client_id="...",
3 client_secret="...",
4 ims_base_url="https://ims-na1-stg1.adobelogin.com",
5)

사용자 지정 HTTP 클라이언트

프록시 지원 또는 사용자 지정 TLS 구성에 사용됩니다.

1import httpx
2
3http_client = httpx.Client(
4 proxy="http://corporate-proxy:8080",
5 verify="/path/to/custom-ca-bundle.pem",
6)
7
8auth = ServerToServerAuth(
9 client_id="...",
10 client_secret="...",
11 http_client=http_client,
12)

스레드 안전성

동기 인증 클래스는 스레드로부터 완전히 안전합니다. 여러 스레드가 동시에 get_token을 호출하여 새로 고침이 필요한 경우 단 하나의 스레드만 새로 고침을 수행합니다. 나머지 스레드들은 대기하다가 동일한 결과를 받게 됩니다. 외부 잠금이 필요하지 않습니다. 비동기 클래스는 asyncio.Lock을 사용하여 동일하게 이를 보장하므로, 단일 이벤트 루프 내의 동시 코루틴에서 안전하게 사용할 수 있습니다.