# Client-Credential-Flow with external IDP

This page explains how to connect an external Identity Provider (IDP) using the OAuth 2.0 client-credential flow. fulfillmenttools creates an internal OpenID Connect (OIDC) service user based on the `appid` in the access token. This service user is not listed in user endpoints or Backoffice, which lists human users. OIDC service users can be assigned any roles available to human users.

## Overview

* **Flow**: `OAuth 2.0 client-credential` (`grant_type=client_credentials`)
* **Token requirements**:
  * The token must be a JSON Web Token (JWT) signed with RS256 by the IDP.
  * The token must include the `iss`, `aud`, `exp`, and `appid` claims.
  * The `appid` uniquely identifies the service user in fulfillmenttools.
* **Visibility**: Service users are not visible in regular user listings.
* **Roles**:
  * Platform roles are assigned to service users by their external identifier (`appid`).
  * Service users support any role defined in fulfillmenttools. The login fails if a specified role doesn't exist.

## Rate limits

* **Default**: 2000 logins per minute per tenant.
* Exceeding the limit returns a `429` status code or a similar throttle response.
* The limit can be increased upon request via support.

## Recommendations

* It's recommended to reuse access tokens until they expire, based on the `exp` claim, to avoid unnecessary logins.
* A single token should be used across concurrent requests where appropriate.
* Implement exponential backoff and jitter on retries.

## Security and lifecycle

* **Token lifetime**: The default lifetime in Entra ID is approximately one hour. Avoid shortening this to prevent frequent logins.
* **Key rollover**: Microsoft rotates signing keys; the platform uses a JSON Web Key Set (JWKS) to follow these rotations automatically.
* **Secret hygiene**: It is recommended to use certificates over client secrets and rotate them regularly.
* **Least privilege**: Use a dedicated client and app role only for the fulfillmenttools integration.

## Support

To configure the audience and issuer, assign roles, or request a rate-limit increase, contact fulfillmenttools support. The request must include the `tenantId`, `issuer`, `audience`, and the client `appid`.

## How to guide

{% hint style="success" %}

## Prerequisites

* A fully configured external IDP. For an example, see [Configure Microsoft Entra ID](https://github.com/fulfillmenttools/documentation-developer/blob/master/connecting-to-fulfillmenttools/openid-connect/configure-microsoft-entra-id-azure-active-directory.md).
* An OAuth application is configured within the IDP with a `client_id` and `client_secret` that's capable of the client-credential flow.
  {% endhint %}

{% stepper %}
{% step %}
**Get an ID token from the IDP with cURL**

```shell
# Variables
TENANT_ID="{your-tenant-id}"
CLIENT_ID="{your-client-app-id}"            # 'fulfillmenttools-client'
CLIENT_SECRET="{your-client-secret}"
SCOPE="api://{api-app-id-or-uri}/.default"  # from 'fulfillmenttools-api'

# Request a token (OAuth 2.0 v2 endpoint)
curl -sS -X POST "https://login.microsoftonline.com/${TENANT_ID}/oauth2/v2.0/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "client_id=${CLIENT_ID}" \
  -d "client_secret=${CLIENT_SECRET}" \
  -d "grant_type=client_credentials" \
  -d "scope=${SCOPE}"
```

{% endstep %}

{% step %}
**Get an identity platform token**

You'll need to replace `{your-api-key}` with your API key for fulfillmenttools. You'll also need to replace the `{insert-id-token}` and `{insert-oidc-provider-id}` with the relevant information.

<pre class="language-shell"><code class="lang-shell"><strong>curl -X POST "https://identitytoolkit.googleapis.com/v1/accounts:signInWithIdp?key={your-api-key}" \
</strong>  -H "Content-Type: application/json" \
  -d '{
    "requestUri": "http://localhost",
<strong>    "postBody": "id_token={insert-id-token}&#x26;providerId=oidc.external.{insert-oidc-provider-id}",
</strong>    "returnRefreshToken": true,
    "sessionId": null,
    "idToken": null,
    "returnSecureToken": true,
    "returnIdpCredential": null,
    "tenantId": null,
    "pendingToken": null
  }'
</code></pre>

{% endstep %}

{% step %}
**Use the identity platform token to call fulfillmenttools APIs**

Replace `{access-token}` with the token response you received in step 2, and replace `{projectId}` with your tenant name.

```shell
ACCESS_TOKEN="{access-token}"
FFT_BASE_URL="https://{projectId}.api.fulfillmenttools.com/api/"

curl -sS -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -H "Content-Type: application/json" \
  "${FFT_BASE_URL}/users"
```

{% endstep %}
{% endstepper %}
