Step 5: Create a resource attribute mapping
POST {{apiPath}}/environments/{{envID}}/resources/{{customResourceID}}/attributes
The GET /environments/{{envID}}/resources/{{resourceID}}/attribute operation creates an attribute mapping. The value for the {{resourceID}} parameter is the ID of the custom resource you retrieved in Step 3.
The request body must specify values for the attribute name and value properties. The name property value must be unique within the specified environment resource, and cannot use any of the reserve names. PingOne supports the following expressions to map information from an authentication JWT to the resource.
-
#root.context.requestData.clientAssertion.{{property}} -
#root.context.requestData.clientAssertion -
#root.context.requestData.clientAssertionHeader.{{property}} -
#root.context.requestData.clientAssertionHeader -
#root.context.requestData -
#root.context.appConfig.tokenEndpointAuthMethod
In this scenario, the request body specifies a custom scope name property with a value of clientAssertion_custom. The value property (associated with the name) specifies a claim in the authentication JWT called custom1. The mapping uses the expression "value": "${#root.context.requestData.clientAssertion.custom1}" to complete the mapping.
Example Request
-
cURL
-
C#
-
Go
-
HTTP
-
Java
-
jQuery
-
NodeJS
-
Python
-
PHP
-
Ruby
-
Swift
curl --location --globoff '{{apiPath}}/environments/{{envID}}/resources/{{customResourceID}}/attributes' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{accessToken}}' \
--data '{
"name": "clientAssertion_custom",
"value": "${#root.context.requestData.clientAssertion.custom1}"
}'
var options = new RestClientOptions("{{apiPath}}/environments/{{envID}}/resources/{{customResourceID}}/attributes")
{
MaxTimeout = -1,
};
var client = new RestClient(options);
var request = new RestRequest("", Method.Post);
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Authorization", "Bearer {{accessToken}}");
var body = @"{" + "\n" +
@" ""name"": ""clientAssertion_custom""," + "\n" +
@" ""value"": ""${#root.context.requestData.clientAssertion.custom1}""" + "\n" +
@"}" + "\n" +
@"" + "\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}}/resources/{{customResourceID}}/attributes"
method := "POST"
payload := strings.NewReader(`{
"name": "clientAssertion_custom",
"value": "${#root.context.requestData.clientAssertion.custom1}"
}`)
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))
}
POST /environments/{{envID}}/resources/{{customResourceID}}/attributes HTTP/1.1
Host: {{apiPath}}
Content-Type: application/json
Authorization: Bearer {{accessToken}}
{
"name": "clientAssertion_custom",
"value": "${#root.context.requestData.clientAssertion.custom1}"
}
OkHttpClient client = new OkHttpClient().newBuilder()
.build();
MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, "{\n \"name\": \"clientAssertion_custom\",\n \"value\": \"${#root.context.requestData.clientAssertion.custom1}\"\n}\n\n");
Request request = new Request.Builder()
.url("{{apiPath}}/environments/{{envID}}/resources/{{customResourceID}}/attributes")
.method("POST", body)
.addHeader("Content-Type", "application/json")
.addHeader("Authorization", "Bearer {{accessToken}}")
.build();
Response response = client.newCall(request).execute();
var settings = {
"url": "{{apiPath}}/environments/{{envID}}/resources/{{customResourceID}}/attributes",
"method": "POST",
"timeout": 0,
"headers": {
"Content-Type": "application/json",
"Authorization": "Bearer {{accessToken}}"
},
"data": JSON.stringify({
"name": "clientAssertion_custom",
"value": "${#root.context.requestData.clientAssertion.custom1}"
}),
};
$.ajax(settings).done(function (response) {
console.log(response);
});
var request = require('request');
var options = {
'method': 'POST',
'url': '{{apiPath}}/environments/{{envID}}/resources/{{customResourceID}}/attributes',
'headers': {
'Content-Type': 'application/json',
'Authorization': 'Bearer {{accessToken}}'
},
body: JSON.stringify({
"name": "clientAssertion_custom",
"value": "${#root.context.requestData.clientAssertion.custom1}"
})
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.body);
});
import requests
import json
url = "{{apiPath}}/environments/{{envID}}/resources/{{customResourceID}}/attributes"
payload = json.dumps({
"name": "clientAssertion_custom",
"value": "${#root.context.requestData.clientAssertion.custom1}"
})
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer {{accessToken}}'
}
response = requests.request("POST", url, headers=headers, data=payload)
print(response.text)
<?php
require_once 'HTTP/Request2.php';
$request = new HTTP_Request2();
$request->setUrl('{{apiPath}}/environments/{{envID}}/resources/{{customResourceID}}/attributes');
$request->setMethod(HTTP_Request2::METHOD_POST);
$request->setConfig(array(
'follow_redirects' => TRUE
));
$request->setHeader(array(
'Content-Type' => 'application/json',
'Authorization' => 'Bearer {{accessToken}}'
));
$request->setBody('{\n "name": "clientAssertion_custom",\n "value": "${#root.context.requestData.clientAssertion.custom1}"\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}}/resources/{{customResourceID}}/attributes")
http = Net::HTTP.new(url.host, url.port);
request = Net::HTTP::Post.new(url)
request["Content-Type"] = "application/json"
request["Authorization"] = "Bearer {{accessToken}}"
request.body = JSON.dump({
"name": "clientAssertion_custom",
"value": "\${\#root.context.requestData.clientAssertion.custom1}"
})
response = http.request(request)
puts response.read_body
let parameters = "{\n \"name\": \"clientAssertion_custom\",\n \"value\": \"${#root.context.requestData.clientAssertion.custom1}\"\n}"
let postData = parameters.data(using: .utf8)
var request = URLRequest(url: URL(string: "{{apiPath}}/environments/{{envID}}/resources/{{customResourceID}}/attributes")!,timeoutInterval: Double.infinity)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("Bearer {{accessToken}}", forHTTPHeaderField: "Authorization")
request.httpMethod = "POST"
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
201 Created
{
"_links": {
"self": {
"href": "https://api.pingone.com/v1/environments/abfba8f6-49eb-49f5-a5d9-80ad5c98f9f6/resources/b552f778-683e-4ebb-b113-19f7de95afc4/attributes/60140ef6-7288-470c-9e81-c659a20f78af"
},
"environment": {
"href": "https://api.pingone.com/v1/environments/abfba8f6-49eb-49f5-a5d9-80ad5c98f9f6"
},
"resource": {
"href": "https://api.pingone.com/v1/environments/abfba8f6-49eb-49f5-a5d9-80ad5c98f9f6/resources/b552f778-683e-4ebb-b113-19f7de95afc4"
}
},
"id": "60140ef6-7288-470c-9e81-c659a20f78af",
"environment": {
"id": "abfba8f6-49eb-49f5-a5d9-80ad5c98f9f6"
},
"name": "clientAssertion_custom",
"value": "${#root.context.requestData.clientAssertion.custom1}",
"type": "CUSTOM",
"resource": {
"id": "b552f778-683e-4ebb-b113-19f7de95afc4"
}
}