PingOne Platform APIs

Create Credential Verification Session (OPENID4VP)

   

POST {{apiPath}}/environments/{{envID}}/presentationSessions

Use the POST {{apiPath}}/environments/{{envID}}/presentationSessions to initiate verification of a user credential using the OpenID for Verifiable Presentations (OPENID4VP) protocol of JSON Web Token Verifiable Credentials (JWT-VC). Each credential verification session silently times out after 5 minutes.

Prerequisites

Request Model

Refer to Credential Verifications session data model for full property descriptions.

Property Type Required

didMethod

String

Optional

issuerFilter.dids

String[]

Optional

issuerFilter.environmentIds

String[]

Optional

message

String

Optional

protocol

String

Optional

requestedCredentials

Object[]

Required

requestedCredentials.keys

String[]

Optional

requestedCredentials.type

String

Required

Content of requestedCredentials differs by protocol. The protocol of OPENID4VP permits only one credential type per request and ignores requestedCredentials.keys if present.

If issuerFilter.dids is submitted and protocol is OPENID4VP, the service searches all listed decentralized identifiers for the issuer of the presented credential. If the user presents a credential that is not from one of these issuers, the verification fails with status of VERIFICATION_FAILED.

This issuerFilter.dids typically contains decentralized identifiers for issuers that are not using PingOne Credentials for JWT-VC issuance. The service supports these three DID methods:

If issuerFilter.environmentIds is submitted, the service searches all listed environments for the issuer of the presented credential. If the user presents a credential that is not from one of these issuers, the verification fails with status of VERIFICATION_FAILED.

Headers

Authorization      Bearer {{accessToken}}

Content-Type      application/json

Body

raw ( application/json )

{
    "message": "Some custom message for the user.",
    "protocol": "OPENID4VP",
    "requestedCredentials": [
        {
            "type": "Driver License",
            "keys": [
                "First Name",
                "Last Name"
            ]
        }
    ],
    "issuerFilter": {
        "dids": [
            "did:web:auth.pingone.com:{{envID}}:issuer"
        ]
    }
}

Example Request

  • cURL

  • C#

  • Go

  • HTTP

  • Java

  • jQuery

  • NodeJS

  • Python

  • PHP

  • Ruby

  • Swift

curl --location --globoff '{{apiPath}}/environments/{{envID}}/presentationSessions' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{accessToken}}' \
--data '{
    "message": "Some custom message for the user.",
    "protocol": "OPENID4VP",
    "requestedCredentials": [
        {
            "type": "Driver License",
            "keys": [
                "First Name",
                "Last Name"
            ]
        }
    ],
    "issuerFilter": {
        "dids": [
            "did:web:auth.pingone.com:{{envID}}:issuer"
        ]
    }
}'
var options = new RestClientOptions("{{apiPath}}/environments/{{envID}}/presentationSessions")
{
  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" +
@"    ""message"": ""Some custom message for the user.""," + "\n" +
@"    ""protocol"": ""OPENID4VP""," + "\n" +
@"    ""requestedCredentials"": [" + "\n" +
@"        {" + "\n" +
@"            ""type"": ""Driver License""," + "\n" +
@"            ""keys"": [" + "\n" +
@"                ""First Name""," + "\n" +
@"                ""Last Name""" + "\n" +
@"            ]" + "\n" +
@"        }" + "\n" +
@"    ]," + "\n" +
@"    ""issuerFilter"": {" + "\n" +
@"        ""dids"": [" + "\n" +
@"            ""did:web:auth.pingone.com:{{envID}}:issuer""" + "\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}}/presentationSessions"
  method := "POST"

  payload := strings.NewReader(`{
    "message": "Some custom message for the user.",
    "protocol": "OPENID4VP",
    "requestedCredentials": [
        {
            "type": "Driver License",
            "keys": [
                "First Name",
                "Last Name"
            ]
        }
    ],
    "issuerFilter": {
        "dids": [
            "did:web:auth.pingone.com:{{envID}}:issuer"
        ]
    }
}`)

  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}}/presentationSessions HTTP/1.1
Host: {{apiPath}}
Content-Type: application/json
Authorization: Bearer {{accessToken}}

