Skip to content

Commit 6f196f3

Browse files
Docs/oauth token exchange (#2201)
1 parent 326abbe commit 6f196f3

File tree

5 files changed

+158
-1
lines changed

5 files changed

+158
-1
lines changed

docs/hub/_toctree.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -515,4 +515,4 @@
515515
- local: api
516516
title: Hub API Endpoints
517517
- local: oauth
518-
title: Sign-In with HF (OAuth)
518+
title: OAuth / Sign in with HF

docs/hub/enterprise-tokens-management.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,7 @@ When a token is revoked or denied, the user who created the token receives an em
5353
<img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/hub/tokens-management-review.png" />
5454
<img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/hub/tokens-management-review.png" />
5555
</div>
56+
57+
## Programmatic Token Issuance
58+
59+
For organizations that need to programmatically issue access tokens for their members (e.g., for internal platforms, CI/CD pipelines, or custom integrations), see [OAuth Token Exchange](./oauth#token-exchange-for-organizations-rfc-8693). This Enterprise plan feature allows your backend services to issue scoped tokens for organization members without requiring interactive user consent.

docs/hub/enterprise.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ Team & Enterprise organization plans add advanced capabilities to organizations,
7575
| [SSO to private org](./enterprise-sso) || ✅ Basic SSO | ✅ Basic SSO | ✅ Advanced SSO |
7676
| [SSO to public Hub](./enterprise-advanced-sso) |||||
7777
| [Enforce 2FA](./enterprise-advanced-security) |||||
78+
| [OAuth Token Exchange](./oauth#token-exchange-for-organizations-rfc-8693) |||||
7879
| Disable personal public repos for users |||||
7980
| Disable joining other orgs for users |||||
8081
| Disable PRO subscription |||||
@@ -140,6 +141,7 @@ In the following sections we will document the following Team & Enterprise featu
140141
- [Advanced Compute Options](./advanced-compute-options)
141142
- [Advanced Security](./enterprise-advanced-security)
142143
- [Tokens Management](./enterprise-tokens-management)
144+
- [OAuth Token Exchange](./oauth#token-exchange-for-organizations-rfc-8693)
143145
- [Publisher Analytics](./enterprise-analytics)
144146
- [Gating Group Collections](./enterprise-gating-group-collections)
145147
- [Network Security](./enterprise-network-security)

docs/hub/oauth.md

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,150 @@ Check out [our badges](https://huggingface.co/datasets/huggingface/badges#sign-i
8989

9090
[![Sign in with Hugging Face](https://huggingface.co/datasets/huggingface/badges/resolve/main/sign-in-with-huggingface-xl.svg)](https://huggingface.co/oauth/authorize?client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&scope=openid%20profile&state=STATE)
9191
[![Sign in with Hugging Face](https://huggingface.co/datasets/huggingface/badges/resolve/main/sign-in-with-huggingface-xl-dark.svg)](https://huggingface.co/oauth/authorize?client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&scope=openid%20profile&state=STATE)
92+
93+
## Token Exchange for Organizations (RFC 8693)
94+
95+
> [!WARNING]
96+
> This feature is part of the <a href="https://huggingface.co/enterprise" target="_blank">Enterprise</a> plan.
97+
98+
Token Exchange allows organizations to programmatically issue access tokens for their members without requiring interactive user consent. This is particularly useful for building internal tools, automation pipelines, and enterprise integrations that need to access Hugging Face resources on behalf of organization members.
99+
100+
This feature implements [RFC 8693 - OAuth 2.0 Token Exchange](https://www.rfc-editor.org/rfc/rfc8693.html), a standard protocol for token exchange scenarios.
101+
102+
### Use cases
103+
104+
Token Exchange is designed for scenarios where your organization needs to:
105+
106+
- **Build internal platforms**: Create dashboards or portals that access Hugging Face resources on behalf of your team members, without requiring each user to manually authenticate.
107+
- **Automate CI/CD pipelines**: Issue short-lived, scoped tokens for automated workflows that need to push models or datasets to organization repositories.
108+
- **Integrate with enterprise identity systems**: Bridge your existing identity provider with Hugging Face by issuing tokens based on your internal user directory.
109+
- **Implement custom access controls**: Build middleware that issues tokens with specific scopes based on your organization's internal policies.
110+
111+
### How it works
112+
113+
1. Your organization has an OAuth application bound to your organization with the `token-exchange` privilege.
114+
2. Your backend service authenticates with this OAuth app using client credentials.
115+
3. Your service requests an access token for a specific organization member (identified by email).
116+
4. Hugging Face verifies the user is a member of your organization and issues a scoped token.
117+
5. The issued token can only access resources within your organization's scope.
118+
119+
### Prerequisites
120+
121+
To use Token Exchange, you need an organization-bound OAuth application with the `token-exchange` privilege. Contact Hugging Face support to set up an eligible OAuth app for your organization.
122+
123+
Once configured, you will receive:
124+
- A **Client ID** (e.g., `a1b2c3d4-e5f6-7890-abcd-ef1234567890`)
125+
- A **Client Secret** (keep this secure!)
126+
127+
> [!WARNING]
128+
> Organization administrators can manage the OAuth app after creation, including refreshing the client secret and configuring the token duration.
129+
130+
### Authentication
131+
132+
Token Exchange uses HTTP Basic Authentication with your OAuth app credentials. Create the authorization header by Base64-encoding your `client_id:client_secret`:
133+
134+
```bash
135+
# Create the authorization header
136+
export CLIENT_ID="your-client-id"
137+
export CLIENT_SECRET="your-client-secret"
138+
export AUTH_HEADER=$(echo -n "${CLIENT_ID}:${CLIENT_SECRET}" | base64)
139+
```
140+
141+
### Issuing tokens by email
142+
143+
To issue an access token for an organization member using their email address:
144+
145+
```bash
146+
curl -X POST "https://huggingface.co/oauth/token" \
147+
-H "Content-Type: application/x-www-form-urlencoded" \
148+
-H "Authorization: Basic ${AUTH_HEADER}" \
149+
-d "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \
150+
-d "subject_token=user@yourorg.com" \
151+
-d "subject_token_type=urn:huggingface:token-type:user-email"
152+
```
153+
154+
### Response
155+
156+
A successful request returns an access token:
157+
158+
```json
159+
{
160+
"access_token": "hf_oauth_...",
161+
"token_type": "bearer",
162+
"expires_in": 28800,
163+
"scope": "openid profile email read-repos",
164+
"id_token": "eyJhbGciOiJS...",
165+
"issued_token_type": "urn:ietf:params:oauth:token-type:access_token"
166+
}
167+
```
168+
169+
The `id_token` field is included when the `openid` scope is requested.
170+
171+
You can then use this token to make API requests on behalf of the user:
172+
173+
```bash
174+
curl "https://huggingface.co/api/whoami-v2" \
175+
-H "Authorization: Bearer ${ACCESS_TOKEN}"
176+
```
177+
178+
### Scope control
179+
180+
By default, issued tokens inherit all scopes configured on the OAuth app. You can request specific scopes by adding the `scope` parameter. See [Currently supported scopes](#currently-supported-scopes) for available values.
181+
182+
The token's effective permissions are limited both by the requested scope and by the user's role within the organization.
183+
184+
```bash
185+
curl -X POST "https://huggingface.co/oauth/token" \
186+
-H "Content-Type: application/x-www-form-urlencoded" \
187+
-H "Authorization: Basic ${AUTH_HEADER}" \
188+
-d "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \
189+
-d "subject_token=user@yourorg.com" \
190+
-d "subject_token_type=urn:huggingface:token-type:user-email" \
191+
-d "scope=openid profile"
192+
```
193+
194+
> [!TIP]
195+
> Follow the principle of least privilege: request only the scopes your application actually needs.
196+
197+
### Security considerations
198+
199+
Tokens issued via Token Exchange have built-in security restrictions:
200+
201+
- **Organization-scoped**: Tokens can only access resources within your organization (models, datasets, Spaces owned by the org).
202+
- **No personal access**: Tokens cannot access the user's personal private repositories or resources from other organizations.
203+
- **Short-lived**: Tokens expire after 8 hours by default. Organization administrators can configure the token duration (up to 30 days) in the OAuth app settings. No refresh tokens are provided.
204+
- **Auditable**: All token exchanges are logged and visible in your organization's [audit logs](./audit-logs).
205+
206+
> [!WARNING]
207+
> Protect your OAuth app credentials carefully. Anyone with access to your client secret can issue tokens for any member of your organization.
208+
209+
### Error responses
210+
211+
| Error | Description |
212+
|-------|-------------|
213+
| `invalid_client` | Client is not authorized to use token exchange, or the app is not bound to an organization |
214+
| `invalid_grant` | User not found in the bound organization |
215+
| `invalid_scope` | Requested scope is not valid |
216+
217+
### Reference
218+
219+
**Grant type:**
220+
```
221+
urn:ietf:params:oauth:grant-type:token-exchange
222+
```
223+
224+
**Request parameter (`subject_token_type`):**
225+
226+
| Value | Description |
227+
|-------|-------------|
228+
| `urn:huggingface:token-type:user-email` | Identify the user by their email address |
229+
230+
**Response field (`issued_token_type`):**
231+
232+
| Value | Description |
233+
|-------|-------------|
234+
| `urn:ietf:params:oauth:token-type:access_token` | Indicates an access token was issued |
235+
236+
**Related documentation:**
237+
- [RFC 8693 - OAuth 2.0 Token Exchange](https://www.rfc-editor.org/rfc/rfc8693.html)
238+
- [Audit Logs](./audit-logs)

docs/hub/security-tokens.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,7 @@ We recommend you create one access token per app or usage. For instance, you cou
7676
We also recommend using only fine-grained tokens for production usage. The impact, if leaked, will be reduced, and they can be shared among your organization without impacting your account.
7777

7878
For example, if your production application needs read access to a gated model, a member of your organization can request access to the model and then create a fine-grained token with read access to that model. This token can then be used in your production application without giving it access to all your private models.
79+
80+
### For Enterprise organizations
81+
82+
If your organization needs to programmatically issue tokens for members without requiring each user to create their own token, see [OAuth Token Exchange](./oauth#token-exchange-for-organizations-rfc-8693). This Enterprise plan feature is ideal for building internal platforms, CI/CD pipelines, or custom integrations that need to access Hugging Face resources on behalf of organization members.

0 commit comments

Comments
 (0)