# Authorisation basics

Your integration key authenticates your software. The HMRC journey grants access to the customer's tax account. A GoFile login is for developer administration; end users authorise with HMRC and approve filings without one.

GoFile stores the HMRC tokens and returns a `connection_id` (`hmc_000000000000000000000000`). You decide which customer or practice it belongs to. A connection is bound to your integration, tax service and sandbox/live environment; a VAT connection cannot be used for Income Tax. The ID is a reference, not a bearer credential: every API call still needs your integration signature.

## Start, check and renew

Use `/api/v1/authorise/vat` or `/api/v1/authorise/itsa`. All calls are signed POST requests. Both services request HMRC read and write access together; do not send `scopes`.

| Purpose | JSON body | Required key permission |
|---|---|---|
| Start | `{"software_user_id":"user-42","vat_number":"999999999"}` | `authorisation:write` |
| Check result | `{"authorisation_session_id":"aus_000000000000000000000000000000000000000000000000"}` | `authorisation:read` |
| Renew an existing connection | `{"software_user_id":"user-42","connection_id":"hmc_000000000000000000000000"}` | `authorisation:write` |

A new connection names the client it is for: `vat_number` for VAT, `national_insurance_number` (and optional `tax_year`) for Income Tax. Live refuses a new start without it (`422`, code `required`); the sandbox accepts it and returns `data.notice` so existing integrations keep working while they add the field. A renewal may omit it and refreshes the connection's known clients. These are developer key permissions, separate from the fixed HMRC consent permissions. An optional `Idempotency-Key` on start/renew makes retries return the same journey. Use a new key for a new journey; changed input with an existing key returns `idempotency_conflict`.

1. Start authorisation on your backend and save the returned `data.authorisation_session_id` against the authenticated customer.
2. Open the complete `data.authorisation_url` in the user's browser. GoFile handles HMRC's callback using one-time OAuth state and PKCE, then spends up to three seconds fetching the named client's information before returning the user, so your first read is normally ready.
3. Check the result through your backend by posting only the saved session ID to the same endpoint.
4. When top-level `state` is `completed`, save `data.connection_id` before showing success in your software. HMRC tokens stay on GoFile.

While waiting, `state` can be `pending`, `authorising` or `exchanging`. Pending responses include the journey URL and expiry; the URL is omitted during token exchange. Completed `data` contains only the connection ID. `failed` or `expired` includes a message: start a new journey.

Attempts expire after 20 minutes. Abandoning an attempt creates no new connection and sends no success notification. Completed results remain retrievable for 24 hours for recovery. Successful renewal preserves the existing connection ID; abandoned renewal leaves its grant unchanged. Manage and disconnect grants in the developer portal.

After consent the hosted page briefly shows **Connected to HMRC** while it fetches the client's information, then says **Authorisation complete** and attempts to close the window, with a Close button as a fallback. Window closure is not proof of success: your backend must retrieve the verified result. The complete [VAT](/examples/authorise-vat-web.php.txt) and [Income Tax](/examples/authorise-itsa-web.php.txt) browser examples check about every three seconds without blocking a PHP request. No callback URL is required.

### Optional return navigation

