PingOne Platform APIs

Update app with PRIVATE_KEY_JWT

 

PUT {{apiPath}}/environments/{{envID}}/applications/{{sharedWebAppID}}

Updates an application to use PRIVATE_KEY_JWT authentication. This is the most secure method, using asymmetric cryptography. The client signs the JWT with its private key, and PingOne verifies it with the public key. No shared secrets are transmitted.

Key points

  • JWT signed with RS256/RS384/RS512 or ES256/ES384/ES512

  • Public key registered with PingOne (JWKS or certificate)

  • No shared secret - highest security

  • Ideal for enterprise applications with PKI infrastructure

The response returns information about the application, including its id property, which identifies the ID for this application resource and the updated value for the tokenEndpointAuthMethod.

Important: For PRIVATE_KEY_JWT to work, you must upload a public key or configure a JWKS URL.

Options

  • Upload Public Key Certificate: Use `POST /environments/envID/applications/appID/keys with a PEM certificate.

  • Configure JWKS URL: Update the application with tokenEndpointAuthSigningAlg and public key details.

Steps to Configure

  1. Generate an RSA or EC key pair (for example, using OpenSSL).

  2. Extract the public key.

  3. Upload the public key to PingOne.

  4. Sign JWTs with your private key.

Headers

Authorization      Bearer {{accessToken}}

Content-Type      application/json

Body

raw ( application/json )

{
    "enabled": true,
    "name": "Shared-Web-App",
    "description": "Application using PRIVATE_KEY_JWT - a JWT signed with a private key for the highest level of security. No shared secrets - asymmetric cryptography.",
    "type": "WEB_APP",
    "protocol": "OPENID_CONNECT",
    "grantTypes": [
        "AUTHORIZATION_CODE"
    ],
    "redirectUris": [
        "http://localhost:3000/callback"
    ],
    "responseTypes": [
        "CODE"
    ],
    "tokenEndpointAuthMethod": "PRIVATE_KEY_JWT",
    "jwks": "{{jwksString}}"
}

Example Request

  • cURL

  • C#

  • Go

  • HTTP

  • Java

  • jQuery

  • NodeJS

  • Python

  • PHP

  • Ruby

  • Swift

curl --location --globoff --request PUT '{{apiPath}}/environments/{{envID}}/applications/{{sharedWebAppID}}' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{accessToken}}' \
--data '{
    "enabled": true,
    "name": "Shared-Web-App",
    "description": "Application using PRIVATE_KEY_JWT - a JWT signed with a private key for the highest level of security. No shared secrets - asymmetric cryptography.",
    "type": "WEB_APP",
    "protocol": "OPENID_CONNECT",
    "grantTypes": [
        "AUTHORIZATION_CODE"
    ],
    "redirectUris": [
        "http://localhost:3000/callback"
    ],
    "responseTypes": [
        "CODE"
    ],
    "tokenEndpointAuthMethod": "PRIVATE_KEY_JWT",
    "jwks": "{{jwksString}}"
}'
var options = new RestClientOptions("{{apiPath}}/environments/{{envID}}/applications/{{sharedWebAppID}}")
{
  MaxTimeout = -1,
};
var client = new RestClient(options);
var request = new RestRequest("", Method.Put);
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Authorization", "Bearer {{accessToken}}");
var body = @"{" + "\n" +
@"    ""enabled"": true," + "\n" +
@"    ""name"": ""Shared-Web-App""," + "\n" +
@"    ""description"": ""Application using PRIVATE_KEY_JWT - a JWT signed with a private key for the highest level of security. No shared secrets - asymmetric cryptography.""," + "\n" +
@"    ""type"": ""WEB_APP""," + "\n" +
@"    ""protocol"": ""OPENID_CONNECT""," + "\n" +
@"    ""grantTypes"": [" + "\n" +
@"        ""AUTHORIZATION_CODE""" + "\n" +
@"    ]," + "\n" +
@"    ""redirectUris"": [" + "\n" +
@"        ""http://localhost:3000/callback""" + "\n" +
@"    ]," + "\n" +
@"    ""responseTypes"": [" + "\n" +
@"        ""CODE""" + "\n" +
@"    ]," + "\n" +
@"    ""tokenEndpointAuthMethod"": ""PRIVATE_KEY_JWT""," + "\n" +
@"    ""jwks"": ""{{jwksString}}""" + "\n" +
@"}";
request.AddStringBody(body, DataFormat.Json);
RestResponse response = await client.ExecuteAsync(request);
Console.WriteLine(response.Content);
package main

import (
  "fmt"
  "strings"
  "net/http"
  "io"
)

func main() {

  url := "{{apiPath}}/environments/{{envID}}/applications/{{sharedWebAppID}}"
  method := "PUT"

  payload := strings.NewReader(`{
    "enabled": true,
    "name": "Shared-Web-App",
    "description": "Application using PRIVATE_KEY_JWT - a JWT signed with a private key for the highest level of security. No shared secrets - asymmetric cryptography.",
    "type": "WEB_APP",
    "protocol": "OPENID_CONNECT",
    "grantTypes": [
        "AUTHORIZATION_CODE"
    ],
    "redirectUris": [
        "http://localhost:3000/callback"
    ],
    "responseTypes": [
        "CODE"
    ],
    "tokenEndpointAuthMethod": "PRIVATE_KEY_JWT",
    "jwks": "{{jwksString}}"
}`)

  client := &http.Client {
  }
  req, err := http.NewRequest(method, url, payload)

  if err != nil {
    fmt.Println(err)
    return
  }
  req.Header.Add("Content-Type", "application/json")
  req.Header.Add("Authorization", "Bearer {{accessToken}}")

  res, err := client.Do(req)
  if err != nil {
    fmt.Println(err)
    return
  }
  defer res.Body.Close()

  body, err := io.ReadAll(res.Body)
  if err != nil {
    fmt.Println(err)
    return
  }
  fmt.Println(string(body))
}
PUT /environments/{{envID}}/applications/{{sharedWebAppID}} HTTP/1.1
Host: {{apiPath}}
Content-Type: application/json
Authorization: Bearer {{accessToken}}

{
    "enabled": true,
    "name": "Shared-Web-App",
    "description": "Application using PRIVATE_KEY_JWT - a JWT signed with a private key for the highest level of security. No shared secrets - asymmetric cryptography.",
    "type": "WEB_APP",
    "protocol": "OPENID_CONNECT",
    "grantTypes": [
        "AUTHORIZATION_CODE"
    ],
    "redirectUris": [
        "http://localhost:3000/callback"
    ],
    "responseTypes": [
        "CODE"
    ],
    "tokenEndpointAuthMethod": "PRIVATE_KEY_JWT",
    "jwks": "{{jwksString}}"
}
OkHttpClient client = new OkHttpClient().newBuilder()
  .build();
MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, "{\n    \"enabled\": true,\n    \"name\": \"Shared-Web-App\",\n    \"description\": \"Application using PRIVATE_KEY_JWT - a JWT signed with a private key for the highest level of security. No shared secrets - asymmetric cryptography.\",\n    \"type\": \"WEB_APP\",\n    \"protocol\": \"OPENID_CONNECT\",\n    \"grantTypes\": [\n        \"AUTHORIZATION_CODE\"\n    ],\n    \"redirectUris\": [\n        \"http://localhost:3000/callback\"\n    ],\n    \"responseTypes\": [\n        \"CODE\"\n    ],\n    \"tokenEndpointAuthMethod\": \"PRIVATE_KEY_JWT\",\n    \"jwks\": \"{{jwksString}}\"\n}");
Request request = new Request.Builder()
  .url("{{apiPath}}/environments/{{envID}}/applications/{{sharedWebAppID}}")
  .method("PUT", body)
  .addHeader("Content-Type", "application/json")
  .addHeader("Authorization", "Bearer {{accessToken}}")
  .build();
Response response = client.newCall(request).execute();
var settings = {
  "url": "{{apiPath}}/environments/{{envID}}/applications/{{sharedWebAppID}}",
  "method": "PUT",
  "timeout": 0,
  "headers": {
    "Content-Type": "application/json",
    "Authorization": "Bearer {{accessToken}}"
  },
  "data": JSON.stringify({
    "enabled": true,
    "name": "Shared-Web-App",
    "description": "Application using PRIVATE_KEY_JWT - a JWT signed with a private key for the highest level of security. No shared secrets - asymmetric cryptography.",
    "type": "WEB_APP",
    "protocol": "OPENID_CONNECT",
    "grantTypes": [
      "AUTHORIZATION_CODE"
    ],
    "redirectUris": [
      "http://localhost:3000/callback"
    ],
    "responseTypes": [
      "CODE"
    ],
    "tokenEndpointAuthMethod": "PRIVATE_KEY_JWT",
    "jwks": "{{jwksString}}"
  }),
};

$.ajax(settings).done(function (response) {
  console.log(response);
});
var request = require('request');
var options = {
  'method': 'PUT',
  'url': '{{apiPath}}/environments/{{envID}}/applications/{{sharedWebAppID}}',
  'headers': {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer {{accessToken}}'
  },
  body: JSON.stringify({
    "enabled": true,
    "name": "Shared-Web-App",
    "description": "Application using PRIVATE_KEY_JWT - a JWT signed with a private key for the highest level of security. No shared secrets - asymmetric cryptography.",
    "type": "WEB_APP",
    "protocol": "OPENID_CONNECT",
    "grantTypes": [
      "AUTHORIZATION_CODE"
    ],
    "redirectUris": [
      "http://localhost:3000/callback"
    ],
    "responseTypes": [
      "CODE"
    ],
    "tokenEndpointAuthMethod": "PRIVATE_KEY_JWT",
    "jwks": "{{jwksString}}"
  })

};
request(options, function (error, response) {
  if (error) throw new Error(error);
  console.log(response.body);
});
import requests
import json

url = "{{apiPath}}/environments/{{envID}}/applications/{{sharedWebAppID}}"

payload = json.dumps({
  "enabled": True,
  "name": "Shared-Web-App",
  "description": "Application using PRIVATE_KEY_JWT - a JWT signed with a private key for the highest level of security. No shared secrets - asymmetric cryptography.",
  "type": "WEB_APP",
  "protocol": "OPENID_CONNECT",
  "grantTypes": [
    "AUTHORIZATION_CODE"
  ],
  "redirectUris": [
    "http://localhost:3000/callback"
  ],
  "responseTypes": [
    "CODE"
  ],
  "tokenEndpointAuthMethod": "PRIVATE_KEY_JWT",
  "jwks": "{{jwksString}}"
})
headers = {
  'Content-Type': 'application/json',
  'Authorization': 'Bearer {{accessToken}}'
}

response = requests.request("PUT", url, headers=headers, data=payload)

print(response.text)
<?php
require_once 'HTTP/Request2.php';
$request = new HTTP_Request2();
$request->setUrl('{{apiPath}}/environments/{{envID}}/applications/{{sharedWebAppID}}');
$request->setMethod(HTTP_Request2::METHOD_PUT);
$request->setConfig(array(
  'follow_redirects' => TRUE
));
$request->setHeader(array(
  'Content-Type' => 'application/json',
  'Authorization' => 'Bearer {{accessToken}}'
));
$request->setBody('{\n    "enabled": true,\n    "name": "Shared-Web-App",\n    "description": "Application using PRIVATE_KEY_JWT - a JWT signed with a private key for the highest level of security. No shared secrets - asymmetric cryptography.",\n    "type": "WEB_APP",\n    "protocol": "OPENID_CONNECT",\n    "grantTypes": [\n        "AUTHORIZATION_CODE"\n    ],\n    "redirectUris": [\n        "http://localhost:3000/callback"\n    ],\n    "responseTypes": [\n        "CODE"\n    ],\n    "tokenEndpointAuthMethod": "PRIVATE_KEY_JWT",\n    "jwks": "{{jwksString}}"\n}');
try {
  $response = $request->send();
  if ($response->getStatus() == 200) {
    echo $response->getBody();
  }
  else {
    echo 'Unexpected HTTP status: ' . $response->getStatus() . ' ' .
    $response->getReasonPhrase();
  }
}
catch(HTTP_Request2_Exception $e) {
  echo 'Error: ' . $e->getMessage();
}
require "uri"
require "json"
require "net/http"

url = URI("{{apiPath}}/environments/{{envID}}/applications/{{sharedWebAppID}}")

http = Net::HTTP.new(url.host, url.port);
request = Net::HTTP::Put.new(url)
request["Content-Type"] = "application/json"
request["Authorization"] = "Bearer {{accessToken}}"
request.body = JSON.dump({
  "enabled": true,
  "name": "Shared-Web-App",
  "description": "Application using PRIVATE_KEY_JWT - a JWT signed with a private key for the highest level of security. No shared secrets - asymmetric cryptography.",
  "type": "WEB_APP",
  "protocol": "OPENID_CONNECT",
  "grantTypes": [
    "AUTHORIZATION_CODE"
  ],
  "redirectUris": [
    "http://localhost:3000/callback"
  ],
  "responseTypes": [
    "CODE"
  ],
  "tokenEndpointAuthMethod": "PRIVATE_KEY_JWT",
  "jwks": "{{jwksString}}"
})

response = http.request(request)
puts response.read_body
let parameters = "{\n    \"enabled\": true,\n    \"name\": \"Shared-Web-App\",\n    \"description\": \"Application using PRIVATE_KEY_JWT - a JWT signed with a private key for the highest level of security. No shared secrets - asymmetric cryptography.\",\n    \"type\": \"WEB_APP\",\n    \"protocol\": \"OPENID_CONNECT\",\n    \"grantTypes\": [\n        \"AUTHORIZATION_CODE\"\n    ],\n    \"redirectUris\": [\n        \"http://localhost:3000/callback\"\n    ],\n    \"responseTypes\": [\n        \"CODE\"\n    ],\n    \"tokenEndpointAuthMethod\": \"PRIVATE_KEY_JWT\",\n    \"jwks\": \"{{jwksString}}\"\n}"
let postData = parameters.data(using: .utf8)

var request = URLRequest(url: URL(string: "{{apiPath}}/environments/{{envID}}/applications/{{sharedWebAppID}}")!,timeoutInterval: Double.infinity)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("Bearer {{accessToken}}", forHTTPHeaderField: "Authorization")

request.httpMethod = "PUT"
request.httpBody = postData

let task = URLSession.shared.dataTask(with: request) { data, response, error in
  guard let data = data else {
    print(String(describing: error))
    return
  }
  print(String(data: data, encoding: .utf8)!)
}

task.resume()

Example Response

200 OK

{
    "_links": {
        "self": {
            "href": "https://api.pingone.com/v1/environments/abfba8f6-49eb-49f5-a5d9-80ad5c98f9f6/applications/7029adfa-164d-4234-a3ca-3e4900ef94a6"
        },
        "environment": {
            "href": "https://api.pingone.com/v1/environments/abfba8f6-49eb-49f5-a5d9-80ad5c98f9f6"
        },
        "metadata": {
            "href": "https://api.pingone.com/v1/environments/abfba8f6-49eb-49f5-a5d9-80ad5c98f9f6/applications/7029adfa-164d-4234-a3ca-3e4900ef94a6/metadata"
        },
        "attributes": {
            "href": "https://api.pingone.com/v1/environments/abfba8f6-49eb-49f5-a5d9-80ad5c98f9f6/applications/7029adfa-164d-4234-a3ca-3e4900ef94a6/attributes"
        },
        "secret": {
            "href": "https://api.pingone.com/v1/environments/abfba8f6-49eb-49f5-a5d9-80ad5c98f9f6/applications/7029adfa-164d-4234-a3ca-3e4900ef94a6/secret"
        },
        "grants": {
            "href": "https://api.pingone.com/v1/environments/abfba8f6-49eb-49f5-a5d9-80ad5c98f9f6/applications/7029adfa-164d-4234-a3ca-3e4900ef94a6/grants"
        }
    },
    "environment": {
        "id": "abfba8f6-49eb-49f5-a5d9-80ad5c98f9f6"
    },
    "id": "7029adfa-164d-4234-a3ca-3e4900ef94a6",
    "name": "Shared-Web-App",
    "description": "Application using PRIVATE_KEY_JWT - a JWT signed with a private key for the highest level of security. No shared secrets - asymmetric cryptography.",
    "enabled": true,
    "type": "WEB_APP",
    "protocol": "OPENID_CONNECT",
    "createdAt": "2026-04-08T15:39:17.367Z",
    "updatedAt": "2026-04-20T16:29:03.919Z",
    "clientId": "7029adfa-164d-4234-a3ca-3e4900ef94a6",
    "assignActorRoles": false,
    "responseTypes": [
        "CODE"
    ],
    "grantTypes": [
        "AUTHORIZATION_CODE"
    ],
    "jwks": "{ \"keys\": [ { \"kty\": \"RSA\", \"e\": \"AQAB\", \"use\": \"sig\", \"kid\": \"q3sWApYjHZQLmWMUdAIqZiVWSshDdau5eI4K_Bm65Us\", \"alg\": \"RS256\", \"n\": \"jWA_vDxg41NrYJdIiv3BcljMy7V15bMyOyK5aJov6F\" } ]}",
    "tokenEndpointAuthMethod": "PRIVATE_KEY_JWT",
    "pkceEnforcement": "OPTIONAL",
    "requestScopesForMultipleResourcesEnabled": false,
    "parRequirement": "OPTIONAL",
    "devicePollingInterval": 5,
    "redirectUris": [
        "http://localhost:3000/callback"
    ],
    "parTimeout": 60,
    "deviceTimeout": 600
}