Open Policy Agent
This tutorial uses the FormKiQ Open Policy Agent module to demonstrate how to protect documents using access attributes.
What You Will Build
You will create a user and Cognito group, configure an OPA policy, add documents with different access attributes, and compare document access for an admin user and a restricted user.
The code for the tutorial can be found within the FormKiQ Github Tutorials
Before You Begin
-
A text editor or IDE - for example IntelliJ IDEA
-
Access to a FormKiQ Advanced/Enterprise installation
-
The
HttpApiUrlfound on the CloudFormation Outputs tab -
A User JWT Authentication Token
-
An Admin JWT Authentication Token
Workflow Overview
- Create a test user and Cognito group.
- Configure Java API clients for admin and user tokens.
- Add an OPA policy.
- Create documents with different access attributes.
- Run access checks as admin and user.
- Verify the expected access decisions.
Step 1: Create User
Goto the Cognito Console and find your FormKiQ user pool and click the Create user button.
Filling create user form and clicking and click the Create user button will send a welcome email with a link that will allow you to set the password for the user.

Next, we will create a Cognito group that will be used in our OPA policy to restrict access to certain documents.
Clicking the Groups tab and then clicking the Create group button will allow us to create a group called opa.

Next we will add the default and opa group the newly created user.
You will find the newly created user in the Users tab and clicking on the user will show the groups the user belongs to.

Clicking the Add user to group will show a list of groups you can add the user to. Add the user to the default and opa group.

You should now see the default and opa group listed under the user's membership.

