ContentGrid Documentation

Introduction

ContentGrid is a modern highly-scalable Content Services Platform. ContentGrid allows you to design, deploy, manage and iterate on content-centric applications, enabling users to retrieve and work with content in a modern, seamless and secure way, across devices and organizational boundaries.

This documentation describes ContentGrid Console concepts, the problems it solves, and contains quick-start tutorials for using ContentGrid.

Subsections of ContentGrid Documentation

Concepts

Console

The ContentGrid Console is a management interface for the ContentGrid platform. It provides a web-based user interface to manage your ContentGrid Projects, Applications and more.

The Console is available at https://console.contentgrid.com

Organizations

An Organization is a top-level concept. Every operation within ContentGrid, happens in the context of an Organization.

ContentGrid Organizations are used to:

Projects

A Project belongs to an Organization and contains:

Your Users will use the deployed Applications.

Members

Members are project administrators for an Organization. They can create new Projects, collaborate on Blueprints, manage Applications and IAM Realms

Note that members are not Users. A User does not need to be a member of your Organization to access an Application.

At this time, members cannot be assigned different roles or permissions. Every member is effectively an organization and project administrator.

Blueprint

A blueprint is the design area of a Project. It describes the full model of an application, including the Data Model, Permissions and any Automations. This model determines how the data is stored in the database, how the REST API is structured and how automations are integrated.

A Release can be created from a Blueprint.

Creating a new version of an active application means making changes in the Blueprint and creating a new Release before deploying this release to a running Application.

A Project has a Blueprint called main.

A Blueprint does not contain any application- or user-data.

TIP: If you are wondering where application- & user-data is stored, see: storing-data.

Release

A Release is an immutable snapshot of a Blueprint and is the artifact that can be deployed to an Application.

A Release is created from the current Blueprint. It has a release-label, like v1.2.3 and optionally a short description. A Release follows a chronological previous Release and belongs to a single Project.

Data Model

The data model is a logical abstraction of concepts from the real world. The data model contains Entities with Attributes and Relations between Entities.

Entities

An Entity represents an object or concept in the digital world. It can represent a physical object, like a product or an invoice-document, or a virtual concept, like an online order.

Attributes

An attribute is a single characteristic of an Entity. An attribute has a data type, such as text, number or date. A file is stored as a special attribute type called content. For example, the attributes for an invoice could be number, amount and document.

Relations

A relation is a named link between two Entities in the Data Model.

Entities can have a one-to-one, one-to-many, many-to-many or many-to-one relationship with another entity. For example, an invoice has a many-to-one relationship with the customer entity: many invoices can have a reference to the same customer.

A relation can be optional or required.

Permissions

Permissions govern under what conditions Entities are visible for a principal (a User or Service Account). They are made up of a collection of Policies per Entity.

ContentGrid uses an Attribute Based Access Control (ABAC) system. This means that a set of rules define access, using attributes of the principal issuing a request and attributes of the Entities being acted upon.

Permissions are deny-by-default.

Policies

Policies are a set of rules, that specify a the conditions under which Operations are allowed on an Entity. A policy always applies to a single Entity.

Under normal circumstances, every Entity gets a Policy. In the absence of any Policies for an Entity, all Operations on this Entity are disallowed for everyone.

One Entity can have multiple Policies, that are inclusively disjunctive. In other words, the policies are combined with “OR” logic: a request is allowed if the conditions of Policy A OR Policy B are satisfied.

Operations

Operations are actions that a principal (a User or Service Account) can perform on an Entity.

The available actions are Read, Create, Update, Delete. A policy can cover one or more operations.

Policy Conditions

Policy Conditions specify additional requirements that must be met, before an operation is allowed. They are like extra security checks that ensure that only the right people can access your Entities or perform actions on them. For a policy to allow something, all conditions in that policy must pass.

A policy without conditions allows the selected operations for all logged-in users.

Automations

Webhooks

