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 |
Options
-
Upload Public Key Certificate: Use `POST /environments/envID/applications/appID/keys with a PEM certificate.
-
Configure JWKS URL: Update the application with
tokenEndpointAuthSigningAlgand public key details.
Steps to Configure
-
Generate an RSA or EC key pair (for example, using OpenSSL).
-
Extract the public key.
-
Upload the public key to PingOne.
-
Sign JWTs with your private key.
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
}