Attention: This site does not support the current version of your web browser. To get the best possible experience using our website we recommend that you upgrade to a newer version or install another browser

Skip main navigation

Client Credentials Authentication

Authentication can be granted to an app rather than to a user. To obtain client credential authentication, you must first contact devsupport@familysearch.org to obtain special permission and assignment.

To authenticate using client credentials you must create and submit a client secret with your authentication request. The client secret is used to validate that the client is who it says it is. Since the Oauth2 specification does not describe the implementation of client authentication, the FamilySearch Platform implementation of Oauth2 provides a custom mechanism to identify the client by having the client create and sign a time stamp which is submitted to each endpoint as the "client_secret" parameter. During Oauth2 client registration clients can link to a FamilySearch Platform service account. The following describes how the client must create this request:

  1. The service account has the public key from a public-private key pair provided by the client.
  2. The time stamp is formatted as a decimal string indicating the time in milliseconds after January 1, 1970 00:00:00 GMT.
  3. The time stamp is then signed/encrypted using the private key of the service account associated with the client and Base 64 encoded.

The time stamp is verified/decrypted by FamilySearch Platform and accepted if the time stamp has a time +- 5 minutes of the time on the FamilySearch Platform server at the time the secret is decoded.

Client Credentials Example 1

Java

Sample Java code illustrating invoking the token endpoint with the client credentials grant type. See Client Secret (below) for details on generating the client_secret.

StringBuilder sb = new StringBuilder("https://ident.familysearch.org/cis-web/oauth2/v3/token");
sb.append("?grant_type=client_credentials&client_id=");
sb.append(clientId);
sb.append("&client_secret");
sb.append("=");
sb.append(URLEncoder.encode(secret, "UTF-8"));

URL url = new URL(sb.toString());

HttpsURLConnection con = (HttpsURLConnection)url.openConnection();
con.setRequestMethod("POST");
InputStream ins = con.getInputStream();
InputStreamReader isr = new InputStreamReader(ins);
BufferedReader in = new BufferedReader(isr);
String inputLine;
StringBuilder sb2 = new StringBuilder();

while ((inputLine = in.readLine()) != null)
{
  sb2.append(inputLine);
}

in.close();

JSON json = new JSON();
try{
  HashMap jsonMap = (HashMap)json.fromJSON(sb2.toString());
  if (jsonMap.containsKey("refresh_token")) {
    String refresh_token = (String)jsonMap.get("refresh_token");
  }
}
catch (IllegalStateException e) {
  e.printStackTrace();
}

Client Secret Creation

To obtain a client secret and to verify/decrypt the time stamp, use private key encryption or signing. See the following examples.

Encryption

Private Key Encryption/Public Key Decryption

The following Java code creates a client secret using private key encryption.

KeyStore ks = KeyStore.getInstance("JKS");
char[] password = "mypassword".toCharArray();
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("mykeystore.jks");
ks.load(is, password);
is.close();
PrivateKey privateKey = (PrivateKey)ks.getKey("mykey", password);
// Create the secret with the private key
Security.addProvider(new BouncyCastleProvider());
long timestamp = System.currentTimeMillis();
String sTimestamp = Long.toString(timestamp);
byte[] bytesTimestampUtf8Unencrypted = sTimestamp.getBytes(Charset.forName("UTF-8"));
Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
byte[] bytesTimestampUtf8Encrypted = cipher.doFinal(bytesTimestampUtf8Unencrypted);
String encoded = (new BASE64Encoder()).encodeBuffer(bytesTimestampUtf8Encrypted);
String secret = URLEncoder.encode(encoded, "UTF-8");

Signing

Private Key Signing/Public Key Verification

The following Java code creates a client secret using private key signing.

KeyStore ks = KeyStore.getInstance("JKS");
char[] password = "mypassword".toCharArray();
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("mykeystore.jks");
ks.load(is, password);
is.close();
PrivateKey privateKey = (PrivateKey)ks.getKey("mykey", password);
// Create the secret with the private key
Security.addProvider(new BouncyCastleProvider());
long timestamp = System.currentTimeMillis();
String sTimestamp = Long.toString(timestamp);
byte[] bytesTimestampUtf8Unencrypted = sTimestamp.getBytes(Charset.forName("UTF-8"));
Signature signer = Signature.getInstance("SHA512withRSA");
signer.initSign(privateKey);
signer.update(bytesTimestampUtf8Unencrypted);
byte[] bytesTimestampUtf8Encrypted = signer.sign();
String encoded = (new BASE64Encoder()).encodeBuffer(bytesTimestampUtf8Encrypted);
String secret = URLEncoder.encode(encoded, + ":" + timestamp "UTF-8");