Webhooks provide a way to configure a ContentGrid Application to send notifications to external systems whenever certain changes occur.

When a mutating operation is performed (for example, a user created a document), an HTTP request is sent to the configured endpoint, with a payload describing the change. Every operation is handled individually and asynchronously. Delivery of webhook events are usually in chronological order, but in-order delivery is not guaranteed.

A webhook receiver needs Service Account credentials, if it wants to call the REST API of the Application.

Applications

Applications are running instances of a Project. An Application is created in a Zone. After creating the Application, a Releases can be Deployed to an Application.

A Project can have multiple active Applications, possibly representing different environments or to try out different Releases.

Each Application is linked to one IAM Realm. The first time an Application is created in a Zone, a default IAM Realm is created for the Organization in this Zone.

Zones

A Zone is the deployment target of an Application and maps to the geographical location of a cloud provider that runs ContentGrid Applications.

An Organization creates an Application in a given Zone.

Currently there is one zone available: Scaleway Paris

Deployments

A Deployment is the rollout of a specific Release to an Application.

Once a Release is deployed, the Application provides a REST API to store, retrieve and manipulate data.

IAM

IAM (Identity and Access Management) is the system that manages User-accounts for ContentGrid Applications.

Realms

A Realm or IAM Realm contains a collection of Users, Groups and their attributes. Applications are linked to an IAM Realm to authenticate Users and Service Accounts.

Multiple Applications, across Projects but within the same Organization, can be connected to the same IAM Realm.

When an Application is created in a Zone for the first time, an IAM Realm gets automatically provisioned.

Users

IAM Users are human principals that interact with Applications.

Users are identified by their email address. Users can be a assigned to one or more Groups. Groups can have attributes and are recommended way to organization Permissions.

NOTE: an Organization Member is not automatically a User of an Application.

Groups

IAM Groups allow you to organize Users based on shared characteristics.

Groups have a collection of user memberships and a set of Attributes. For the purpose of permission evaluation, users inherit attributes from the groups they are a member of. For example, you might create a group for all users in the accounting department, so you set the group’s department-name attribute to “accounting”, so that you can create a permission policy for invoices that checks what department a user belongs to.

These attributes are defined in the IAM Attribute Model.

Attribute Model

The IAM Attributes describe a set of properties for Groups. The purpose of this model is to describe the information that can be used in permissions. Users inherit properties from the groups they are member of.

It is similar to defining Attributes for an Entity in the Datamodel, but is not part of a Blueprint.

An attribute has a name, a data type and can be single- or multi-valued. For instance, if you want to be able to write permission policies that allow access to admins, you should define an is-admin attribute of type boolean.

Service Accounts

A Service Account is a non-human principal in an IAM Realm. A Service Account can acquire an access token, to interact with the REST API of an Application.

Service Accounts are useful for programmatic integrations with the REST API. For example, a Webhook receiver may call back into the REST API to update a status field, but it needs to be authenticated to do so.

At this moment, it is not possible to create Service Accounts in the ContentGrid Console.

Guides

ContentGrid has 2 main web interfaces. One of them for managing applications, is called the Console. The web UI for using ContentGrid applications is called Navigator.

Console

The Console enables you to create projects, model blueprints and deploy applications.

Navigator is the out-of-the-box end user interface for every ContentGrid applications and allows you to create, search, consult and delete entities.

Subsections of Guides

Subsections of Console

Getting Started

Get started with Data Modeling

Before creating a data model, you need to create a project.

You can do that with the “Create Project” button on the organization page:

Create Project Button Create Project Button

In the pop-up dialog you can give your project a name:

Create Project Dialog Create Project Dialog

Next, you have to select a blueprint to work with:

Select Main Blueprint Select Main Blueprint

Data modeling

Now you can start the data modeling by clicking the Data model menu item:

Data Model Menu Data Model Menu

In the Data model tool you can model your business entities. You start by creating your first “Entity” by clicking the “Add Entity” button and give it a name.

Add Entity Add Entity

Now that you created your first entity, you’ll see that you can still edit the name of the entity or delete it.

An entity can have attributes and relations to other entities. When you create an attribute in an entity a dialog will pop up with a few options:

Add Attribute Add Attribute

Attribute options:

  • Property Name: A unique name within the entity.
  • Type: The data type for this attribute.
    • Text
    • Integer
    • Decimal
    • Boolean
    • Date
    • Content: Binary object or file
  • Use as ID: This checkbox can be checked if you want the value of this attribute to be used as the identifier of the entity. This also means that the attribute must be unique, required and searchable.
  • Values must be unique: When this checkbox is checked, the value for this attribute must be unique. Creating duplicate values will be prevented.
  • Values are required: With this checkbox enabled, adding a value for this attribute is mandatory, otherwise the entity cannot be created.
  • Values are searchable: Enabling this options makes sure that the values are indexed and therefore searchable.

You can also model relationships to other entities, or even to the same entity. To add a new relation to the entity, click the “Add Relation” button, and you will see a pop-up dialog:

Add Relation Add Relation

When adding a relation, you have some options to configure:

  • Name: The name of the relationship
  • From: Will be prefilled with the current entity
  • To: Entity where this relationship is going to
  • Checkboxes:
    • Relationship is required
    • checkboxes to indicate the cardinality of the relationship

Permission Policies

Permission Policies

ContentGrid takes a different approach to permissions than legacy content management systems. Instead of making a complex hierarchical tree structure of permissions with inheritance, a set of permission policies describes access for each entity. These policies are rules that contain logical expressions, making use of (a combination of) entity attributes and user attributes.

How to create a Policy

First, go to the Permissions modeler:

Permissions Permissions

To create our first policy, we first have to choose the entity for which we are going to create a policy:

Select Entity Select Entity

When clicking the “Create Policy” button you will see the configuration options for creating a new policy:

Create Policy Create Policy

First, you’ll have to choose for which operation this policy will be evaluated. The options are: Read, Create, Update, Delete. You can choose one or more operations.

By choosing the visibility setting, you can define if this policy is applicable for authenticated users only, or for all users.

The “Additional conditions” section is where you define the conditions for this policy, access to the entity is granted when the conditions are fulfilled.

Multiple conditions can be applied, and each rule has a left and a right side, that are compared to each other. Both left and right sides of can be a “user attribute”, “entity attribute” or constant. The possible comparisons between the left and the right side are:

  • equals
  • not equals
  • greater than
  • greater or equals
  • less than
  • less than or equals
  • contains
  • in

You can add more conditions with the “Add Condition” button. All conditions have to be satisfied before a policy grants access. Save the policy with the “Add Policy” button.

Now, you should see your policy for this entity in the overview.

Policy Overview Policy Overview

Webhooks

Tutorial on webhooks

Webhooks are one way that ContentGrid applications can send automated messages or information to external systems. They are almost always faster than polling, and require less work on your end.

Each mutating operation on an resource is handled individually and is asynchronously, but almost immediately delivered to the configured webhook endpoint.

A ContentGrid Webhook

  • is always attached to a ContentGrid entity and selected change triggers
  • is delivered to a configured HTTP endpoint
  • is delivered as a HTTP POST message with a body payload and specific ContentGrid HTTP headers

Create New Webhook?

First, go to the Webhooks modeler:

Webhooks Webhooks

To create our first Webhook, we first have to click on Create Webhook:

Create Webhook Create Webhook

When clicking the “Create Webhook” button you will see the configuration options for creating a new Webhook:

Create Webhook Options Create Webhook Options

  • First, you will have to give a satisfying Webhook name (or description).
  • Then you have to choose for which entity this Webhook will be applied
  • After the entity selection, select the notifications triggers, where the options are
    • create (whenever the selected entity type is created)
    • update (when each existing entity is being updated)
    • content (when a document content has been changed)
    • delete (when the enetity selected has been deleted)
  • As a last step, you have to provide the Webhook URL to be invoked by your ContentGrid application

Webhooks sample Webhooks sample

After clicking save, the Webhook is saved and is listed in the overview but will only be available to your ContentGrid runtime application once you create a new release.

Webhooks listing Webhooks listing

You can add more Webhooks with the “Create Webhook” button.

Webhook endpoint

A Webhook endpoint has some specific constraints and must respect the following implementation details:

  • it has to support the HTTP POST method
  • should accept a JSON body and application/json Content-Type
  • can use our ContentGrid HTTP headers in order to validate that the delivered message is coming from our platform
    • User-Agent value is ContentGrid-Slingshot/APP_VERSION
    • ContentGrid-Application-Id contains the application id
    • ContentGrid-Deployment-Id contains the deployment id
    • ContentGrid-Signature provides a JWT signed by the our platform that should be used in order that the message is actually sent by the ContentGrid platform

Security and validation

ContentGrid signs JWTs using asymmetric encryption (RS256), and publishes the public signing keys in a JWKS (JSON Web Key Set).

The signing keys are rotated on a regular basis.

  • We discourage doing manual JWT validation since it might be easy to improperly implement and miss some important details that will lead to serious security vulnerabilities. Most JWT libraries take care of JWT validation for you.
  • We also highly recommend to use a JWK library for the programming language of your choice.

One of the benefits of JSON Web Token (JWT) is that you can validate a token using an easy cryptographic operation.

What are JWKs?

A JSON Web Key (JWK) is a JSON data structure that represents a cryptographic key. JWKs are a set of keys shared between different services and are used to verify the JWT token from the authorization server.

You should only be validating the received JWT against ContentGrid Json Web Key (JWK) URL which is ${CONTENTGRID_URL}/.well-known/jwks.json

We use JWKS to expose the public keys used by the ContentGrid platform to all the clients required to validate signatures.

For more information you can check the JWK RFC

The example of a JWKS is something that looks like this:

{
  "keys": [
    {
      "use": "sig",
      "kty": "RSA",
      "kid": "UVelusmvyM2xScEu0F_xSNlhelC5jZTD77R_3mmOZXs",
      "alg": "RS256",
      "n": "...yjXzcFpbMJB1fIFam9lQBeXWbTqzJwbuFbspHMsRowa8FaPw44l2C9Q42J3AdQD8CcN...",
      "e": "AQAB"
    },
    {
        ...
    }
  ]
}

In the above example some important fields are

  • e: is the exponent for a standard pem
  • n: is the moduluos for a standard pem
  • alg: the signing algorithm.
  • kid: a unique id for every key in the set.

ContentGrid’s JWT headers and claims:

{
  "kid": "UVelusmvyM2xScEu0F_xSNlhelC5jZTD77R_3mmOZXs",
  "alg": "RS256"
}.{
  "aud": "https://webhooks-demo.rtp-scw-sandbox.contentgrid.cloud/broker-process",
  "exp": 1679044765,
  "iat": 1679044465,
  "jti": "df475d5a-fc0e-4fca-a03a-c279e86fe9ed"
}.[Signature]
  • kid: is Identifier of the static key used to sign the JWT
  • alg: Algorithm used to sign the key
  • aud: Recipients that the JWT is intended for (the CG Application URL)
  • iat: The issuing time of the token in seconds
  • exp: The expiration time of the token in seconds
  • jti: Unique identifier of the token

Get the signing keys

Here is a Java exmaple of how to validate a JWT using JWKs with Nimbus JOSE + JWT

  • To validate the token, first, you need to get the JSON web key set from the JWKs endpoint. The token will be received as JSON in the validation endpoint in the body.
