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

# Authentication Details

> OAuth 2.0 Authorization Code with PKCE, refresh tokens, and reconnects.

The Delegate API uses OAuth 2.0 **Authorization Code with PKCE**. Your backend ends up
holding a long-lived **refresh token** per end-user, which it exchanges for short-lived
**access tokens** to call the API. See the [Quickstart](/quickstart) for the concrete
commands. This page covers the model and steady-state behavior.

## The flow

<Steps>
  <Step title="Authorize (one-time, interactive)">
    Generate a `code_verifier` and its `code_challenge` (PKCE, S256), and keep the verifier
    for the next step. Send the user to the
    [`/authorize`](/api-reference/authentication/authorize) URL with that `code_challenge`
    and a `state` value you generate. They log in to TaxRock and consent, and
    TaxRock redirects to your registered callback with `?code=...&state=...`. Verify the returned `state` matches what you sent.
  </Step>

  <Step title="Exchange the code (backend)">
    Call [Get or refresh a token](/api-reference/authentication/token) with the `code`,
    `code_verifier`, and `client_secret` (the `authorization_code` grant) to receive an
    `access_token` and a `refresh_token`. **Store the refresh token securely, per end-user.**
  </Step>

  <Step title="Refresh (steady state)">
    When a cached access token has expired, exchange the refresh token for a fresh access
    token. See [Get or refresh a token](/api-reference/authentication/token).
  </Step>

  <Step title="Reconnect (as needed)">
    Refresh tokens eventually expire and can be revoked. When a refresh returns
    `invalid_grant`, send the user back through the authorize step to grant consent again,
    which issues a new refresh token. See [When a user must reconnect](#when-a-user-must-reconnect).
  </Step>
</Steps>

## Tokens

* **Access token.** Short-lived, about an hour. Cache and reuse it rather than minting one
  per request. Send it as a `Bearer` credential.
* **Refresh token.** Non-rotating, so keep using the same one. The refresh response returns
  no new refresh token. It expires after about **100 days idle**, with an absolute maximum
  lifetime of about **365 days**, after which the user must reconnect even if active.

## When a user must reconnect

A refresh that returns `invalid_grant`, or an API response of `401`, means that user's
connection is broken. `invalid_grant` happens when the refresh token expired: it sat
idle past \~100 days, reached its \~365-day maximum, or was revoked. Send the user back
through the authorize step and surface a **"Reconnect TaxRock"** action. This is normal
steady-state behavior, not an error to alarm the user with.

A `403` from the API is different. Its `error` field says which kind:

* **`insufficient_scope`**: the access token is missing a required scope. Re-run the
  authorize step requesting it (for the lookups, `read:client-accounts`). This is a setup
  issue, not a broken connection.
* **`forbidden`**: the connected user is not eligible or lacks permission, for example when
  the TaxRock account is not active or the user's role does not grant API access.
  Reconnecting will not fix this, so treat it as an account or configuration issue.

<Note>
  We will give advance notice if a change ever requires re-consent (for example, a new
  scope).
</Note>

## PKCE

For more on generating the `code_challenge` and `code_verifier`, see
[RFC 7636](https://datatracker.ietf.org/doc/html/rfc7636).
