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

# Authentication

> How to authenticate requests to the FormHug API — Personal Access Tokens and OAuth 2.0 PKCE access tokens.

All authenticated FormHug API endpoints expect a bearer token in the `Authorization` header:

```http theme={null}
Authorization: Bearer <token>
```

FormHug supports two kinds of token. Both enforce the same scope system — each endpoint's reference page lists its required scope.

## Personal Access Token (PAT)

Use this for **server-to-server scripts**, internal tools, or anywhere running a full OAuth flow would be overkill. A PAT belongs to a single user and is prefixed with `fh_`:

```http theme={null}
Authorization: Bearer fh_xxxxxxxxxxxx
```

Generate a PAT at <a href="https://formhug.ai/profile/personal_access_token" target="_blank">formhug.ai/profile/personal\_access\_token</a> and assign only the scopes the integration actually needs.

<Tip>
  The interactive **Try it out** panel in this reference uses Personal Access Tokens. Paste your `fh_…` token into the Authorization box to call live endpoints from the browser.
</Tip>

<Warning>
  Treat a PAT like a password. Store it in a secret manager, never commit it to source control, and rotate it if it leaks.
</Warning>

## OAuth 2.0 access token (JWT)

Use OAuth when a **third-party application** acts on a FormHug user's behalf. FormHug implements the **Authorization Code flow with PKCE** (RFC 7636).

1. Generate a `code_verifier` and derive a `code_challenge` using the **S256** method.
2. Redirect the user to `GET /api/v1/oauth/authorize` with your `client_id`, `redirect_uri`, requested `scope`, `state`, `code_challenge`, and `code_challenge_method=S256`.
3. The user is redirected back to your `redirect_uri` with a one-time `code`.
4. Exchange the code at `POST /api/v1/oauth/token` with `grant_type=authorization_code`, the `code`, and the original `code_verifier`. You receive an `access_token` (JWT), a `refresh_token`, expirations, and the granted `scope`.
5. Call API endpoints with the JWT in the `Authorization` header.
6. When the access token expires, call `/api/v1/oauth/token` again with `grant_type=refresh_token` and your `refresh_token`.
7. Revoke a token with `POST /api/v1/oauth/revoke` (RFC 7009). This also clears the underlying session.

See the **OAuth** section in the sidebar for full endpoint details, parameters, and error responses.

<Note>
  OAuth tokens are documented here for reference. The **Try it out** flow in this UI doesn't run an OAuth handshake — use a Personal Access Token to send live requests from the playground.
</Note>

## Scopes

Every endpoint requires a specific scope. Both PATs and OAuth tokens are checked against the same scope list:

| Scope               | Grants                                               |
| ------------------- | ---------------------------------------------------- |
| `form:read`         | Read forms and folders.                              |
| `form:write`        | Create and update forms and folders.                 |
| `form:delete`       | Delete forms and folders.                            |
| `entry:read`        | Read submissions to a form.                          |
| `entry:write`       | Create or modify entries on the owner's behalf.      |
| `form:respond`      | Submit to a published form on a respondent's behalf. |
| `integration:read`  | List webhooks and other integrations.                |
| `integration:write` | Configure webhooks and other integrations.           |

A request with an insufficient scope returns `403 Forbidden`. A request with a missing or invalid token returns `401 Unauthorized`.