ResourceRetriever jwkSetRetriever = new DefaultResourceRetriever();
JWKSource<SecurityContext> jwkSource = new RemoteJWKSet<>(URI.create("${CONTENTGRID_URL}/.well-known/jwks.json").toURL(), jwkSetRetriever);
JWSKeySelector<SecurityContext> jwsKeySelector = JWSAlgorithmFamilyJWSKeySelector.fromJWKSource(jwkSource);
  • Additional validation for token claims
ConfigurableJWTProcessor<SecurityContext> jwtProcessor = new DefaultJWTProcessor<>();
jwtProcessor.setJWSKeySelector(jwsKeySelector);

jwtProcessor.setJWTClaimsSetVerifier((claims, context) -> {
	final Date now = new Date();			
	final Date exp = claims.getExpirationTime();
	if (exp != null) {
		if (now.after(exp)) {
			throw new BadJWTException("expired");
		}
	}
});	
  • and the JWT validation
SignedJWT signedJWT = SignedJWT.parse(THE_JWT);	
jwtProcessor.process(signedJWT, null);

This short guide provides the basic steps required to locally verify an access or ID token signed by ContentGrid. It uses packages from Nimbus JOSE + JWT for key parsing and token validation, but the general principles should apply to any JWT validation library.

Navigator

ContentGrid Navigator is the out-of-the box frontend for you ContentGrid application. The interface will adapt automatically to the entities and attributes you have configured.

Overview

An overview of the different UI elements of Navigator.

Create entity

Guide on how to create new entities with metadata and relations.

Subsections of Navigator

Navigator overview

Navigator overview Navigator overview

(1) Entity menu

The entity menu allows you to select an entity type for search and creation. The selected entity is highlighted.

(2) Search form

In the search form you can search on the searchable metadata of the entity and it’s related entities, as defined in the Console.

(3) Results table

The results table shows up after search and displays the search results as a table with metadata. Clicking one of the lines in the table will open the document preview.

(4) Create entity button

Clicking the create entity button will bring you to create form where you can fill in the metadata, files and link the relations for this entity.

(5) Document preview

The document preview will display a preview of the line selected in the results table. If there are multiple files attached to that entity, there will be a dropdown selector to choose what file you want to preview.

Info

The previewer can natively show PDF’s and images. For other documents, ContentGrid will attempt to transform the file to PDF. Currently, these formats are supported for previewing:

  • pdf
  • jpg, png
  • doc, docx, ppt, pptx, xls, xlsx
  • odt, ods, odp

Of course, other file formats can still be used in ContentGrid, but they don’t have out-of-the-box previews.

Creating entities

Create entity Create entity

(1) Create form

In the create form you can fill in the metadata fields of the entity you are creating. Mandatory fields are indicated with an asterisk. Datetime fields have a datetime picker. Content fields support drag and drop and opening a file picker.

(2) Relation field

If your entity has a relation to another relation, you will see that in the form. The link data button will bring you to the link relation popover where you can link the correct entities.

(3) Extract button

The extract button will open a pop-up to start an automated metadata extraction using AI based on the files you already uploaded in the form.

(4) Create/cancel buttons

These buttons allow you to submit or cancel the entity creation.

(5) Document preview

The document preview allows you to see the documents added next to the form. This can be practical when you need to read data from the document to fill in the form. The extract feature will also overlay information in the preview when used.

After clicking the link data button in the create form a popover will appear that will help you link related entities.

Add relation Add relation

(1) Search form

The search form in this popover functions similarly to the entity search form and searches on the linked entity.

(2) Result table

After pressing the “SEARCH” or “SHOW ALL” button, the results table shows the candidates for linking. Just click a line to link the entity. It is possible to link multiple entities if it is a “TO MANY” relationship.

(3) Create button

This button will open a new tab on the create form of the entity type you are trying to link. Use this when the entity you want to link does not yet exist.

Reference Docs

Subsections of Reference Docs

How ContentGrid stores data ?

Storing data

Permissions Reference

Permissions Reference

