PingOne Advanced Identity Cloud

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 for the receiving tenant.

  2. Create and sign a JSON Web Token (JWT) using your service account, then exchange it for an access token:

    Request
    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
    {
       "access_token": "eyJ0eXAiOiJKV1QiLCJhbGc…​",
       "token_type": "Bearer",
       "expires_in": 3599
    }
  3. Create the OAuth 2.0 client using the access token returned in step 2:

    Request
    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
    {
       "_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
    curl \
    --header "Authorization: Bearer <access-token>" \
    --header "Accept-API-Version: resource=1.0" \
    --request GET \
    "https://<receiving-tenant-env-fqdn>/openidm/config/authentication"
    Response
    {
       "_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
    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
    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
    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 for clientSecret instead of a plaintext value.
    After creating the ESV, restart Advanced Identity Cloud services so the placeholder resolves.
    Response
    {
       "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
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
{
   "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.