{
    "message": "Some custom message for the user.",
    "protocol": "OPENID4VP",
    "requestedCredentials": [
        {
            "type": "Driver License",
            "keys": [
                "First Name",
                "Last Name"
            ]
        }
    ],
    "issuerFilter": {
        "dids": [
            "did:web:auth.pingone.com:{{envID}}:issuer"
        ]
    }
}
OkHttpClient client = new OkHttpClient().newBuilder()
  .build();
MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, "{\n    \"message\": \"Some custom message for the user.\",\n    \"protocol\": \"OPENID4VP\",\n    \"requestedCredentials\": [\n        {\n            \"type\": \"Driver License\",\n            \"keys\": [\n                \"First Name\",\n                \"Last Name\"\n            ]\n        }\n    ],\n    \"issuerFilter\": {\n        \"dids\": [\n            \"did:web:auth.pingone.com:{{envID}}:issuer\"\n        ]\n    }\n}");
Request request = new Request.Builder()
  .url("{{apiPath}}/environments/{{envID}}/presentationSessions")
  .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}}/presentationSessions",
  "method": "POST",
  "timeout": 0,
  "headers": {
    "Content-Type": "application/json",
    "Authorization": "Bearer {{accessToken}}"
  },
  "data": JSON.stringify({
    "message": "Some custom message for the user.",
    "protocol": "OPENID4VP",
    "requestedCredentials": [
      {
        "type": "Driver License",
        "keys": [
          "First Name",
          "Last Name"
        ]
      }
    ],
    "issuerFilter": {
      "dids": [
        "did:web:auth.pingone.com:{{envID}}:issuer"
      ]
    }
  }),
};

$.ajax(settings).done(function (response) {
  console.log(response);
});
var request = require('request');
var options = {
  'method': 'POST',
  'url': '{{apiPath}}/environments/{{envID}}/presentationSessions',
  'headers': {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer {{accessToken}}'
  },
  body: JSON.stringify({
    "message": "Some custom message for the user.",
    "protocol": "OPENID4VP",
    "requestedCredentials": [
      {
        "type": "Driver License",
        "keys": [
          "First Name",
          "Last Name"
        ]
      }
    ],
    "issuerFilter": {
      "dids": [
        "did:web:auth.pingone.com:{{envID}}:issuer"
      ]
    }
  })

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

url = "{{apiPath}}/environments/{{envID}}/presentationSessions"

payload = json.dumps({
  "message": "Some custom message for the user.",
  "protocol": "OPENID4VP",
  "requestedCredentials": [
    {
      "type": "Driver License",
      "keys": [
        "First Name",
        "Last Name"
      ]
    }
  ],
  "issuerFilter": {
    "dids": [
      "did:web:auth.pingone.com:{{envID}}:issuer"
    ]
  }
})
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}}/presentationSessions');
$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    "message": "Some custom message for the user.",\n    "protocol": "OPENID4VP",\n    "requestedCredentials": [\n        {\n            "type": "Driver License",\n            "keys": [\n                "First Name",\n                "Last Name"\n            ]\n        }\n    ],\n    "issuerFilter": {\n        "dids": [\n            "did:web:auth.pingone.com:{{envID}}:issuer"\n        ]\n    }\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}}/presentationSessions")

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({
  "message": "Some custom message for the user.",
  "protocol": "OPENID4VP",
  "requestedCredentials": [
    {
      "type": "Driver License",
      "keys": [
        "First Name",
        "Last Name"
      ]
    }
  ],
  "issuerFilter": {
    "dids": [
      "did:web:auth.pingone.com:{{envID}}:issuer"
    ]
  }
})

response = http.request(request)
puts response.read_body
let parameters = "{\n    \"message\": \"Some custom message for the user.\",\n    \"protocol\": \"OPENID4VP\",\n    \"requestedCredentials\": [\n        {\n            \"type\": \"Driver License\",\n            \"keys\": [\n                \"First Name\",\n                \"Last Name\"\n            ]\n        }\n    ],\n    \"issuerFilter\": {\n        \"dids\": [\n            \"did:web:auth.pingone.com:{{envID}}:issuer\"\n        ]\n    }\n}"
let postData = parameters.data(using: .utf8)