Step 2: Configure the FormKiQ Client Library
FormKiQ has a client library available in Java and Python which makes communicating with the FormKiQ application easier.
This tutorial will be using the Java API and requires a client of version 1.14.0 or greater, but we will also reference the REST API endpoints used.
Setup API
The Java API requires the creation of a ApiClient which requires a JWT AccessToken and the FormKiQ url of the FormKiQ instances to use.
-
The HTTP_API_URL can be found from the "Outputs" tab of the CloudFormation console
-
A JWT Authentication Token can be aquired using this how-to.
The code sample supports ADMIN and USER access token, so the step above should be repeated for both a USER and an ADMIN user.
private static final String ADMIN_ACCESS_TOKEN = "<ADMIN_ACCESS_TOKEN>";
private static final String USER_ACCESS_TOKEN = "<USER_ACCESS_TOKEN>";
private static final String HTTP_API_URL = "<CloudFormation Outputs HttpApiUrl>";
The API is broken into sections. In this case, we will need to use the DocumentWorkflowsApi, RulesetApi, and DocumentsApi. These APIs can be instantiated as follows:
/**
* Setup API classes.
*/
public void setUpApi() {
// Setup User API access
ApiClient userClient = (new ApiClient()).setReadTimeout(0).setBasePath(HTTP_API_URL);
userClient.addDefaultHeader("Authorization", USER_ACCESS_TOKEN);
userDocumentsApi = new DocumentsApi(userClient);
// Setup Admin API access
ApiClient adminClient = (new ApiClient()).setReadTimeout(0).setBasePath(HTTP_API_URL);
adminClient.addDefaultHeader("Authorization", ADMIN_ACCESS_TOKEN);
adminDocumentsApi = new DocumentsApi(adminClient);
adminControlApi = new AccessControlApi(adminClient);
}
Step 3: Add an OPA Policy
We will now configure an OPA policy that will restrict users with the "opa" role to only be able to access documents that have an access attribute of "documentType" = "invoice".
The following policy shows how this can be implemented using OPA.
package formkiq
import future.keywords.if
import future.keywords.in
default allow := false
allow if {
"opa" in input.user.roles
data.documents.documentType = "invoice"
}
By converting the policy above to a String object, you can use the AccessControlApi to set the OpaConfiguration.
String policy = "...";
adminControlApi.setOpaConfiguration(new SetOpaConfigurationRequest().siteId(siteId).policy(policy));
The REST API endpoint PUT /sites/opa/accessPolicies can be used to set the OPA policy
Step 4: Add Documents
Finally, we will add three documents:
-
one document will have a access attribute of "documentType" and string value of "invoice"
-
one document will have no access attributes
-
one document will have a access attribute of "documentType" and string value of "bill"
private String addDocument(String siteId, String path, String content, String contentType,
List<AddAccessAttribute> accessAttributes) throws ApiException {
AddDocumentRequest req = new AddDocumentRequest().path(path).content(content).contentType(contentType)
.accessAttributes(accessAttributes);
String documentId = adminDocumentsApi.addDocument(req, siteId, null).getDocumentId();
if (accessAttributes == null || accessAttributes.isEmpty()) {
System.out.println("added document " + documentId + " without access attributes");
} else {
System.out.println("added document " + documentId + " with access attributes");
}
return documentId;
}
// Create document with Access Attribute 'documentType'
AddAccessAttribute accessAttribute0 = new AddAccessAttribute().key("documentType").stringValue("invoice");
String documentId0 = app.addDocument(siteId, "protected.txt", "my protected content", "text/plain",
Arrays.asList(accessAttribute0));
// Create document without Access Attributes
String documentId1 = app.addDocument(siteId, "unprotected.txt", "my unprotected content", "text/plain",
null);
// Create document with different value for Access Attribute 'documentType'
AddAccessAttribute accessAttribute2 = new AddAccessAttribute().key("documentType").stringValue("bill");
String documentId2 = app.addDocument(siteId, "protected2.txt", "my protected content2", "text/plain",
Arrays.asList(accessAttribute2));
Verify the Result
Running the application, you will receive an output similar to the following, expect the documentIds will change.
added document e234f1eb-33a7-46a1-aa1c-aaeb54e823ff with access attributes
added document 467a0982-85a7-4b3b-bfda-8e85ab9107fc without access attributes
added document 68e787a5-c745-4168-ab7c-def8ea53c911 with access attributes
document e234f1eb-33a7-46a1-aa1c-aaeb54e823ff has access attributes
document 467a0982-85a7-4b3b-bfda-8e85ab9107fc has NO access attributes
document 68e787a5-c745-4168-ab7c-def8ea53c911 has access attributes
user has access to document e234f1eb-33a7-46a1-aa1c-aaeb54e823ff
user access denied to document 467a0982-85a7-4b3b-bfda-8e85ab9107fc
user access denied to document 68e787a5-c745-4168-ab7c-def8ea53c911
admin has access to document e234f1eb-33a7-46a1-aa1c-aaeb54e823ff
admin access denied to document 467a0982-85a7-4b3b-bfda-8e85ab9107fc
admin access denied to document 68e787a5-c745-4168-ab7c-def8ea53c911
As you can see, first we created document e234f1eb-33a7-46a1-aa1c-aaeb54e823ff that has the access attribute documentType=invoice, while document 467a0982-85a7-4b3b-bfda-8e85ab9107fc has no access attributes, and document 68e787a5-c745-4168-ab7c-def8ea53c911 has access attribute of documentType = bill.
The user we created in first step has access to document e234f1eb-33a7-46a1-aa1c-aaeb54e823ff because their roles and access attributes match the OPA policy.
The user does not have access to document 467a0982-85a7-4b3b-bfda-8e85ab9107fc because the document has no access attributes. The user also does not have access to document 68e787a5-c745-4168-ab7c-def8ea53c911 because the documentType is "bill" and not "invoice", following our OPA policy.
The admin will have access to all three documents, regardless of the OPA policy.
Clean Up
Remove the test user, Cognito group, OPA policy, and test documents if they are no longer needed.
Troubleshooting
| Problem | Likely cause | What to check |
|---|---|---|
| User can access too much | OPA policy allows the role or access attribute unexpectedly. | Review role names and policy conditions. |
| User cannot access expected document | Access attribute value does not match the policy. | Confirm documentType=invoice on the document. |
| Policy update fails | Admin token or OPA module access is missing. | Confirm the admin JWT and module availability. |