How to Get Customer and Application Context When Logging API Calls for 3scale API Gateway

Xing Wang - Oct 26 '23 - - Dev Community

As APIs handle enormous amounts of data of a widely varying type, the critical question for any data provider is how specifically to secure this data. An authentication method that gives power to developers to build applications for all of their needs, determines who could access the APIs to protect sensitive data and ensure the request aren’t tempered. Authentication is when an entity proves an identity. Simply put, authentication is the act of verifying that you are who you claim to be. Without authentication, there wouldn’t be an easy way to associate requests with the specific user data and no way to protect requests from malicious users that might delete other user’s data. Authentication shouldn’t be an afterthought but rather built into the very fabric of your API.

Authentication Patterns

Depending on our API we may need to use different authentication patterns to issue credentials for access to our API. These can range from API keys to custom configurations.

3Scale supports the following authentication patterns:

Standard API Keys

An authentication model where a single randomized strings or hashes acts as an identifier and a secret token. Each application with permissions on the API has a single unique string. By default the name of the key parameter is user_key. We can use this same label or choose another label before making the authorization calls to 3scale.

Application Identifier and Key pairs

An authentication model where the immutable identifier — Application Id (App_Id) and mutable secret key strings — Application Keys (App_Keys) are separated into two tokens. The App_Id is constant and may or may not be secret. Each application may have 1-n Application Keys where each key is associated directly with App_Id and should be treated as secret.

In 3Scale, each service could use a different authentication pattern but only one pattern could be used per service. In the authentication section, we could choose the required Authentication mode.

Image description

Application Context

3Scale provides an admin API endpoint to fetch application context associated for each user. Application context contains the details associated with an individual user about their interaction with 3Scale APIs like first_traffic_at, first_daily_traffic_at and other personally identifiable information data like - user_id, user_account_id, service_id, plan information and other details. With access to these details, it would be easy to associate requests with the specific user.

Depends on the authentication method we use, we call the admin endpoint to fetch the application context. While using the standard API keys authentication method, we fetch the application context by calling this endpoint -

curl -v -X GET "https://#{domain}/admin/api/applications.xml?access_token=#{ADMIN_ACCESS_TOKEN}&user_key=#{user_key}"

While using the application identifier and key pairs authentication method, we fetch the application context by calling this endpoint -

curl -v -X GET "https://#{domain}/admin/api/applications.xml?access_token=#{ADMIN_ACCESS_TOKEN}&app_id=#{app_id}&app_key=#{app_key}"

Setting Up Moesif API Analytics with 3Scale

Moesif has a plugin available in the Luarocks to capture API requests and responses and log to Moesif for easy inspecting and real-time debugging of your API traffic via 3Scale. The plugin captures metrics locally and queues them which enables the plugin to send metrics data to the Moesif collection network out of band without impacting your app.

The recommended way to install Moesif is via Luarocks:

luarocks install --server=http://luarocks.org/manifests/moesif lua-resty-moesif

Authentication Credentials Location

3Scale provides flexibility to an end-user to pass authentication credentials via HTTP_Headers or as query_parameters while calling an API. Moesif would look for the credentials in both headers and query parameters and fetch the application context for that particular user. Moesif provide a configuration option to set the field name which is the same name used while configuring the API authentication setting. By default, 3Scale uses user_key for standard API Key and app_id and app_key for App_Id and App_Key pair authentication method.

Identify User and Company (Account)

The admin endpoint returns the application context as a XML entity. Moesif provides a configuration option to set the field name from 3Scale’s application XML entity which will be used to identify the user and the company (account). The field name are id and user_account_id by default for user and company, but other valid examples include user_key and service_id.

-- Function to parse 3Scale XML entity
-- @param
user_id_nameThe 3scale field name from 3scale's application XML entity used to identify the user. Defaultid.
-- @param
company_id_nameThe 3scale field name from 3scale's application XML entity used to identify the company (account). Defaultuser_account_id.
-- @param
debugA flag to print logs
function parseXML(user_id_name, company_id_name, debug)
-- config_response is the response from an api call to fetch application context which is a XML entity
local response_body = config_response:match("(%<.*>)")
if response_body ~= nil then
local xobject = xml.eval(response_body)
local xapplication = xobject:find("application")
if xapplication ~= nil then
local xtable = {}
for k, v in pairs(xapplication) do
if v ~= nil and type(v) == "table" then
xtable[v:tag()] = k
end
end
local key = xapplication[xtable[user_id_name]]
if key ~= nil then
if debug then
ngx.log(ngx.DEBUG, "Successfully fetched the userId ")
end
-- Set the UserId
local user_id = key[1]
else
if debug then
ngx.log(ngx.DEBUG, "The user_id_name provided by the user does not exist ")
end
end
local companyKey = xapplication[xtable[company_id_name]]
if companyKey ~= nil then
if debug then
ngx.log(ngx.DEBUG, "[moesif] Successfully fetched the companyId (accountId) ")
end
-- Set the CompanyId (AccountId)
local company_id = companyKey[1]
else
if debug then
ngx.log(ngx.DEBUG, "[moesif] The company_id_name provided by the user does not exist ")
end
end
else
if debug then
ngx.log(ngx.DEBUG, "Application tag does not exist ")
end
end
else
if debug then
ngx.log(ngx.DEBUG, "Xml response body does not exist ")
end
end
end

Conclusion

In this way, the plugin would link every event or action to an individual customer and behavioral trends can be discovered by looking at multiple events together to identify product issues such as why users stop using your API or which features or endpoints they engage with the most.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .