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

# API authentication

> Authenticate Maadify API requests with bearer tokens or OAuth 2.0

Maadify API endpoints require a bearer token in the `Authorization` header. You can use either a Maadify user session token or an OAuth 2.0 access token issued to an approved API client.

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

OAuth access tokens use the authenticated user's tenant and permissions. The user must have API access permission, and the OAuth client must be active for the tenant.

## OAuth 2.0 flow

Use OAuth when an external application needs delegated access to the Maadify API on behalf of a user. Most server-side integrations should use confidential clients. Public clients can use PKCE when they cannot safely store a client secret.

<Steps>
  <Step title="Create an API client">
    In Maadify, open **API clients** and click **Create client**.

    Enter a client name and one or more redirect URIs.

    * Use a **confidential client** for most server-side integrations. The app exchanges the authorization code from your backend with a client secret.
    * Use a **public client with PKCE** for browser apps, mobile apps, desktop apps, CLIs, or any app that cannot keep a secret.

    <Warning>
      Store the client secret for confidential clients when it is shown. You cannot retrieve the same secret later.
    </Warning>
  </Step>

  <Step title="Create a PKCE challenge for public clients">
    Generate a cryptographically random `code_verifier`, then create a SHA-256 `code_challenge` from it.

    ```javascript theme={null}
    const crypto = globalThis.crypto;

    function base64UrlEncode(buffer) {
      return btoa(String.fromCharCode(...new Uint8Array(buffer)))
        .replace(/\+/g, "-")
        .replace(/\//g, "_")
        .replace(/=+$/, "");
    }

    const verifierBytes = crypto.getRandomValues(new Uint8Array(32));
    const codeVerifier = base64UrlEncode(verifierBytes);
    const challengeBytes = await crypto.subtle.digest(
      "SHA-256",
      new TextEncoder().encode(codeVerifier)
    );
    const codeChallenge = base64UrlEncode(challengeBytes);
    ```

    Store the `code_verifier` temporarily. You need it when you exchange the authorization code for tokens.

    Confidential clients typically skip this step and use the client secret during token exchange. They can also use PKCE if your integration requires an extra proof step.
  </Step>

  <Step title="Send the user to authorize access">
    Redirect the user to the Maadify auth URL with the OAuth authorization parameters.

    <Tabs>
      <Tab title="Public client with PKCE">
        ```http theme={null}
        GET https://data.maadify.com/auth/v1/authorize?response_type=code&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope=api.access&state={STATE}&code_challenge={CODE_CHALLENGE}&code_challenge_method=S256
        ```
      </Tab>

      <Tab title="Confidential client">
        ```http theme={null}
        GET https://data.maadify.com/auth/v1/authorize?response_type=code&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope=api.access&state={STATE}
        ```
      </Tab>
    </Tabs>

    Use `https://data.maadify.com` as the auth host.

    <ParamField query="response_type" type="string" required>
      Use `code`.
    </ParamField>

    <ParamField query="client_id" type="string" required>
      The OAuth client ID from **API clients**.
    </ParamField>

    <ParamField query="redirect_uri" type="string" required>
      One of the redirect URIs registered for the client.
    </ParamField>

    <ParamField query="scope" type="string" required>
      Use `api.access` for Maadify API access.
    </ParamField>

    <ParamField query="state" type="string">
      An opaque value your application validates after redirect to prevent CSRF.
    </ParamField>

    <ParamField query="code_challenge" type="string" required>
      Required for public PKCE clients. The base64url-encoded SHA-256 hash of your `code_verifier`.
    </ParamField>

    <ParamField query="code_challenge_method" type="string" required>
      Required for public PKCE clients. Use `S256`.
    </ParamField>
  </Step>

  <Step title="Handle user consent">
    Maadify asks the signed-in user to approve or deny API access. If the user approves, Maadify redirects back to your `redirect_uri` with an authorization code.

    ```http theme={null}
    {REDIRECT_URI}?code={AUTHORIZATION_CODE}&state={STATE}
    ```
  </Step>

  <Step title="Exchange the code for tokens">
    Exchange the authorization code at the token endpoint.

    <Tabs>
      <Tab title="Public client with PKCE">
        ```bash theme={null}
        curl -X POST "https://data.maadify.com/auth/v1/token?grant_type=authorization_code" \
          -H "Content-Type: application/x-www-form-urlencoded" \
          --data-urlencode "code={AUTHORIZATION_CODE}" \
          --data-urlencode "redirect_uri={REDIRECT_URI}" \
          --data-urlencode "client_id={CLIENT_ID}" \
          --data-urlencode "code_verifier={CODE_VERIFIER}"
        ```
      </Tab>

      <Tab title="Confidential client">
        ```bash theme={null}
        curl -X POST "https://data.maadify.com/auth/v1/token?grant_type=authorization_code" \
          -u "{CLIENT_ID}:{CLIENT_SECRET}" \
          -H "Content-Type: application/x-www-form-urlencoded" \
          --data-urlencode "code={AUTHORIZATION_CODE}" \
          --data-urlencode "redirect_uri={REDIRECT_URI}"
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Call the Maadify API">
    Send the returned `access_token` as a bearer token.

    ```bash theme={null}
    curl -X POST "https://app.maadify.com/api/parent_agents/search" \
      -H "Authorization: Bearer {ACCESS_TOKEN}" \
      -H "Content-Type: application/json" \
      -d '{"filters": [], "sort": [], "page": 1, "page_size": 10}'
    ```
  </Step>
</Steps>

## Token refresh

If the token response includes a `refresh_token`, use it to request a new access token when the current token expires.

<Tabs>
  <Tab title="Public client with PKCE">
    ```bash theme={null}
    curl -X POST "https://data.maadify.com/auth/v1/token?grant_type=refresh_token" \
      -H "Content-Type: application/json" \
      -d '{"refresh_token": "{REFRESH_TOKEN}", "client_id": "{CLIENT_ID}"}'
    ```
  </Tab>

  <Tab title="Confidential client">
    ```bash theme={null}
    curl -X POST "https://data.maadify.com/auth/v1/token?grant_type=refresh_token" \
      -u "{CLIENT_ID}:{CLIENT_SECRET}" \
      -H "Content-Type: application/json" \
      -d '{"refresh_token": "{REFRESH_TOKEN}"}'
    ```
  </Tab>
</Tabs>

## Access control

OAuth clients can only access API surfaces approved for the client and tenant. Requests can fail even with a valid token when:

* The user does not have `api.access`.
* The OAuth client is inactive or not approved for the tenant.
* The tenant does not have active billing for endpoints that require billing access.
* The user lacks the permission required by the specific endpoint.

## Troubleshooting

<AccordionGroup>
  <Accordion title="401 Invalid authentication credentials">
    Confirm that the `Authorization` header uses `Bearer {ACCESS_TOKEN}` and that the token has not expired.
  </Accordion>

  <Accordion title="403 OAuth client is not approved for this API">
    Confirm that the OAuth client is active for the user's tenant and includes the `api` API surface.
  </Accordion>

  <Accordion title="403 Missing permission">
    Ask a Maadify administrator to grant the user the permission required by the endpoint.
  </Accordion>
</AccordionGroup>
