Skip to main content

API Security and Best Practice

Fenergo have provided API Endpoints and capabilities so clients can create and manage their integrations as per their own requirements. We have followed industry best practice in how those API are provisioned and secured but clients must consider how they intend to use those APIs and what Security practices they intend to adopt. This document is intended to highlight common topics and suggested strategies that clients might want to follow.

  • Environment Clients do not need to treat every tenant the same from a security standpoint. It is a perfectly valid trade off to leave lower SDLC tenants configured with lighter security to aid and support development, but that strategy needs to be tightened in Gold State and Production tenants, especially where real data resides.
  • Access Control The Fenergo application uses Access Layers and teams to make sure only the correct users can perform specific actions. The API handles this same strategy using Scopes which govern what services an API client can access.
  • MTLS Fenergo APIs can support MTLS (Mutual Transport Layer Security) where both client and server establish trust using certificates (as opposed to TLS where only the server presents a certificate that the client trusts). There is some overhead and planning involved in MTLS configuration which must be planned for and it likely is not required for lower region SDLC tenants.

Facilitate Development

As can be seen from the list of scopes, a lot of control can be exerted in terms of permissions when accessing the Fenergo APIs. However a very popular choice my by clients is to simply request a fenx.all scope for lower SDLC tenants. Security at this level is not a primary concern in terms of:

  • Data: No real Client Data is permitted on lower region tenants, only test or anonymized data is permitted.
  • System to System Access: Especially early in a development cycle, the systems a client intends to use for integration might not yet exist or at best be running POC code implementations. The objective at this stage of development is to demonstrate what can be done, not present barriers.
  • Test Harness: Developers may be using tools like postman to test and get familiar with the APIs and may also be sharing the credential amongst their team, if they get slowed down by more complex Access Control requirements it may inhibit their ability to work in an agile way.
  • Functionality: Focus Development effort on SDLC tenants will focus on happy path functional outcomes. A set of more Non Functional lenses are applied a little later in the cycle, such as Performance and Security.

Environment Overviews

Once development is functionally enabled, security stakeholders can then design the target state from a security standpoint. It actually serves better to do this in parallel with development as you don't create any contention or dependencies up front. It helps to consider a typical tenant allocation where clients get three SDLC Tenants and a Production Tenant as below. Some clients structure and name their environments differently but this is a typical way to interpret the intended use of the allocated tenants.

Tenant TypeEquivalent EnvironmentSecurity Overview
SDLC Tenant 1DEV (Development)Should be considered an open sandbox where people can test, learn, configure and experiment. Implementing security barriers here will only slow down development and test as well as training. It should be used as a proving ground for Policy, Journey, Risk, Screening configuration etc.... and somewhere to test the API interactions planned for the project.
SDLC Tenant 2UAT (User Acceptance Testing)UAT would typically have firmer controls that DEV, there would be governance over the configuration as the Journey and Operational experience configured in DEV gets validated on UAT. The Team and Access Layers may be closer to the intended target but still supports the ability to be flexible. Potentially the security would get tightened up as UAT test cycles mature towards a production candidate.
SDLC Tenant 3PRE-PROD (Production Staging Area)It would be common to see Pre Prod mirror the exact configuration for production. Everything from Team Structure to API Credentials. It would be identical with the exception of the data which would still be test or anonymized data
Production TenantPROD (Production)Production configuration is the target state being planned for from a security and configuration perspective. If production is Green Field (not yet live) then there would be more flexibility in terms of doing soft, staggered launches but the tenant should be treated in the same manner as any other high profile strongly governed technology asset.

Design for Security

With the environment configurations in mind, we would suggest the following as best practices from a security design standpoint.

MTLS Configuration

  • MTLS should only be used for Pre-Production and Production. For Pre-Production this is simply to prove the configuration but could also fully mimic the planned production approach if it was necessary. There is administrative overhead in creating and managing certificates which needs to be taken into account but in general, it only serves to make lower tenants unnecessarily complex.
  • Clients can if required create their own CSRs. Fenergo can supply certificates to clients and the Cloud Business Office can arrange to have the Certificate shared in a secure fashion, but if policy dictates then clients can do the CSR themselves.
  • Establish a Certificate Rotation Schedule. Certificates are typically valid for a period of two years, so once a client credential is issued you should plan for the rotation process. Fenergo will of course monitor for this but clients may want to plan for an overlap period where a new certificate is created well in advance of the expiry of an existing one to allow for a comfortable, planned and fully tested transition without the need for emergency change activities.
MTLS

If MTLS is NOT required, none of these considerations need to be accommodated and MTLS can always be requested at a later stage post production, potentially when introducing new integrations.

Number of Client Credentials Required and Allocated Scopes

