# Space에 HF 로그인 버튼 추가

Space에서 [OAuth/OpenID connect](https://developer.okta.com/blog/2019/10/21/illustrated-guide-to-oauth-and-oidc) 앱을 자연스럽게 생성하고 연결하여 사용자가 HF 계정으로 로그인할 수 있는 내장된 로그인 플로우를 활성화할 수 있습니다.

이를 통해 Space에 새로운 사용 사례를 추가할 수 있습니다. 예를 들어, [Storage Buckets](https://huggingface.co/docs/hub/storage-buckets)와 결합하면 생성형 AI Space에서 사용자가 로그인하여 자신만 접근할 수 있는 이전 생성 결과를 조회할 수 있습니다.

> [!TIP]
> 이 가이드에서는 어떤 Space에도 *Sign-In with HF* 버튼을 통합하는 과정을 안내합니다. **Gradio** Space에서 이를 빠르고 간단하게 구현하는 방법을 찾고 있다면, 해당 [내장 통합 기능](https://www.gradio.app/guides/sharing-your-app#o-auth-login-via-hugging-face)을 확인해 보세요.

> [!TIP]
> Spaces 외부의 웹사이트나 앱에서 HF OAuth 플로우를 사용하여 "HF로 로그인" 플로우를 만들 수도 있습니다. [일반적인 OAuth 페이지를 읽어보세요](./oauth).

## OAuth 앱 만들기

`README.md` 파일의 Space 메타데이터에 `hf_oauth: true`를 추가하기만 하면 됩니다.

다음은 Gradio Space의 메타데이터 예시입니다:

```yaml
title: Gradio Oauth Test
emoji: 🏆
colorFrom: pink
colorTo: pink
sdk: gradio
sdk_version: 3.40.0
python_version: 3.10.6
app_file: app.py

hf_oauth: true
# optional, default duration is 8 hours/480 minutes. Max duration is 30 days/43200 minutes.
hf_oauth_expiration_minutes: 480
# optional, see "Scopes" below. "openid profile" is always included.
hf_oauth_scopes:
 - read-repos
 - gated-repos
 - write-repos
 - manage-repos
 - inference-api
# optional, restrict access to members of specific organizations
hf_oauth_authorized_org: ORG_NAME
hf_oauth_authorized_org:
  - ORG_NAME1
  - ORG_NAME2
```

자세한 내용은 [구성 참조 문서](./spaces-config-reference)를 확인하세요.

이렇게 하면 다음 [환경 변수](https://huggingface.co/docs/hub/spaces-overview#built-in-environment-variables)가 스페이스에 추가됩니다:

- `OAUTH_CLIENT_ID`: OAuth 앱의 클라이언트 ID(공개)
- `OAUTH_CLIENT_SECRET`: OAuth 앱의 클라이언트 시크릿
- `OAUTH_SCOPES`: OAuth 앱에서 접근할 수 있는 스코프입니다.
- `OPENID_PROVIDER_URL`: OpenID 제공자의 URL입니다. OpenID 메타데이터는 [`{OPENID_PROVIDER_URL}/.well-known/openid-configuration`](https://huggingface.co/.well-known/openid-configuration)에서 사용할 수 있습니다.

기타 환경 변수와 마찬가지로, 예를 들어 `os.getenv("OAUTH_CLIENT_ID")`를 사용하여 코드에서 사용할 수 있습니다.

## 리다이렉트 URL

Space를 대상으로 하는 한 어떤 redirect URL이든 사용할 수 있습니다.

`SPACE_HOST`은 환경 변수로 [사용할 수 있습니다](https://huggingface.co/docs/hub/spaces-overview#built-in-environment-variables).

예를 들어, 리다이렉트 URI로 `https://{SPACE_HOST}/login/callback`를 사용할 수 있습니다.

## 범위

다음 스코프는 Spaces에 항상 포함됩니다:

- `openid`: 액세스 토큰 외에 ID 토큰을 수신합니다.
- `profile`: 사용자의 프로필 정보(사용자 이름, 아바타 등)를 읽습니다

이러한 스코프는 선택 사항이며, Space의 메타데이터에서 `hf_oauth_scopes`를 설정하여 추가할 수 있습니다:

- `email`: 사용자의 이메일 주소를 읽습니다.
- `read-billing`: 사용자가 결제 수단을 설정했는지 확인합니다.
- `read-memberships`: 사용자가 속한 조직 및 각 조직에서의 역할을 읽습니다. 이 권한은 조직의 설정이나 리소스에 대한 액세스를 부여하지 않습니다.
- `read-repos`: 사용자의 개인 저장소를 읽습니다.
- `gated-repos`: 사용자가 접근 권한을 부여받은 공개 gated 리포지토리의 내용을 읽습니다. `read-repos`와 달리, 이 권한은 비공개 리포지토리에 대한 접근을 허용하지 않습니다.
- `contribute-repos`: 저장소를 생성하고 이 앱이 생성한 저장소에 액세스합니다. 추가 권한이 부여되지 않는 한 다른 저장소에 액세스할 수 없습니다.
- `write-repos`: 사용자의 개인 저장소를 읽고 씁니다.
- `manage-repos`: 사용자의 개인 저장소를 생성 및 삭제하는 것을 포함하여 완전히 관리합니다.
- `read-collections`: 사용자의 개인 컬렉션을 읽습니다.
- `write-collections`: 사용자의 개인 컬렉션을 읽고 쓰며, 이를 생성하고 삭제합니다.
- `inference-api`: 사용자를 대신하여 [Inference Providers](https://huggingface.co/docs/inference-providers/index)에 추론 요청을 보냅니다.
- `read-endpoints`: 사용자의 [Inference Endpoints](https://huggingface.co/docs/inference-endpoints/index)를 확인하고, 사용자를 대신하여 해당 엔드포인트에 추론 요청을 보냅니다.
- `write-endpoints`: 사용자의 Inference Endpoints를 관리하며, 이를 생성하고 삭제합니다. `read-endpoints` 액세스를 포함합니다.
- `jobs`: [jobs](https://huggingface.co/docs/huggingface_hub/main/en/guides/jobs) 실행
- `webhooks`: [webhooks](https://huggingface.co/docs/huggingface_hub/main/en/guides/webhooks) 관리
- `write-discussions`: 사용자를 대신하여 토론 및 Pull Request를 열고 토론에 상호작용(반응, 댓글 게시/편집, 토론 닫기 등)합니다. 비공개 저장소에서 Pull Request를 열려면 `read-repos` 스코프도 요청해야 합니다.

## 조직 리소스에 액세스

기본적으로 oauth 앱은 조직 리소스에 액세스할 필요가 없습니다.

하지만 `read-repos`나 `read-billing`와 같은 일부 스코프는 조직에도 적용됩니다.

사용자는 앱을 승인할 때 액세스 권한을 부여할 조직을 선택할 수 있습니다. 특정 조직에 대한 액세스가 필요한 경우, OAuth 승인 URL에 `orgIds=ORG_ID`를 쿼리 파라미터로 추가할 수 있습니다. `ORG_ID`는 userinfo 응답의 `organizations.sub` 필드에서 확인할 수 있는 조직 ID로 대체해야 합니다.

## Space에 버튼 추가

이제 Space에 "Sign-in with HF" 버튼을 추가하는 데 필요한 모든 정보를 갖추셨습니다. 일부 라이브러리([Python](https://github.com/lepture/authlib), [NodeJS](https://github.com/panva/node-openid-client))는 OpenID/OAuth 프로토콜 구현을 도와줍니다.

Gradio와 huggingface.js도 **내장 지원** 기능을 제공하여 Sign-in with HF 버튼 구현을 쉽게 만들어 줍니다. [gradio](https://www.gradio.app/guides/sharing-your-app#o-auth-login-via-hugging-face)와 [huggingface.js](https://huggingface.co/docs/huggingface.js/hub/README#oauth-login)의 관련 가이드를 확인해 보세요.

기본적으로 다음을 수행해야 합니다:

- `https://huggingface.co/oauth/authorize?redirect_uri={REDIRECT_URI}&scope=openid%20profile&client_id={CLIENT_ID}&state={STATE}`로 사용자를 리디렉션하세요. 여기서 `STATE`는 나중에 검증해야 하는 랜덤 문자열입니다.
- `/auth/callback` 또는 `/login/callback`(또는 사용자 정의 콜백 URL)에서 콜백을 처리하고 `state` 매개변수를 검증합니다.
- `code` 쿼리 매개변수를 사용하여 `https://huggingface.co/oauth/token`에서 액세스 토큰과 ID 토큰을 가져옵니다 (POST 요청으로 `client_id`, `code`, `grant_type=authorization_code`, `redirect_uri`를 폼 데이터로, `Authorization: Basic {base64(client_id:client_secret)}`을 헤더로 전송).

> [!WARNING]
> Space를 `iframe` 외부에서 실행하는 경우를 제외하고, 로그인 페이지를 새 탭에서 열려면 버튼에 `target=_blank`를 사용해야 합니다. 그렇지 않으면 일부 브라우저에서 쿠키 관련 문제가 발생할 수 있습니다.

## 예:

- [Gradio 테스트 앱](https://huggingface.co/spaces/Wauplin/gradio-oauth-test)
- [HuggingChat (NodeJS/SvelteKit)](https://huggingface.co/spaces/huggingchat/chat-ui)
- [Inference Widgets (Auth.js/SvelteKit)](https://huggingface.co/spaces/huggingfacejs/inference-widgets)는 `inference-api` 스코프를 사용하여 사용자를 대신하여 추론 요청을 보냅니다.
- [정적 공간에서 클라이언트 사이드(huggingface.js)](https://huggingface.co/spaces/huggingfacejs/client-side-oauth) - 매우 간단한 JavaScript 예제입니다.

JS 코드 예시:

```js
import { oauthLoginUrl, oauthHandleRedirectIfPresent } from "@huggingface/hub";

const oauthResult = await oauthHandleRedirectIfPresent();

if (!oauthResult) {
  // If the user is not logged in, redirect to the login page
  window.location.href = await oauthLoginUrl();
}

// You can use oauthResult.accessToken, oauthResult.userInfo among other things
console.log(oauthResult);
```

