> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hud.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Sign in with HUD

> Let your product's users sign in with their HUD account and call the HUD API on their behalf, as members of your enterprise team.

**Sign in with HUD** lets the users of your product connect their HUD account over OAuth. Your
product then calls the [REST API](https://docs.hud.ai/platform/rest-api.md) on each user's behalf with their own access
token, so you never handle their API keys and each user's access can be revoked on its own.

Every user acts as a member of your team. Their work belongs to your team, and its billing,
[spend limits](https://docs.hud.ai/platform/billing.md), [roles](https://docs.hud.ai/platform/team.md#roles), and admin controls apply exactly
as they do for API keys.

> [!NOTE]
>
> Sign in with HUD is available on the Enterprise plan. HUD registers your application; to set one
> up, [contact HUD](mailto:founders@hud.ai).

## Set up your application

Tell HUD which team the application belongs to, its name, and its redirect URIs. HUD registers it
and sends you its **client ID** and **client secret**. Keep the secret on your server. Each
application belongs to exactly one team; a team can have several.

Your users see the application's name on HUD's consent screen and choose whether to allow it.

## Scopes

Request the scopes your product needs. The user sees them on the consent screen.

| Scope | Grants |
| - | - |
| `hud:api` | The HUD API endpoints for building tasks and running evaluations, and joining your team. Required to call the API. |
| `hud:team` | Team changes: invitations, member roles, and removals. The user must also be a team admin. |
| `profile`, `email` | The user's name and email, from the userinfo endpoint. |
| `offline_access` | A refresh token, so your product can keep access without asking the user to sign in again. |

## Sign a user in

HUD uses the OAuth 2.0 authorization code flow with PKCE (`S256`) at `https://clerk.hud.ai`.

**1. Send the user to HUD**

Redirect the user to the authorization endpoint. They sign in to HUD and approve the scopes.

```text theme={"dark"}
https://clerk.hud.ai/oauth/authorize
  ?response_type=code
  &client_id=<client_id>
  &redirect_uri=<redirect_uri>
  &scope=hud:api profile email offline_access
  &state=<state>
  &code_challenge=<code_challenge>
  &code_challenge_method=S256
```

HUD redirects back to your `redirect_uri` with `code` and your `state`.

**2. Exchange the code for tokens**

From your server, exchange the code for an access token (it starts with `oat_`) and, with
`offline_access`, a refresh token.

```bash theme={"dark"}
curl https://clerk.hud.ai/oauth/token \
  -u "<client_id>:<client_secret>" \
  -d grant_type=authorization_code \
  -d code=<code> \
  -d redirect_uri=<redirect_uri> \
  -d code_verifier=<code_verifier>
```

**3. Add the user to your team**

A user who is not yet a member of your team must join it once. Joining is idempotent, so you can
call it after every sign-in.

```bash theme={"dark"}
curl -X POST https://api.beta.hud.ai/v2/oauth/join \
  -H "Authorization: Bearer $OAUTH_ACCESS_TOKEN"
```

The response is the user's membership: `membership_id`, `team_id`, and `role`. New users join
with the **External** role; current members keep their role.

**4. Call the API**

Send the access token as the bearer token, exactly like an API key.

```bash theme={"dark"}
curl https://api.beta.hud.ai/v2/tasksets \
  -H "Authorization: Bearer $OAUTH_ACCESS_TOKEN"
```

To identify the user in your product, call the userinfo endpoint with the access token. `sub` is the
user's stable HUD ID; link accounts on it rather than on email. `name` and `email` need the `profile`
and `email` scopes.

```bash theme={"dark"}
curl https://clerk.hud.ai/oauth/userinfo \
  -H "Authorization: Bearer $OAUTH_ACCESS_TOKEN"
```

## Keep and end access

Access tokens expire after the `expires_in` seconds in the token response. Refresh them from your
server. Each refresh returns a new access token and a new refresh token, and the previous access
token stops working, so store both.

```bash theme={"dark"}
curl https://clerk.hud.ai/oauth/token \
  -u "<client_id>:<client_secret>" \
  -d grant_type=refresh_token \
  -d refresh_token=<refresh_token>
```

To sign a user out, revoke their token. HUD stops accepting a revoked token within a minute.

```bash theme={"dark"}
curl https://clerk.hud.ai/oauth/token/revoke \
  -u "<client_id>:<client_secret>" \
  -d token=<token>
```

## What users can do

A token acts as the user's membership in your team. It has that member's access, no more, and
shares the [rate limit](https://docs.hud.ai/platform/limits.md#api-rate-limits) of their API keys.

With `hud:api`, tokens reach environments, tasksets and tasks, imports, data files, jobs, rollouts,
traces and trace storage, models, builds, checks, QA agents and QA checks, limits, usage, and the
team member list. Secrets, provider keys, completions, and instances refuse OAuth tokens, as does
everything outside the public API. The [REST API reference](https://docs.hud.ai/platform/rest-api.md#sign-in-with-hud)
lists the endpoints by group.

New users join as **External** members, who see only their own work and what is shared with them.
To give a user access to the team's shared environments, tasksets, and jobs, a team admin changes
their role to **Member** in **Settings** → **Members**, or through the
[REST API](https://docs.hud.ai/platform/rest-api.md#team) with a `hud:team` token.

## Manage users

Users who joined through your application are listed in **Settings** → **Members** with everyone
else, and admins manage them the same way. Removing a user ends their access: their tokens are
refused with `membership_unavailable`, and they can't rejoin through your application until an admin
invites them again.

Unregistering the application stops all of its tokens within a minute. Its users stay members of
the team.

## Errors

| Status | Error | What to do |
| - | - | - |
| `401` | `principal_not_found` | The user is not a member of your team yet. Call `POST /v2/oauth/join`, then retry. |
| `401` | `unauthorized` | The token is invalid, expired, or revoked. Refresh it, or sign the user in again. |
| `403` | `insufficient_scope` | The token was not granted the scope the endpoint requires. Sign the user in again with that scope. |
| `403` | `forbidden` | The endpoint does not accept OAuth tokens, or the user's role does not allow the action. |
| `403` | `membership_unavailable` | The user was removed from your team, or their account or the team is banned or deleted. |
| `429` | `rate_limited` | Rate limited, or your server sent too many invalid tokens in the last minute. Retry after the `Retry-After` delay. |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.