As per the list of available scopes, clients should be planning what they want their connected systems to do. This should be done via user-story mapping. Think of a simple example where an event notification is sent out after a journey is complete and the client wants to use the notification as a trigger to update a downstream reporting system with an update of the Legal Entity and Journey details.

Sample use case
  AS: an API consumer:

GIVEN: I have received a webhook notification indicating that a Journey has completed

AND: I want to retrieve Legal Entity & Journey Data to update a downstream platform

WHEN: I get the webhook notification

THEN: I want to create call the APIs needed to gather the data required.

In satisfying this use case the system only needs to use APIs from EntityDataQuery and JourneyQuery. The Scopes required to access these APIs are fenx.entitydata.read and fenx.journey.read. So when planning for the production instance of this Client Credential, one with ONLY these scopes should be requested. This would be adhering to the principal of least privilege and in doing so restricting the potential impact if the credential or access tokens generated with it were compromised.

In Identifying The Required Credentials

  • Analyze the use cases you are intending to deliver. You can be as granular as you wish and create a credential for each system limiting the scopes to only that which is required to deliver the use case.
  • Decide early on MTLS and make the requests in advance of your production go-live.
  • It is possible to share your credentials amongst different client systems but this broadens the attack surface, again this depends on where you are storing the credentials so the calling platforms can read them.
  • Request as many credentials as you require, and set the granularity of scopes in accordance to your own security policy.
  • Do not use fenx.all for production integration clients.
  • You can request and manage a fenx.all credential for production, but the purpose should be explicitly for admin use where maintenance or investigative activity is required. Such a credential should follow best practice access change control (in a similar way to a production database admin account).

Caching Access Tokens

When using a client credential, an authentication request is sent to the Fenergo IDP which returns (if authenticated) a Bearer Access Token. This token response comes with a value called expires_in which is a value in Seconds for how long that token will be accepted for API calls. The default time for this timeout is 900 seconds which is 15 Minutes. An example of the response is below with the token type and the expires_in property.

Access Token Response
  {
"access_token": "eyJhbGciOiJSUzI1JZdWa83jQ8n1A........",
**"expires_in": 900**,
**"token_type": "Bearer"**,
"scope": "fenx.all"
}
Caching Access Tokens

CLIENTS USING THE client_credentials GRANT TYPE SHOULD CACHE TOKENS

If a client is requesting a new token as part of their code for every API call, they are putting unnecessary pressure on the Fenergo Identity Provider.

Caching the token means that client integrations can use and re-use the same token for the full 15 minute validity timeframe. If a client was performing a batch operation with 1000's of API calls they could find that their call to authenticate gets throttled which would slow down their batch or potentially cause errors in execution.

The current limit is 100 requests per client over a 5 minute-period and it also considers token requests over MTLS.

C# Code for Caching Access Tokens

A simple example to cache an Access Token is illustrated below. In the C# code it can be seen that a call to FenX SendFenXApiRequest(), contains a test to see if the token is null or has expired. If it has expired or is null, a new one is requested. This way a common function can be used to make calls throughout your system but without making a request for a new token each time.

C# Code to Cache Access Tokens
// Get Token from FenX
public void RenewToken()
{
//Assuming the code in the below function makes a call to retrieve an Access Token
var tokenResponse = GetTokenFromFenX();
//Add that token to the cache.
cache.AddTokenEntry(tokenResponse.access_token, DateTime.UtcNow + TimeSpan.FromSeconds(tokenResponse.expires_in));
}
// Use token
public void SendFenXApiRequest()
{
var cacheEntry = cache.GetTokenEntry();
//Test if the Token has Expired
if (cacheEntry == null || DateTime.UtcNow >= cacheEntry.ExpirationTime)
{
//If it has Expired - Renew it and add to the cache
RenewToken();
cacheEntry = cache.GetTokenEntry();
}
SendRequestToFenx(cacheEntry.Value);
}

Python Code for Caching Access Tokens

Same Token Caching objective as above but written in Python.

Python Code to Cache Access Token
# Get Token from FenX

def renew_token():
# Assuming the code in the below function makes a call to retrieve an Access Token
token_response = get_token_from_fenx()
# Add that token to the cache.
cache.add_token_entry(token_response['access_token'], datetime.utcnow() + timedelta(seconds=token_response['expires_in']))
# Use token

def send_fenx_api_request():
cache_entry = cache.get_token_entry()
# Test if the Token has Expired
if cache_entry is None or datetime.utcnow() >= cache_entry.expiration_time:
# If it has Expired - Renew it and add to the cache
renew_token()
cache_entry = cache.get_token_entry()
send_request_to_fenx(cache_entry.value)