CLI 인증
CLI 인증 (CLI Authentication)
litellm cli로 LiteLLM Gateway에 인증하는 방법을 알려드려요. 많은 개발자에게 LiteLLM Gateway에 대한 셀프서비스 액세스를 제공하려는 경우에 적합해요.
출처: 문서
본문
데모 (Demo)
사용법 (Usage)
사전 요구사항 - Beta 플래그로 LiteLLM 프록시 시작
Beta 기능 - 필수
CLI SSO 인증은 현재 베타예요. LiteLLM 프록시를 시작할 때 이 환경 변수를 반드시 설정해야 해요:
export EXPERIMENTAL_UI_LOGIN="True"
litellm --config config.yaml
또는 프록시 시작 명령에 추가하세요:
EXPERIMENTAL_UI_LOGIN="True" litellm --config config.yaml
구성 (Configuration)
JWT 토큰 만료 (JWT Token Expiration)
기본적으로 CLI 인증 토큰은 24시간 후 만료돼요. LiteLLM 프록시를 시작할 때 LITELLM_CLI_JWT_EXPIRATION_HOURS 환경 변수를 설정해 이 만료 시간을 사용자 지정할 수 있어요:
# CLI JWT 토큰이 48시간 후 만료되도록 설정
export LITELLM_CLI_JWT_EXPIRATION_HOURS=48
export EXPERIMENTAL_UI_LOGIN="True"
litellm --config config.yaml
또는 단일 명령으로:
LITELLM_CLI_JWT_EXPIRATION_HOURS=48 EXPERIMENTAL_UI_LOGIN="True" litellm --config config.yaml
예시:
LITELLM_CLI_JWT_EXPIRATION_HOURS=12- 토큰이 12시간 후 만료LITELLM_CLI_JWT_EXPIRATION_HOURS=168- 토큰이 7일(168시간) 후 만료LITELLM_CLI_JWT_EXPIRATION_HOURS=720- 토큰이 30일(720시간) 후 만료
실험 UI 세션 (Experimental UI Session)
EXPERIMENTAL_UI_LOGIN이 활성화되면 브라우저 UI 로그인 세션은 고정된 10분 만료(구성 불가)를 사용해요. LITELLM_UI_SESSION_DURATION은 비실험 플로우에만 적용돼요.
tip
현재 토큰의 나이와 만료 상태는 다음과 같이 확인할 수 있어요:
lite whoami
검증 코드 사전 채우기 (Pre-fill the verification code)
기본적으로 lite login을 완료하는 브라우저 페이지는 터미널이 출력한 검증 코드를 직접 입력하라고 요구해요. lite login이 그 페이지를 코드가 이미 채워진 채 열도록 하려면(확인하고 Continue만 클릭) 프록시에 다음을 설정하세요:
general_settings:
allow_cli_sso_verification_uri_complete: true
이 플래그는 기본적으로 꺼져 있어요. 코드를 직접 입력하는 것이 브라우저 페이지를 로그인을 시작한 터미널에 연결해주기 때문이에요. 플래그가 켜져 있어도, 확인하기 전에 사전 채워진 코드가 터미널이 출력한 것과 일치하는지 여전히 확인하세요. 오래된 lite 버전은 어느 쪽이든 코드 없이 페이지를 열므로 CLI도 업그레이드하세요.
그 브라우저가 이미 SSO 제공자에 로그인되어 있고 코드를 완전히 건너뛰고 싶다면, lite login --pkce를 실행하세요. Approve 한 번 클릭으로 터미널이 Login successful!을 출력해요. Browser sign-in with PKCE 참고.
속성 메타데이터 (Attribution metadata, OIDC claims)
허용 목록에 있는 OIDC claims를 LiteLLM 사용자의 메타데이터로 매핑하고 /sso/cli/poll에서 attribution_metadata로 CLI에 반환해요. 클라이언트에서 큰 그룹 목록을 파싱하지 않고도(예: 고용 유형, 원가 센터) 안정적인 속성 필드를 위해 사용해요.
시작 전에 프록시에 설정하세요:
export CLI_SSO_CLAIM_MAP="employment_type->acme_employment_type,org_info.department->department"
export GENERIC_USER_EXTRA_ATTRIBUTES="employment_type,org_info.department"
CLI_SSO_CLAIM_MAP과 LITELLM_CLI_SSO_CLAIM_MAP은 동등해요. 형식: 쉼표로 구분된 source_claim->metadata_key 쌍. 대상의 선택적 metadata. 접두사는 제거되고, 값은 사용자의 metadata JSON 컬럼에 저장돼요.
| 부분 | 의미 |
|---|---|
| source_claim | OIDC claim 경로 (점 표기법), GENERIC_USER_EXTRA_ATTRIBUTES의 필드 포함 |
| metadata_key | LiteLLM 사용자 메타데이터 아래의 키 (점을 통한 중첩 키 지원) |
비시크릿 스칼라 값(문자열, int, float, bool)만 저장·반환돼요. 리스트, 객체, 그리고 token이나 secret 같은 조각을 포함하는 대상 키는 버려져요.
예시 폴 응답 (SSO 완료 후):
{
"status": "ready",
"key": "eyJ...",
"user_id": "[email protected]",
"attribution_metadata": {
"acme_employment_type": "full_time",
"department": "Engineering"
}
}
실제 IdP 없이 로컬 테스트: LiteLLM 저장소에서 python scripts/mock_oidc_server_for_cli_sso.py를 실행하고, Generic SSO env vars를 http://127.0.0.1:8765로 지정한 다음 python scripts/test_cli_sso_claims_e2e.py를 실행하세요.
단계 (Steps)
CLI 설치 (Install the CLI)
lite 클라이언트는 가벼운 랩톱 설치예요. LiteLLM 프록시를 가리키고 그것을 통해 코딩 에이전트를 실행해요. 프록시 서버 런타임은 전혀 포함하지 않아요. 원라인 설치자는 curl만 필요해요. uv가 없으면 부트스트랩하고, uv가 호환 Python을 프로비저닝해줘요:
curl -fsSL https://raw.githubusercontent.com/BerriAI/litellm/main/scripts/install-cli.sh | sh
이미 uv가 있고 직접 다루고 싶다면? 패키지를 직접 설치하세요:
uv tool install 'litellm[cli]'
이 중 어느 것이든 lite 명령을 제공해요. litellm[proxy]에서 설치한 프록시 서버도 함께 제공하지만, 그 추가분은 keyring을 빠뜨리므로 자격 증명이 OS 키체인 대신 파일에 저장돼요. 터미널에서 입력해 시작하세요:
lite
환경 변수 설정 (Set up environment variables)
로컬 머신에서 프록시 URL을 설정하세요:
export LITELLM_PROXY_URL=http://localhost:4000
(실제 프록시 URL로 교체)
로그인 (Login)
lite login
이것은 인증할 브라우저 창을 열어요. LiteLLM 프록시를 SSO 제공자에 연결했다면 SSO 자격 증명으로 로그인할 수 있어요. 로그인 후 CLI로 LiteLLM Gateway에 요청할 수 있어요.
브라우저 페이지는 터미널이 출력한 검증 코드를 요구해요. 직접 입력을 건너뛰려면, 프록시가 검증 코드를 사전 채우게 하거나, 브라우저가 이미 SSO 세션을 보유하고 있다면 코드가 전혀 필요 없는 lite login --pkce를 사용하세요.
자격 증명은 OS 키체인에 들어가고, lite login이 저장 위치를 출력해요. 키체인이 없는 머신에서는 소유자 전용 권한으로 ~/.litellm/token.json에 폴백해요. 자세한 내용과 키체인 저장을 끄는 방법은 lite login credential을 보세요.
모델을 보기 위한 테스트 요청 (Make a test request to view models)
lite models list
이것은 사용 가능한 모든 모델을 나열해요.
PKCE로 브라우저 로그인 (Browser sign-in with PKCE)
lite login --pkce는 OAuth 2.0 인가 코드 + PKCE(S256)로 시스템 브라우저를 통해 로그인해요. CLI는 공개 클라이언트로 동작해요: 프록시에 자기 자신을 등록하고, OS가 할당한 루프백 포트에서 수신하며, 클라이언트 시크릿을 절대 보유하지 않아요. 프록시 로그인 페이지와 SSO 제공자가 인증을 하고, CLI는 결과 자격 증명만 보게 돼요.
export LITELLM_PROXY_URL=https://litellm.example.com
lite login --pkce
Opening browser to: https://litellm.example.com/authorize?response_type=code&client_id=llm_dcrc_...&redirect_uri=http%3A%2F%2F127.0.0.1%3A57485%2Fcallback&state=...&code_challenge=...&code_challenge_method=S256&resource=https%3A%2F%2Flitellm.example.com
Approve the sign-in in your browser. Waiting...
Login successful!
JWT Token: R46gzIdke6PgQZUiGctb...
Credential stored in your OS keychain.
You can now use the CLI without specifying --api-key
브라우저에서 세션이 없으면 프록시 로그인 페이지가 먼저 열려요 (프록시가 ID 제공자에 연결돼 있으면 SSO, 아니면 사용자 이름·비밀번호). 로그인 후 브라우저는 동의 페이지로 돌아와요. 페이지는 CLI의 루프백 주소(예: http://127.0.0.1:57485)를 명명하고, 로그인한 사용자를 보여주며, 요청을 귀속시킬 팀을 선택할 수 있게 해줘요. 팀에 속한 사용자는 lite login과 같은 규칙으로 하나를 반드시 골라야 해요. Approve를 클릭하세요. 브라우저는 "Signed in to LiteLLM. You can close this window and return to the terminal."을 보여주고 터미널은 Login successful!을 출력해요.
클래식 lite login 플로우와 가상 API 키는 변경 없이 계속 동작해요. --pkce는 /.well-known/litellm-cli-auth를 서빙하는 프록시가 필요해요. 오래된 프록시에서는 그렇게 말하는 메시지와 함께 명령이 중단돼요.
저장된 자격 증명 (The stored credential)
키와 갱신 토큰 모두 OS 키체인으로 가요. lite login이 키를 두는 곳과 같은 곳이에요. 나머지 레코드는 ~/.litellm/token.json(모드 0600)으로 가요. lite login이 쓰는 base_url, user_id, user_role 필드 옆에 --pkce 레코드는 expires_at, client_id, token_endpoint, revocation_endpoint, resource, team_id도 보유해요. 이 중 어느 것도 홀로 키를 얻지 못해요. 사용 가능한 키체인이 없는 머신에서는 키와 갱신 토큰이 같은 파일로 폴백하고 lite login이 그렇게 말해요. 그럴 때는 ~/.litellm/token.json을 민감하게 취급하세요. 읽을 수 있는 사람이라면 누구나 갱신 토큰을 동작하는 키로 교환할 수 있기 때문이에요. 이전 lite로 만든 --pkce 로그인은 다음 lite 명령이 읽어 키체인으로 옮길 때까지 갱신 토큰을 파일에 남겨둬요.
키는 LITELLM_CLI_JWT_EXPIRATION_HOURS(기본 24시간, JWT Token Expiration 참고) 후 만료돼요. 만료 시 다시 로그인할 필요는 없어요. 키가 필요한 다음 lite 명령이 갱신 토큰으로 이를 갱신하고 새 쌍을 저장해요. 각 갱신은 갱신 토큰을 순환시키며, 이미 사용된 갱신 토큰은 거부돼요.
다른 도구에서 자격 증명 사용 (Use the credential from other tools)
lite auth print-token은 현재 키를 stdout으로 출력하고 다른 것은 아무것도 출력하지 않아요 (진단은 stderr로). 키가 곧 만료되면 먼저 갱신하므로, 이걸 호출하는 도구는 항상 동작하는 키를 얻어요.
Claude Code는 이를 apiKeyHelper로 실행할 수 있어요. lite login --pkce --config-claude가 그것을 작성해줘요: env.ANTHROPIC_BASE_URL을 프록시로, apiKeyHelper를 lite auth print-token(lite의 절대 경로와 프록시 URL 포함)로 ~/.claude/settings.json에 설정하고, 다른 설정은 그대로 둬요. 직접 하려면:
~/.claude/settings.json
{
"env": {
"ANTHROPIC_BASE_URL": "https://litellm.example.com"
},
"apiKeyHelper": "/absolute/path/to/lite --base-url https://litellm.example.com auth print-token"
}
OpenCode나 다른 OpenAI 호환 클라이언트에서는 클라이언트를 <proxy>/v1로 지정하고 환경 변수를 통해 키를 전달하세요:
LITELLM_PROXY_KEY=$(lite auth print-token) opencode
opencode.json
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"litellm": {
"npm": "@ai-sdk/openai-compatible",
"name": "LiteLLM proxy",
"options": {
"baseURL": "https://litellm.example.com/v1",
"apiKey": "{env:LITELLM_PROXY_KEY}"
},
"models": {
"gpt-5.4-mini": { "name": "gpt-5.4-mini" }
}
}
},
"model": "litellm/gpt-5.4-mini"
}
키로 만든 요청은 귀하의 사용자와 선택한 팀에 귀속되므로, 로그 페이지에서 귀하의 이름 아래에 표시되고 귀하의 사용자·팀 예산이 차감돼요.
로그아웃 (Log out)
lite logout
lite logout은 갱신 토큰을 프록시의 POST /revoke 엔드포인트로 보낸 다음, 키체인 항목과 ~/.litellm/token.json 두 저장소를 모두 지워요. 그 시점부터 갱신 토큰은 무효예요. 키 자체는 해지할 수 없어요. LITELLM_CLI_JWT_EXPIRATION_HOURS 안에 스스로 만료돼요.
lite login --pkce나 클래식 lite login으로 다시 로그인하면 교체하는 레코드에도 동일하게 적용돼요. 새 자격 증명을 먼저 저장한 다음, 이전 로그인의 갱신 토큰을 해지해요. 그래서 다시 로그인한 후에는 이전 token.json 사본을 갱신할 수 없어요. 해지에 프록시에 도달하지 못하면 로그인은 여전히 성공하고 그렇게 말해요.
관리자는 대시보드에서 --pkce 로그인을 해지할 수 없어요. 보유자의 lite logout만이 갱신 토큰을 조기에 잘라내요. 모든 갱신은 프록시에서 사용자를 다시 읽으므로, 사용자를 비활성화하거나 팀에서 제거하면 다음 갱신이 실패하고 키가 LITELLM_CLI_JWT_EXPIRATION_HOURS 안에 소진돼요. 갱신이 거부되면 lite auth print-token과 다른 모든 lite 명령이 프록시가 준 이유를 stderr로 출력하고, 키가 소진되면 lite login --pkce를 다시 실행하라고 말해요.
여러 워커 또는 복제본 (Several workers or replicas)
갱신 토큰 단일 사용, 재생 탐지, POST /revoke는 Redis 캐시가 구성돼 있을 때(Redis cache_params가 있는 litellm_settings.cache 또는 general_settings.coordination_redis) 프록시의 Redis 캐시를 통해 강제되고, Redis에 도달할 수 없는 동안에는 fail closed로 동작해요. 그때 도착한 갱신이나 POST /revoke는 503 temporarily_unavailable로 응답하고, CLI는 이미 가진 키를 유지해 다음 명령에서 다시 시도하며, lite logout은 로그인 레코드를 유지하고 exit 1로 나간 뒤 곧 다시 실행하라고 요청하므로 갱신 토큰은 여전히 해지돼요. Redis가 없으면 각 워커가 자체 레코드를 유지하므로, 워커나 복제본이 둘 이상인 프록시에서는 해지되었거나 이미 사용된 갱신 토큰을 그것을 본 적 없는 워커가 수락할 수 있어요. 단일 워커로 실행하거나 Redis를 구성하세요.
네이티브 클라이언트 계약 (Native client contract)
어떤 언어로든 작성된 CLI는 LiteLLM 소스를 읽지 않고 하나의 발견 문서에서 같은 로그인을 실행할 수 있어요. 일반적인 경우는 사용자를 로그인시킨 다음 OpenCode를 키로 시작하는 Go 런처예요. 계약은 버전이 매겨져요. 문서의 나머지를 신뢰하기 전에 contract_version을 확인하세요. 필드를 추가해도 버전은 올라가지 않아요. 의미가 바뀌거나 사라지는 필드만 올려요.
발견 문서 (Discovery document)
curl https://litellm.example.com/.well-known/litellm-cli-auth
{
"contract_version": 1,
"issuer": "https://litellm.example.com",
"authorization_endpoint": "https://litellm.example.com/authorize",
"token_endpoint": "https://litellm.example.com/token",
"registration_endpoint": "https://litellm.example.com/register",
"revocation_endpoint": "https://litellm.example.com/revoke",
"resource": "https://litellm.example.com",
"response_types_supported": ["code"],
"grant_types_supported": ["authorization_code", "refresh_token"],
"code_challenge_methods_supported": ["S256"],
"token_endpoint_auth_methods_supported": ["none"],
"revocation_endpoint_auth_methods_supported": ["none"]
}
resource는 프록시 origin이에요. authorize와 token 요청에 RFC 8707 resource 파라미터로 보내세요. 그 파라미터가 프록시 API 자격 증명을 요청하는 것이며, MCP 세션이 아니에요. 그것 없이는 같은 authorize 요청이 MCP connect 경로를 취하고, 주조된 토큰은 /v1/*에서 거부돼요.
URL은 요청의 base URL로 만들어져요. 로드 밸런서나 리버스 프록시 뒤에서는 프록시에 PROXY_BASE_URL을 공개 origin으로 설정해 issuer, 엔드포인트, resource가 사용자가 도달하는 주소를 명명하게 하세요. lite login --pkce는 RFC 8414 섹션 3.3이 요구하는 대로 이를 확인해요. issuer가 사용자가 입력한 --base-url과 다르면 --base-url로 전달할 issuer를 명명하는 메시지와 함께 멈추므로, 둘이 일치해야 해요.
단계
-
위 발견 문서를 가져와
contract_version이 1이고code_challenge_methods_supported가 S256을 포함하는지 확인하세요. 엔드포인트에 아무것도 게시하기 전에,issuer가 문서를 가져온 주소와 일치하는지(스킴, 호스트, 포트, 경로가 대소문자와 끝 슬래시를 무시하고 동일) 그리고 모든 엔드포인트와resource가 같은 origin에 있는지도 확인하세요. 등록, 토큰, 해지 엔드포인트에 리다이렉트를 따르지 않고 게시하세요. 307이나 308이면 Location이 가리키는 곳으로 코드와 verifier, 또는 갱신 토큰을 재생하게 돼요. -
공개 클라이언트 등록. OS가 할당한 포트의
127.0.0.1에서 리스너를 시작하고 그 주소를 redirect URI로 등록하세요. 반환된client_id를 보관하세요. 시크릿은 없어요.curl -X POST https://litellm.example.com/register \ -H 'content-type: application/json' \ -d '{ "client_name": "my-cli", "redirect_uris": ["http://127.0.0.1:53187/callback"], "token_endpoint_auth_method": "none", "grant_types": ["authorization_code", "refresh_token"], "response_types": ["code"] }'{ "client_id": "llm_dcrc_lq411b6QkPmfxjW...", "token_endpoint_auth_method": "none", "redirect_uris": ["http://127.0.0.1:53187/callback"] } -
PKCE code verifier(43~128자)와 그 S256 code challenge, 그리고 임의
state를 생성하고 시스템 브라우저를 authorization endpoint에서 열어요.https://litellm.example.com/authorize ?response_type=code &client_id=llm_dcrc_lq411b6QkPmfxjW... &redirect_uri=http://127.0.0.1:53187/callback &state=<random> &code_challenge=<S256 challenge> &code_challenge_method=S256 &resource=https://litellm.example.com프록시 세션이 없으면 브라우저는 로그인 페이지로 보내지고 이후 이 URL로 돌아와요. 세션이 있으면 동의 페이지가 바로 렌더링돼요. 사용자가 팀을 고르고 Approve를 클릭해요.
-
루프백 리스너에서 코드 받기. 브라우저는
http://127.0.0.1:53187/callback?code=<code>&state=<state>에 도달해요. 코드를 사용하기 전에state가 보낸 것과 일치하는지 확인하세요. 사용자가 Deny를 클릭했다면 콜백은code대신error와error_description을 담아요. -
코드를 자격 증명으로 교환. 요청은 form-encoded이며 클라이언트 시크릿이 없어요.
code_verifier가 클라이언트가 플로우를 시작한 당사자임을 증명해요.curl -X POST https://litellm.example.com/token \ -d grant_type=authorization_code \ -d code=<code> \ -d redirect_uri=http://127.0.0.1:53187/callback \ -d client_id=llm_dcrc_lq411b6QkPmfxjW... \ -d code_verifier=<verifier> \ -d resource=https://litellm.example.com{ "access_token": "LneZuxEFqvemEwK6lRzgg6BN...", "token_type": "Bearer", "expires_in": 86400, "refresh_token": "llm_srefresh_eyJhbGciOiJ...", "user_id": "[email protected]", "team_id": "a0a759e9-6234-4c75-bbad-b535f6c9e80e" }인가 코드는 단일 사용이에요. 다시 보내면 400과
{"error": "invalid_grant", "error_description": "the authorization code was already used"}를 반환해요. -
access_token을 프록시의 LLM 라우트에서 Bearer 토큰으로 사용하세요:/v1/chat/completions,/v1/responses,/v1/messages,/v1/models등. 지출은 토큰 응답의 사용자와 팀에 귀속돼요.curl https://litellm.example.com/v1/chat/completions \ -H "Authorization: Bearer LneZux...N..." \ -H 'content-type: application/json' \ -d '{"model": "gpt-5.4-mini", "messages": [{"role": "user", "content": "Say hi in three words."}]}' -
expires_in이 소진되기 전에 자격 증명 갱신. 응답은 5단계와 같은 형태이며 새 갱신 토큰을 담아요. 이전 갱신 토큰을 다시 사용하면 400invalid_grant로 거부되므로, 새 액세스 토큰을 사용하기 전에 새 쌍을 저장하세요.curl -X POST https://litellm.example.com/token \ -d grant_type=refresh_token \ -d refresh_token=llm_srefresh_eyJhbGciOiJ... \ -d client_id=llm_dcrc_lq411b6QkPmfxjW... \ -d resource=https://litellm.example.com -
로그아웃 시 갱신 토큰 해지(RFC 7009), 그리고 사용자가 다시 로그인할 때 교체하는 자격 증명의 갱신 토큰도 해지. 갱신 토큰만 해지할 수 있어요. 액세스 토큰은 스스로 만료돼요. 엔드포인트는 더 이상 인식하지 못하는 토큰에도 200과
{}로 응답하므로, 두 번 이상 호출해도 안전해요.curl -X POST https://litellm.example.com/revoke \ -d token=llm_srefresh_eyJhbGciOiJ... \ -d client_id=llm_dcrc_lq411b6QkPmfxjW...
보안 규칙 (Security rules)
resource를 담은 grant는 루프백 주소(127.0.0.1, ::1, localhost)로만 리다이렉트해요. 호스팅된 https:// redirect URI는 클라이언트가 등록한 것이라도 400 invalid_request와 함께 a proxy-API grant may only redirect to a loopback address 설명으로 거부돼요. 그래서 이 플로우가 주조하는 개인 자격 증명은 사용자 자신의 머신에만 도달할 수 있어요. 인가 코드는 단일 사용이며 클라이언트와 PKCE verifier에 바인딩돼요. lite는 등록, 토큰, 해지 엔드포인트의 리다이렉트를 절대 따르지 않아요. 3xx 응답은 그곳을 가리킨 메시지와 함께 명령을 멈추므로, 코드와 verifier 또는 갱신 토큰은 발견 문서가 검사된 origin에만 도달해요. 동의 페이지는 Cache-Control: no-store와 Content-Security-Policy: frame-ancestors 'none'으로 서빙되므로 다른 페이지에 삽입될 수 없어요. 서버는 사용자를 대신해 팀을 절대 선택하지 않아요. 팀은 동의 페이지에서 오고, 멤버십은 매 토큰 교환과 갱신에서 다시 확인되며, 사용자가 아직 고를 활성 팀이 있을 때 팀 없이 게시된 grant는 400 invalid_grant와 함께 this user belongs to a team; sign in again and pick the team for this credential 설명으로 거부돼요.
디바이스 인가 grant, 임베디드 브라우저, 리소스 소유자 비밀번호 자격 증명 grant는 지원되지 않아요.