Permissions in ContentGrid operate on the level of entities. By default, all permissions are denied and you cannot read or write any data. In order to grant a permission, you must define a policy. A policy is created for a particular entity and states that certain operations are allowed on that entity under certain conditions. For instance, a policy might say that the read operation is allowed on the invoice entity if the user has the bookkeeping attribute.

Operations

The currently supported operations are:

  • Create: The creation of an entity. Policies involving entity attributes are evaluated against the attributes that you send. This corresponds to http POST.
  • Read: Covers both reading a specific entity referred by id, as well as listing all visible entities. If you’re getting an entity by id but you don’t meet all the conditions, you will get a “Not Found” error. If you’re listing all entities, the list will be filtered down to the entities for which you meet the conditions. This corresponds to http GET and http HEAD.
  • Update: Updating the attributes and relations of an entity. If there are policies specifying conditions on the attributes, you must meet the conditions both before and after the update to the attributes. This corresponds to http PUT and http PATCH.
  • Delete: Deleting an entity. This corresponds to http DELETE.

Conditions

A policy has a list of conditions. If this list is empty, the operation in the policy is simply allowed. Otherwise, all the conditions have to match for the policy to allow access.

For instance, you can have two policies for the blog entity. The first policy has the operation READ and no conditions. The second policy has the operations CREATE and UPDATE, but also has a condition stating that the user must have the blogger attribute equal to true. The consequences of these policies are that anyone can read (and list) blog entities, but only people marked as bloggers can write them.

A condition consists of three parts:

  • A left value: This is the value that you want to check. It can be an entity attribute, a user attribute, or a constant.
  • A comparison operator: This is the symbol that defines the type of comparison you want to make. For example, if you want to check whether the left value is equal to the right value, you would use the equals operator. If you want to check whether the left value is a list that contains the right value, you would use the contains operator.
  • A right value: This is the value that you want to compare the left value to. It can be an entity attribute, a user attribute, or a constant.

Types of Values

There are three types of values that can be used in a condition:

  • Entity attribute: This refers to an attribute of the entity being accessed, or to an attribute of an entity that has a relation to the entity being accessed. For example, if you have a policy that controls access to a report, you could use the report’s confidentiality level as a value. If you have a policy that controls access to an employee’s information, you can use the employee’s relation to their department to ensure that only people in a particular department are visible.
  • User attribute: This refers to a characteristic of the user who is trying to access the resource. For example, if you have a policy that controls access to files private to a particular department, you can verify that the user is a member of the department to which the file belongs.
  • Constant: This is a fixed value that you define in the condition. It can be of subtype boolean, number, or string. It is useful as the right value side of a comparison where the left value is an entity attribute or user attribute. For example, if you have a policy that says admins can see everything, you could use a constant value of true as the right value in a condition where the left value is user.is_admin.
Some examples
  • Allowing access to users of certain department: user.department equals "Sales"
  • Allow access when attribute category has a certain value: entity.category equals "Published"
  • Allow access where attribute vat matches the user attribute: entity.vat equals user.vat
  • Following the relation belongs_to to party, using the attribute department on party: entity.belongs_to.department equals "Bookkeeping"

Types of comparison operators

These are the comparison operators that you can use in a condition:

  • equals (=)
    • Used for any type of value, to check that the left value is equal to the right value
  • not equals (≠)
    • Used for any type of value, to check that the left value is different from the right value
  • greater than (>)
    • Used for numeric types or date types, to check that the left value is greater (or later in time) than the right
  • greater or equals (≄)
    • Used for numeric types or date types, to check that the left value is greater or equal (or later in time) than the right
  • less than (<)
    • Used for numeric types or date types, to check that the left value is smaller (or earlier in time) than the right
  • less than or equals (≀)
    • Used for numeric types or date types, to check that the left value is smaller or equal (or earlier in time) than the right
  • contains (∋)
    • Used with a collection as the type of the left value, to check that the right value appears in the collection
  • in (∈)
    • Used with a collection as the type of the right value, to check that the left value appears in the collection