Client Credentials Example 2

PHP

Sample PHP code showing how to do the client authentication. This sample code uses Composer for its php library dependency management.

<?php
require "vendor/autoload.php";
function create_secret(){
  $pk = openssl_pkey_get_private("file:///path_to_keys/mykey.pem");
  $timestamp = (string)intval(microtime(true)* 1000);
  openssl_private_encrypt($timestamp,$crypttext,$pk);
  $base64_crypt_time = base64_encode($crypttext);
  return $base64_crypt_time;
}
Guzzle\Http\StaticClient::mount();
$secret = create_secret();
$params = [
  'grant_type' => 'client_credentials',
  'client_id' => 'YOUR-DEV-KEY',
  'client_secret' => $secret
];
$response = Guzzle::post('https://ident.familysearch.org/cis-web/oauth2/v3/token', [
    'query'   => $params,
    'timeout' => 10,
    'debug'   => true
]);
$doc = json_decode($response->getBody());
echo $doc->token;
?>

Here is the Composer package information for this sample code:

{
    "require": {
        "guzzle/guzzle": "~3.7"
    }
}

Client Credentials Example 3

Ruby

Sample Ruby code showing how to do the client authentication. This sample code uses Bundler to manage the required gems to run this code. See the Gemfile below the sample.

require 'openssl'
require 'base64'
require 'faraday'
require 'faraday_middleware'
def create_secret()
  private_key = OpenSSL::PKey::RSA.new File.read 'keys/mykey.pem'
  time_in_milliseconds = (Time.new.to_f * 1000).to_i
  encrypted_time = private_key.private_encrypt time_in_milliseconds.to_s
  base64_crypt_time = Base64.encode64 encrypted_time
end
# Using Faraday, but this could easily be done with any other HTTP library.
conn = Faraday.new() do |faraday|
  faraday.response :logger                  # log requests to STDOUT
  faraday.adapter  Faraday.default_adapter  # make requests with Net::HTTP
  faraday.response :json, :content_type => /\bjson$/
end
secret = create_secret
params = {
  'grant_type' => 'client_credentials',
  'client_id' => 'YOUR-KEY',
  'client_secret' => secret
}
response = conn.post do |req|
  req.url "https://ident.familysearch.org/cis-web/oauth2/v3/token", params
end
puts response.body['token']

Here is the Gemfile for bundler.

source "https://rubygems.org"
gem "faraday", "~> 0.8.9"
gem "faraday_middleware", "~> 0.9.0"

Sample Request and Response

Request
POST /cis-web/oauth2/v3/token
Accept: application/json
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&client_id=Q9DB-R9RS-78MC-52M4-N3J9-W5VX-KT25-PK83&client_secret=KCnu5RD
SZHpiwa3G9xssuIE2vVO3XqBUNZwIDUk3e244x%2F6TGo5M9HD06dlgqxv9YP6bhk%2F7YjX84JE2JdZbe2n6G5s3TDcHr35OerqHu
Zq5Fs7BI63KnC7ejv7E5Of5UJOojXqUxQSKIQ07CH7wfwniyHtb1xkk%2BVVPQfVFKj8X42r%2BFwkNXuYUOzTdzoFgktwuWAVMWZ
fLfLPMrz7z%2BtqgUiJ9h0EWdfpNsrrVpip3ivxc3KLDUWyhgGu4eouxYCrr2V8%2FTMhnch7eyBtBEgHAT2graMGjXxiH%2BjhB
SLlwXECm673p6u8%2BAJ40QoofXPyhVkMt6cD5JowHp38Yjw%3D%3D
Response
HTTP/1.1 200 OK
Transfer-encoding: chunked
Cache-control: no-cache, no-store, no-transform, must-revalidate, max-age=0
Vary: Accept-Encoding
Vary: Accept, Accept-Language, Accept-Encoding, Expect
Date: Thu, 14 Jan 2016 22:39:55 GMT
Content-type: application/json
X-processing-time: 37
{
  "access_token" : "2YoTnFdFEjr1zCsicMWpAA",
  "token_type" : "family_search"
}
x

Select a language