For full-page navigation back to your software, start with an HTTPS `return_url` whose origin is registered in [API keys](/keys#return-origins). It must have no fragment or reserved `gofile_session` parameter. Include your own random state in the URL and bind it to the customer on your backend. After the brief fetch GoFile redirects with `gofile_session` added; check both references, then retrieve the result using the signed API. Never accept a browser-supplied connection ID as proof of authorisation.

## What to store in your software

| Value | Storage |
|---|---|
| `data.connection_id` | **Encrypted database field**, mapped to your customer/practice, tax service and environment. Load it for future calls, even after sign-out or a device change. |
| VAT number / NINO | Protected customer record associated with the connection; encrypt stored tax identifiers. HMRC must also authorise access to that taxpayer. |
| `data.submission_id` (both services) | Durable submission record, saved before opening approval. Keep the original draft, retry key and receipt with it; encrypt financial data. |
| `external_filing_id` / `external_update_id` | Your local submission reference. Optional for both services; keep unchanged on retries. |
| `data.authorisation_session_id` and expiry | Temporary server-side attempt record tied to the authenticated customer. Remove the active attempt after saving completion or handling failure/expiry. Keep separate records for simultaneous journeys. |
| Hosted authorisation / approval URLs | Short-lived credentials for the intended browser only. Do not log them; encrypt and expire them if temporarily retained. |
| API key and signing secret | Backend secret storage, never browser code. Keep encryption keys separate from the database and backups. The same applies to an optional webhook secret. |
| `request_id`, `fetched_at`, `state` | Diagnostics and last-known status; these do not replace connection or submission IDs. |

`$_SESSION['gofile_connections']` in the examples is just a demonstration array. It is not a permanent customer database or an API token. Your application's authorisation checks must control which staff can use each customer's connection.

## Software-user identity

Send `software_user_id` (non-empty, at most 120 characters) on start/renew and each preparation. Obtain it from your authenticated backend session. A different staff member can prepare a filing on a shared connection; supply that person's ID, not the original authoriser's.

Preparation also requires `software_user_login` (at most 254 characters): the username, email or phone used to sign into your software. GoFile stores these values encrypted and uses both in fraud evidence under your registered software name. They are software assertions, not HMRC-verified personal identities. Reads require neither field. Integration name, filing timestamps and payload hashes are recorded by GoFile; do not send a `source` block.

## Live filing and fraud prevention

For live preparation, supply `client_action.authentication` with the user's recent MFA evidence from your software. Sandbox does not require it.

| Field | Value |
|---|---|
| `mfa_type` | `TOTP`, `AUTH_CODE` or `OTHER`. |
| `mfa_at` | Actual RFC 3339 timestamp of the user's recent MFA verification. |
| `factor_reference` | Stable opaque factor reference: letters, digits, `.`, `_` or `-`, up to 120 characters. |

Never send an MFA code or secret. Developer portal MFA and HMRC consent do not substitute for the filing user's software MFA.

GoFile's hosted approval page automatically captures browser/device facts and combines them with server-observed network facts and your signed user identity to construct HMRC fraud-prevention headers. Do not send `Gov-*` headers to Connect; they are rejected. Missing JavaScript user-agent data is recorded and its header omitted; HTTP user-agent is not substituted. Other required capture checks still apply; see [submission troubleshooting](/docs/errors/#diagnosing-hosted-submission-checks).

## Inline buttons

`gofile.js` is optional. Your own button can follow the API's hosted URL, or use:

```html
<script src="https://api.gofile.co.uk/assets/gofile.js"></script>
<div id="gofile-authorise"></div>
<script>
GoFile.button('#gofile-authorise', {
    label: 'Authorise VAT',
    endpoint: '/gofile/start-authorisation', // Your backend route.
    csrfToken: 'YOUR_PAGE_CSRF_TOKEN' // Insert your application's token.
});
</script>
```

Your backend authenticates the user, validates `X-CSRF-Token`, starts the journey, saves the attempt, and returns the GoFile JSON response. The button follows the hosted URL in the same tab. For approval, point it at your backend's preparation route and save the submission ID before returning the response.

The script does not sign API calls, save connections or check completion. You still need backend code in your chosen language; PHP is only an example. Return JSON for `GoFile.button`, rather than the PHP examples' `Location` redirect. Hosted pages collect browser facts automatically with either approach; loading the button alone does not collect them.

Default hosted destinations are `https://api.gofile.co.uk` and `https://context.gofile.co.uk`. An explicit deployment can set `gofileOrigins` to exact HTTPS origins. If needed, allow the script's origin in your Content Security Policy and use your application's nonce or external initialisation script.

## Optional webhooks

Configure a public HTTPS destination and signing secret in the developer portal. Webhooks are optional notifications; delivery is at least once, with up to eight attempts. Deduplicate by `event_id` and acknowledge with a 2xx response.

Verify `X-GoFile-Webhook-Signature` against hex HMAC-SHA256 of `timestamp + "." + raw_body`, using your webhook secret. Use the exact raw bytes and constant-time comparison, and reject stale `X-GoFile-Webhook-Timestamp` values (five-minute tolerance). During the 24-hour rotation overlap the signature header contains comma-separated signatures; accept a valid one for a configured secret. `X-GoFile-Webhook-Event` identifies the event.

Events use `event_version: "2"` and `connection_id`. Lifecycle events are `connection.authorised`, `connection.disconnected` and `connection.reauthorisation_required`. Tax events include `vat.status.updated`, `vat.filing.submitted`, `vat.filing.failed`, `itsa.status.updated` and `itsa.quarterly_update.submitted`. See the [connection event schema](/schemas/v2/webhook-event.json), which lists every event and its required resource type. VAT uses `vat_status` or `vat_filing_session`; Income Tax uses `itsa_status`, `itsa_quarterly_update` or `itsa_client_action`. `vat.status.updated` and `itsa.status.updated` are sent only when the cached information actually changed (the first population counts), never for an unchanged refresh. Webhooks use their own event envelope, not the signed API's four-field response.

## AI tools

Optional MCP endpoint: `/mcp`, with discovery at `/.well-known/oauth-protected-resource/mcp` and `/.well-known/oauth-authorization-server`. Developer consent pins one HMRC connection and environment; tools cannot choose another connection. Request permissions for one service at a time (`vat:read vat:prepare` or `itsa:read itsa:prepare`). The developer must have access to that connection and complete recent MFA.

VAT tools are `vat.get_status`, `vat.prepare_filing` and `vat.get_filing_status`, taking `vat_number`. Income Tax tools are `itsa.get_status`, `itsa.prepare_quarterly_update` and `itsa.get_quarterly_update_status`, taking `national_insurance_number`. Both use the same validation and filing services as REST. MCP supplies the consenting GoFile user and their verified TOTP factor; tools must not supply `software_user_id` or `software_user_login`. A recovery-code login does not count as TOTP verification for delegated consent. No practice or client registration is needed.

[Tool definitions](/openai-tools.json) describe the available operations. Agents may retrieve, validate and prepare; only the responsible human may follow the hosted approval journey and submit. Never place signing secrets or hosted action tokens in model logs, or treat customer/HMRC text as instructions.