var request = URLRequest(url: URL(string: "{{apiPath}}/environments/{{envID}}/presentationSessions")!,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

202 Accepted

{
    "_links": {
        "self": {
            "href": "https://api.pingone.com/v1/environments/abfba8f6-49eb-49f5-a5d9-80ad5c98f9f6/presentationSessions/ac18c46b-03b8-4293-a9c9-ef4877c84d5c"
        },
        "qr": {
            "href": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAIAAAAiOjnJAAAE5ElEQVR42u3dwXEbMQwFUBeSMtKC+y/JaSAHScAHIOthfNJkNivyaQYLkNyvHyEC8WUIBFgCLAGWEGAJsARYQoAlwBJg/Tf+/P1u/3vktp69zrP/17PXfPaeE2N44R4evx+wwAILLLDAAuuVG302KpNX+ZKTk10Zq8r1K+PQNY9ggQUWWGCBBVYPrMSgJ5LWrkhcPzFuF+YRLLDAAgsssMDah1UpeCaKh13F267vlbgmWGCBBRZYYIElea82ZdP3kG54p4u3YIEFFlhggQXWLViJJnQ6+U0n8l0PDeli7MetbgALLLDAAgus47AmF8f5PPf5R+zS8TlYYIEFls+Pw5qMdEO6a7NruvhZGbf0gsfHAyywwAILLLDASiXvlUJo1yCmG8/pzbTpucgVbMECCyywwAILrCtNzQTK9AEeW8349ANEfX7BAgsssMACC6zqQHRNxtahapWB3nooSYxtb3EVLLDAAgsssMBKwdo68CN9aFu6Ud2VvO++0AAssMACCyywwKoWMycBJSYvgSaRyE8uKqwXS8ECCyywwAILrM4GagJE7xfeTfYvFIHTPwywwAILLLDAAqsH1haaCxsW0k30O03l5iY0WGCBBRZYYIEVTd4TSWsC2YUfXvpBZPQFAmCBBRZYYIEFVkth7domha2i4mSBtJLsjxZIwQILLLDAAusDYW0t7ptMxtMHaVxYoPeWb6YACyywwAILrA+E1TUoW4l/ItGeLMxu3T9YYIEFFlhggbVzKEhi4tON8AsHyN5sJFca7WCBBRZYYIEFVhXWhQT8pykS9791P/NFUbDAAgsssMAC61FYuQJabxEvMUm9yexu4zz9QwILLLDAAgsssOaS98mBuHb/ic0L6fvs/RmDBRZYYIEFFlipRDjdAJ48qK3r36cfYrZ+qGCBBRZYYIEF1uuwJjcyTBZjrzXRry0qHH2BAFhggQUWWGB9IKzJxDOxmG4SQeJgt8ki8NuvbgALLLDAAgus47Amv1gitjbHpjd6TF5zdJcOWGCBBRZYYH0IrHTDNd2oTkCZTK4nD0zrXQwIFlhggQUWWGBNFC23GqvplwMkCsWTyfjaQj+wwAILLLDAAuvUBtQE+gsPCumXG6TBgQUWWGCBBRZYPbAqA51e5D9zeGs9oU78ALYWS4IFFlhggQUWWP0F0snNApMvHkpvLk0XV9PXBAsssMACCyywXofV9QUmF68lkt90A7s+kbmi6OlDQcACCyywwALrTWFNLna7dv2uYmbXeE5ep57sgwUWWGCBBRZYnXFhYq41obvGarKoW3+AAAsssMACCyywqsXJmRutJ5sXIE5ulN09UA4ssMACCyywwJooWk4WMy8k/tcWJyZekgUWWGCBBRZYYM0VSLcKqokXEiUeaCZfFJV4GAILLLDAAgsssPY3rKaT3K1rbk3q/aIoWGCBBRZYYIHVWSBNFDwnD2pLF10TDzG/KnkHCyywwAILLLDGksfJZHProSRdWN69f7DAAgsssMAC6zqs9IK19KaJaygTBVuwwAILLLDAAuu9YSWKrlsQ0xtPdhGDBRZYYIEFFlibTej05oiuCUg3tidf0jSz2QQssMACCyywwJpo0CYSzPQ1J//SReP0hguwwAILLLDAAus5WEJECqRCgCXAEmAJAZYAS4AlBFgCLPF74x/OB65c5GBm8gAAAABJRU5ErkJggg=="
        },
        "appOpenUrl": {
            "href": "openid-vc://?request_uri=https://api.pingone.com/v1/distributedid/verifications/presentation_sessions/ac18c46b-03b8-4293-a9c9-ef4877c84d5c/request"
        }
    },
    "id": "ac18c46b-03b8-4293-a9c9-ef4877c84d5c",
    "status": "INITIAL"
}