Authorization

Ownera APIs are protected by an authentication mechanism that restricts access from unauthorized entities, the authorization is based on a JWT authorization that is verified and expected to be present in each request.

A token is required to communicate with the Ownera APIs. The token payload contains the associated organization ID, API key, nonce, issued at timestamp, and token expiration timestamp.

The one-time-access token is required to be generated for each request to the Ownera APIs. The token is limited to one time access and is time bound by the expiration and nonce unique value. A token which has a timestamp that is outside of the accepted time range or has already been used will be rejected by the authorization process.

JWT access token is built out of 3 parts: Header, Payload, and Signature.

  1. Header - includes the signing algorithm and the token type (JWT).
  2. Payload - includes:

Organization id (aud) – organization name for the router in which the connection is made to.

Issued At (iat) – timestamp of token issuance in seconds (epoch).

Nonce (nonce) – unique string built out of 24 random bytes concatenate with current epoch timestamp (8 bytes). Time deviation of up to a given minutes range is allowed based on configuration (default is 5 seconds). Nonce has to be encoded as a hexadecimal string.

Expire At (exp) – timestamp in epoch that will be used to expire the token (issued At + 30 seconds).

API key (sub) – API key.

  1. Signature - is built of header and payload, both encoded as base64url concatenated with “.” in between and signed with, RS256 algorithm, the private key you generated is used to sign.
    The authorization object, including the generated access token, is base64 encoded and sent to the API as bearer authorization header.

--header 'Authorization: Bearer <generated token>’

Onboarding Authorization to FinP2P

The following are the steps involved in onboard the authorization part of the integration into the Ownera finp2p API:

StepsDetails
1Generate a private key that you will use when signing your calls to finp2p for authorization for the given finp2p router.

openssl genrsa -out prv.key 4096
2Generate a public key out of the private key and send it to Ownera which will be used to configure your access to the given finp2p router:

openssl rsa -in prv.key -RSAPublicKey_out -out pub.key
3Ownera generates and supplies you the required API key for the authorization.
4Ownera will also supply the organization ID that needs to be included in the JWT authorization.
5Configure and enable the authorization in your finp2p API integration to test your code, including the supplied API key and Organization ID. In addition to that you will include in your configuration the private key you generated.

JWT Implementation code example

The following is an example of code illustrating the generation of a token that is used to authorize the API call in RS256 algorithm:

const crypto = require('crypto');


// The generated inputs that were created as part of the onboarding of the authorization for the given Router in which you are connecting to.


// These values are provided to you by Ownera
const API_KEY = "239189f2d-19af-4eaf-a4cc-30f7df6e9f37";
const ORGANIZATION_ID = "bank_one";


// The private key you generated
const PRIVATE_KEY   = "-----BEGIN PRIVATE KEY-----\n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\ng55fcfRdDysxi/nooh0EgHFMNpgw\n-----END PRIVATE KEY-----\n"


// The algorithm used in this case is RS256
const ALGORITHM = "RS256";


// Generate 24 random bytes value, add timestamp, to generate a nonce
const buffer = Buffer.alloc(32);
buffer.fill(crypto.randomBytes(24), 0, 24);
const nowEpochSeconds = Math.floor(new Date().getTime() / 1000);
const t = BigInt(nowEpochSeconds);
buffer.writeBigInt64BE(t, 24);
const nonce = buffer;


// generate creation and expiration values for the token
const timestamp = Math.floor(new Date().getTime() / 1000);
const expireAt = timestamp + 30;


// generate the jwt payload
const payload = {
 aud: ORGANIZATION_ID,
 apiKey: API_KEY,
 nonce: nonce.toString('hex'),
 iat: timestamp,
 exp: expireAt
};

// function to base64 encoding
function base64UrlEncode(str) {
 let base64 = Buffer.from(str).toString('base64');
 return base64.replace('+', '-').replace('/', '_').replace(/=+$/, '');
}


// function to sign payload with private key
function sign(data, privateKey) {
 return crypto.createSign('RSA-SHA256').update(data).sign(privateKey, 'base64')
 .replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
}

 // encode base64 both payload and header
const encodedHeader = base64UrlEncode(JSON.stringify({ alg: ALGORITHM, typ: "JWT" }));
const encodedPayload = base64UrlEncode(JSON.stringify(payload));
const toBeSigned = `${encodedHeader}.${encodedPayload}`;


// sign encoded header and payload
const signature = sign(toBeSigned, PRIVATE_KEY);


// concat each part with "." separator
const token = `${encodedHeader}.${encodedPayload}.${signature}`;

// The token should be assigned to every API call as a Bearer token in header
console.log(token);
/opt/homebrew/bin/node ./JWT_auth.js
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJiYW5rLXVrIiwiYXBpS2V5IjoiMzkxODlmMmQtMTlhZi00ZWFmLWE0Y2MtMzBmN2RmNmU5ZjM3Iiwibm9uY2UiOiIwNzQ2NmU5YTI5ODA2MmY1ZWQyYzIyOTY3YThkYWVjMTI0ZDM5ODAwNTQzNzNjYTMwMDAwMDAwMDY1NjVkNzY2IiwiaWF0IjoxNzAxMTczMDk0LCJleHAiOjE3MDExNzMxMjR9.Te9z2_bZqDGNgeWjeTAs1iKCvg5t4T9-b50E93ah08r2NG9nlUu_0H3XMFLYbat_DNJqt1Gjz63UOMwWIQ7sCJeqYz8aZIFCiVGvnH9g3hT4daFtcENB0jCp_WlJVcrx26Hklw6vNo0H5aF142lYu6S21IoWWDl4GItywBfLVLK2Vn2eBiS5tGem8B3Vak-00fDnWVjlCNoiR10NengTN_sAYkr8_-6CVXYxSNGJRiwS2Lg4cAeZgIPzq8Mfk9jSKpl85uweIDAOWshyJy_3NCFZJ78qz4jy-PmnRrY0v4flup2dIdjOAD1Howh8x_J-oerI909ZJ7Ku1cDji1FNI2UV5XT1dOQWl4KY5RZVu7rfnlLTlBMbyfssGKgelCB3yd0M2LrOq_I2gDkXQ9PhLSlcplOEorK6WyEtB3_HfwOB28joPzG16cDd0l3ik5A8BuJmTIoqtVV_TjnMvPBCXVUjW2s7MPphOCdEK6uBE9YeFjY6M11Icz5G7FPeR0f5GvtcupdZF-VRcGvRDx3oNVDQxbGeCrO3LtOiYGqWo0NaotDYcIIDTKzVBvyiiwtlviAAjAN-fKPVKvY4YFGmICxOFZFTBv_VtCjcpEkp8q-JI5t-KgpWOMRtK6u6pdkMNOARtG6wsRrPJpwLeC1HkzULx1JZnycBd2mGEpcJl_o