Chevron RightLink On-DemandChevron Right

Authentication With Public/Private Keypair

Search

Authenticating with Public/Private Keypair

Public/Private Keypair authentication is recommended when using the Link API for production use cases. While it requires some additional setup, this method is the most secure and easy way to use Link in the long term. For testing and development, individual users should check out the authentication quickstart guide.

Keypair Setup

Generate an RSA Keypair

In this guide, we will use the openssl library, which is available on Unix systems (which includes Macs). First, open a terminal and generate a 2048-bit private key:

openssl genrsa -out private.pem 2048

Next, extract the public key:

openssl rsa -in private.pem -outform PEM -pubout -out public.pem

Send Kensho Your Public Key

Email support@kensho.com with your PEM encoded public key as an attachment. We will respond with your Client ID. You will need this ID in the following step. While typical response times are very quick, please allow up to three business days for us to process your request.

Important: Do not send us your private key! While your public key and Client ID are not secret, your private key should not be shared outside your organization.

Use Your Private Key and Client ID to Generate an Acess Token

Most languages have JWT (JSON Web Token) libraries. In this example, we make use of PyJWT, a JWT library for Python. We provide a get_access_token_from_key helper function that can be used.

import jwt
import requests
import time
def get_access_token_from_key(client_id):
PRIVATE_KEY_PATH = "private.pem" # the location of your generated private key file
with open(PRIVATE_KEY_PATH, "rb") as f:
private_key = f.read()
iat = int(time.time())
encoded = jwt.encode(
{
"aud": "https://kensho.okta.com/oauth2/default/v1/token",
"exp": iat + (30 * 60), # expire in 30 minutes
"iat": iat,
"sub": client_id,
"iss": client_id,
},
private_key,
algorithm="RS256",
)
response = requests.post(
"https://kensho.okta.com/oauth2/default/v1/token",
headers={
"Content-Type": "application/x-www-form-urlencoded",
"Accept": "application/json",
},
data={
"scope": "kensho:app:link-model-server",
"grant_type": "client_credentials",
"client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
"client_assertion": encoded,
}
)
return response.json()["access_token"]
CLIENT_ID = "" # paste your Client ID sent to you by Kensho inside the quotation marks
ACCESS_TOKEN = get_access_token_from_key(CLIENT_ID)

Note that Content-Type is specified as application/x-www-form-urlencoded. When you call requests.post() in python, data dictionary will automatically be converted into a string formatted like this: client_assertion=xxxxxxx&scope=kensho:app:link-model-server&grant_type=client_credentials&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer If you are using another programming language, you need to make sure you send data in the format specified above, rather than sending in JSON.

Verify Token

To test out your new Access Token, run

curl -H "Authorization: Bearer <your token>" https://link-streaming.kensho.com/me

If you get a response with your client ID, you're in the money! Head over to the REST API Guide to link your records to S&P records.

Production Use

Using your Public/Private Keypair allows you to always generate a fresh Access Token. This token expires every hour, on the hour, so you will need to regenerate it during a long-running application. We provide an example in Python below. Note that this snippet uses the get_access_token_from_key defined above. For more details on using the Link API, check out the REST API Guide.

The code below defines a LinkClient class that can be used to make requests to the Link on-demand endpoint. This client will update the access token when needed, using public/private keypair authentication. You will need to paste your Client ID (emailed to you by our support@kensho.com team in the steps above) in the field CLIENT_ID. Below the LinkClient definition, the client is used to make linking requests for two companies, "S&P Global Inc." and "kensho".

import json
import requests
import time
import os
CLIENT_ID = "" # paste your Client ID sent to you by Kensho inside the quotation marks
class LinkClient:
"""A class to call the Link API that automatically refreshes tokens when needed."""
def __init__(self, client_id):
self.client_id = client_id
def update_access_token(self):
self.access_token = get_access_token_from_key(self.client_id)
def call_api(self, verb, *args, headers={}, **kwargs):
"""Call Link API, refreshing access token as needed."""
if not hasattr(self, "access_token"):
self.update_access_token()
def call_with_updated_headers():
nonlocal method
headers["Authorization"] = f"Bearer {self.access_token}"
return method(*args, headers=headers, **kwargs)
method = getattr(requests, verb)
response = call_with_updated_headers()
if response.status_code == 401:
self.update_access_token()
response = call_with_updated_headers()
return response
def make_link_request(self, knowledge_base, data):
"""Make a POST call to Link On-Demand Endpoint."""
response = self.call_api(
"post",
f"https://link-streaming.kensho.com/api/ondemand/v0/companies/{knowledge_base}/generic",
data=json.dumps(data),
headers={"Content-Type": "application/json"}
)
return response.json()
# knowledge base to link to ("capiq" or "mi")
knowledge_base = "capiq"
# link request data
data = {
"records": [
{
"uid": "1",
"name": "S&P Global Inc.",
"aliases": ["S&P", "SPGI"],
"country_iso3": "USA",
"address": "55 Water Street",
"state": "New York",
"city": "New York",
"zipcode": "10041",
"year_founded": 1917,
"url": "https://www.spglobal.com/",
"phone_number": "718-123-4567"
},
{
"uid": "2",
"name": "kensho"
}
],
"num_top_records": 2,
"include_response_fields": ["knowledge_base_name"],
}
# create a link client
link_client = LinkClient(CLIENT_ID)
# submit request to on-demand endpoint
linked_results = link_client.make_link_request(knowledge_base, data)