In the first part of this blog series, we began a conversation on the emerging open-source API standards GraphQL and how to apply access control to a GraphQL API. We demonstrated how to validate incoming OAuth tokens in a GraphQL service and how to filter data by identity tag. So far, we have operated from the perspective of a GraphQL resolver working in conjunction with PingFederate.
Today, in this second installment of the two-part blog series, we continue down the example path of our open banking GraphQL service and introduce another layer of authorization: user privacy management and enforcement. In order to implement this, we will introduce a data governance layer to apply dynamic user privacy preferences and fine-grained access control for our GraphQL service.
Dynamic GraphQL Access Control: An Open Banking Example
Let’s consider our open banking use case: A third-party aggregator mobile app—perhaps one that provides value by aggregating data from multiple banking services—retrieves account-related information on behalf of a banking customer. That customer likely will want to restrict the information their bank shares with the third-party app. (Keep in mind that third-party information sharing controls is a common requirement not only in banking but in many consumer-facing applications.)
In our scenario, the customer might be uncomfortable sharing, for example, the identifier of the bank accounts and the bank’s branch identifier. By default, this information would not be justified for use by a third-party app. In cases where we want to hide these details, a convenient field “nickname” lets the third-party aggregator app refer to a specific account in a way that is meaningful to the end user. However, for certain advanced use cases, the actual account and branch identifiers might be required, or the end user might prefer to see these identifiers appear in the third-party app. Putting a user in control of this type of choice is often warranted—not only for improving user experience but also as required by regulations.
This type of privacy preference would be configurable with the banking service (in our use case, the same party as the GraphQL service provider) via its customer portal. These privacy-preference choices have a clear mapping from a GraphQL API schema perspective, as illustrated below:
A bank’s portal privacy end-user settings mapped to GraphQL schema elements
One way to approach this problem might be to adjust the schema presented to the client-side app developer at design time. However, as described by the use case, the privacy choices are in the end users’ control. Some users might want to allow these, some might not. Some users will change these settings over time.
This consideration is therefore not design time. The decision as to whether to include this information must happen at runtime and must override the requesting application’s query if needed. Rather than show/hide the existence of these fields in the GraphQL schema at design time, the app developer should instead be made aware that these values might be missing or redacted. This allows the client-side app developer to take that into consideration when developing the application.
The inclusion or exclusion of this data in the response becomes a new fine-grained access control decision that needs to be applied at runtime. These server-side decisions are independent of the client-side app’s GraphQL query and instead are driven by the end user’s privacy settings. If a client-side app makes a query that includes, for example, the account’s owner attributes but the end user’s privacy settings are currently set to not make that information available to the app, the resulting response should reflect the privacy settings and not include this sensitive information, as illustrated below:
The GraphQL query is trumped by privacy settings
PingDataGovernance for GraphQL Services
Implementing this new decision making and data redaction for our GraphQL service can be done independently from the GraphQL service’s implementation code. This implementation does not necessarily need to change to adapt to this new authorization requirement. Let’s explore a way to implement this new requirement as part of the API infrastructure, on behalf of the GraphQL service implementation code.
PingDataGovernance provides policy-based, fine-grained access controls for data protection that can be applied to existing GraphQL services without disrupting the existing service. PingDataGovernance lets the administrator define rules in a centralized policy decision point, and apply the rules by running as a sideband to an API gateway or as a reverse proxy to your GraphQL service directly.
User privacy settings can be read by PingDataGovernance from the same system that is used by the bank’s end-user portal. PingDataGovernance has the flexibility required to retrieve the information regardless of its format and origin. This can come from a database, an LDAP directory or a REST API.
Because it has access to the incoming OAuth token from the GraphQL query, PingDataGovernance can leverage identity attributes to retrieve the privacy settings relevant to the specific end user for which the query is being processed—whether the identity attributes are part of a signed token or are retrieved from a token introspection endpoint.
The privacy settings are then declared as attributes in PingDataGovernance’s trust framework. You can choose to retrieve these privacy settings at each enforcement, or you can configure PingDataGovernance to maintain its own version of those settings in a local cache for performance tuning, as illustrated below:
Retrieval of privacy settings via PingDataGovernance’s Trust Framework service attributes
With these privacy settings now available to PingDataGovernance, we can define a policy that will redact outgoing responses to reflect privacy settings the user has selected. The screenshot below shows PingDataGovernance’s Policy Editor defining such a rule leveraging privacy preferences captured earlier:
The GraphQL response redaction policy in PingDataGovernance
Using the rule exclude-attributes will remove the respective data from the response, whereas the rule modify-attribute lets PingDataGovernance alter the value of these fields so that the client-side application receives a modified value for these attributes rather than simply removing it. Either way of transforming the response honors the banking customer’s privacy preferences. The approach selected should reflect the desired developer experience and the externally facing developer documentation for the GraphQL service.
Partial GraphQL responses for data deletion vs data substitution policies
Once the policy is saved in PingDataGovernance, the GraphQL traffic passing through it (or via an API gateway) will start reflecting user privacy preferences. No changes to the GraphQL implementation are needed and no service disruptions are experienced. Without a specialized tool like PingDataGovernance, a similar logic would need to be coded in the GraphQL service itself.
The decoupling of privacy preference management and enforcement from a GraphQL service implementation offers a number of benefits. Home-grown software has its cost of ownership and can be slow to adapt. The personae of the Node.js developer and the personae responsible for enforcing privacy regulations seldom intersect. Empowering security architects and business analysts with their own tool to implement this level of access control accelerates digital transformation. In addition, this decoupling future-proofs the investment in GraphQL services by making them more resilient to changes as they relate to fine-grain data governance.
Centralized Data Access Governance
Banks are forced to adapt to trends and regulations. Their legacy infrastructure needs to accommodate new open banking use cases. Similarly, the GraphQL service that you are building today will need to adapt to its own changing use cases tomorrow. Implementing a fine-grain data governance layer, decoupled from the service implementation, makes this possible. PingDataGovernance provides a centralized solution to authorize and filter data flowing through GraphQL services in real time.