---
title: Remote proxy setup
description: Step-by-step guide to configure a PingIDM remote proxy between tenants, including OAuth client setup, static user mapping, and verification
component: pingoneaic
page_id: pingoneaic:idm-objects:remote-proxy-setup
canonical_url: https://docs.pingidentity.com/pingoneaic/idm-objects/remote-proxy-setup.html
llms_txt: https://docs.pingidentity.com/pingoneaic/llms.txt
docs_for_agents: https://developer.pingidentity.com/build-with-ai/docs-for-agents.md
keywords: ["Data Object Model", "Synchronization"]
section_ids:
  remote-proxy-task1-oauth-client: "Task 1: Create an OAuth 2.0 client on the receiving tenant"
  remote-proxy-task2-static-mapping: "Task 2: Add a static user mapping on the receiving tenant"
  remote-proxy-task3-source-config: "Task 3: Create an external proxy on the originating tenant"
  remote-proxy-task4-verify: "Task 4: Verify the proxy configuration"
---

# Remote proxy setup

Follow these steps to configure a remote proxy between an originating tenant and a receiving tenant. This configuration allows the originating tenant to make API calls to the receiving tenant securely.

## Task 1: Create an OAuth 2.0 client on the receiving tenant

On the receiving tenant, create an OAuth 2.0 client that the originating tenant uses to authenticate:

1. Get a [service account token](../developer-docs/authenticate-to-rest-api-with-access-token.html) for the receiving tenant.

2. [Create and sign a JSON Web Token (JWT)](../developer-docs/authenticate-to-rest-api-with-access-token.html#create-and-sign-a-jwt) using your service account, then [exchange it for an access token](../am-oauth2/token-exchange.html):

   Request

   ```none
   curl \
   --header "Authorization: Bearer <access-token>" \
   --header "Accept-API-Version: resource=1.0"  \
   --request POST "https://<receiving-tenant-env-fqdn>/am/oauth2/realms/root/realms/alpha/access_token" \
   --data 'client_id=service-account' \
   --data 'grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer' \
   --data 'assertion=<signed-jwt-token>' \
   --data 'scope=fr:am:* fr:idm:*'
   ```

   Response

   ```json
   {
      "access_token": "eyJ0eXAiOiJKV1QiLCJhbGc…​",
      "token_type": "Bearer",
      "expires_in": 3599
   }
   ```

3. Create the [OAuth 2.0 client](../app-management/standalone-oauth2-clients.html) using the access token returned in step 2:

   Request

   ```none
   curl \
   --header "Authorization: Bearer <access-token>" \
   --header 'Content-Type: application/json' \
   --header 'Accept-API-Version: resource=1.0' \
   --request PUT "https://<receiving-tenant-env-fqdn>/am/json/realms/root/realms/alpha/realm-config/agents/OAuth2Client/idmprovisioning" \
   --data '{
     "_id": "idmprovisioning",
     "coreOAuth2ClientConfig": {
       "clientType": "Confidential",
       "redirectionUris": [],
       "scopes": ["fr:idm:*"],
       "defaultScopes": ["fr:idm:*"],
       "clientName": {
         "en": "IDM Provisioning Client"
       },
       "userpassword": "<client-secret>"
     },
     "advancedOAuth2ClientConfig": {
       "tokenEndpointAuthMethod": "client_secret_post",
       "grantTypes": ["client_credentials"]
     }
   }'
   ```

   |   |                                                                                                                                                                          |
   | - | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
   |   | Consider the following:- `tokenEndpointAuthMethod`: Must be `client_secret_post`

   - `grantTypes`: Must include `client_credentials`

   - `scopes`: Must include `fr:idm:*` |

   Response

   ```json
   {
      "_id": "idmprovisioning",
      "coreOAuth2ClientConfig": {
         "clientType": "Confidential",
         "scopes": [
            "fr:idm:*"
         ]
      }
   }
   ```

## Task 2: Add a static user mapping on the receiving tenant

The OAuth 2.0 client needs permissions to access PingIDM endpoints. Configure a static user mapping:

1. Get the current authentication configuration:

   Request

   ```none
   curl \
   --header "Authorization: Bearer <access-token>" \
   --header "Accept-API-Version: resource=1.0" \
   --request GET \
   "https://<receiving-tenant-env-fqdn>/openidm/config/authentication"
   ```

   Response

   ```json
   {
      "_id": "authentication",
      "rsFilter": {
         "serverAuthContext": {
            "authModules": […​]
         },
         "staticUserMapping": []
      }
   }
   ```

2. Add the static user mapping:

   |   |                                                                             |
   | - | --------------------------------------------------------------------------- |
   |   | You must add the new mapping to the existing configuration, not replace it. |

   Request

   ```none
   curl \
   --header "Authorization: Bearer <access-token>" \
   --header "Content-type: application/json" \
   --header "Accept-API-Version: resource=1.0" \
   --request PUT "https://<receiving-tenant-env-fqdn>/openidm/config/authentication" \
   --data '{
     "_id": "authentication",
     "rsFilter": {
       "serverAuthContext": {
         "authModules": [
           …​ existing modules …​
         ]
       },
       "staticUserMapping": [
         {
           "subject": "idmprovisioning", (1)
           "localUser": "internal/user/openidm-admin",
           "roles": [
             "internal/role/openidm-authorized",
             "internal/role/openidm-admin",
             "internal/role/platform-provisioning"
           ],
           "userRoles": "authzRoles/*"
         }
       ]
     }
   }'
   ```

   |       |                                                    |
   | ----- | -------------------------------------------------- |
   | **1** | The `subject` must match your OAuth 2.0 client ID. |

## Task 3: Create an external proxy on the originating tenant

On the originating tenant, create the external proxy configuration:

1. Get a service account token for the originating tenant:

   Request

   ```none
   curl \
   --header "Authorization: Bearer <access-token>" \
   --header "Accept-API-Version: resource=1.0"  \
   --request POST "https://<originating-tenant-env-fqdn>/am/oauth2/realms/root/realms/alpha/access_token" \
   --data 'client_id=service-account' \
   --data 'grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer' \
   --data 'assertion=<signed-jwt-token>' \
   --data 'scope=fr:idm:*'
   ```

2. Create the external configuration:

   Request

   ```none
   curl \
   --header "Authorization: Bearer <access-token>" \
   --header "Content-type: application/json" \
   --header "Accept-API-Version: resource=1.0" \
   --request PUT "https://<originating-tenant-env-fqdn>/openidm/config/external.idm/<receiving-tenant-name>" \(1)
   --data '{
     "enabled": true,
     "authType": "bearer",
     "instanceUrl": "https://<receiving-tenant-env-fqdn>/openidm/", (2)
     "clientId": "idmprovisioning",
     "clientSecret": "&{esv.idmprovisioning.client.secret}", (3)
     "scope": ["fr:idm:*"],
     "tokenEndpoint": "https://<receiving-tenant-env-fqdn>/am/oauth2/realms/root/realms/alpha/access_token",
     "tokenEndpointAuthMethod": "client_secret_post",
     "scopeDelimiter": " "
   }'
   ```

   |       |                                                                                                                                                                                          |
   | ----- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
   | **1** | This configuration defines the endpoint and is accessible at runtime using `/openidm/external/idm/<receiving-tenant-name>`.                                                              |
   | **2** | The `instanceUrl` must end with a trailing slash.                                                                                                                                        |
   | **3** | Use an [ESV secret](../tenants/esvs.html) for `clientSecret` instead of a plaintext value.	After creating the ESV, restart Advanced Identity Cloud services so the placeholder resolves. |

   Response

   ```json
   {
      "enabled": true,
      "authType": "bearer",
      "instanceUrl": "https://<receiving-tenant-env-fqdn>/openidm/"
   }
   ```

## Task 4: Verify the proxy configuration

Test that the proxy works by querying users from the receiving tenant:

Request

```none
curl \
--header "Authorization: Bearer <access-token>" \
--header "Content-type: application/json" \
--header "Accept-API-Version: resource=1.0" \
--request GET "https://<originating-tenant-env-fqdn>/openidm/external/idm/<receiving-tenant-name>/managed/realm-name_user?_queryFilter=true&_pageSize=10"
```

Response

```json
{
   "result": [
      {
         "_id": "95b2b43c-621e-4bca-8a97-efc768f17751",
         "_rev": "00000000f20217df",
         "userName": "bjensen",
         "accountStatus": "active",
         "givenName": "Barbara",
         "sn": "Jensen",
         "mail": "bjensen@example.com"
      }
   ],
   "resultCount": 1,
   "pagedResultsCookie": null,
   "totalPagedResults": -1
}
```

If you get an error, review the following:

* **401 Unauthorized**: Check OAuth 2.0 client credentials.

* **403 Forbidden**: Verify the static user mapping is configured.

* **404 Not Found**: Verify the configuration name and realm name.

* **500 Server Error**: Check logs on both originating and receiving tenants.
