Step 3: Add Permissions and Create Application

This step adds access control to your database types through GraphQL permissions and creates a Tailor application that exposes your database through a GraphQL API endpoint. This makes your data accessible to client applications while maintaining security controls.

What This Step Does

In this step, you:

  1. Add GraphQL permission policies to all three database types (User, Project, Task)
  2. Configure permissions to allow all actions for everyone (suitable for development)
  3. Create a Tailor application named project-management
  4. Configure CORS settings to allow local development access
  5. Set up IP address restrictions (allowing all IPs for development)
  6. Connect the application to the TailorDB database through a subgraph configuration

The application serves as the API gateway that client applications will use to interact with your data. The GraphQL permissions ensure that access to data is controlled and secure.

Configuration Files

To follow along, review the configuration files for this step here.

tailordb.tf (Updated)

The database configuration now includes GraphQL permission resources for each type:

<span><span style="color: var(--shiki-token-function)">resource</span><span style="color: var(--shiki-color-text)"> &quot;tailor_tailordb_gql_permission&quot; &quot;user&quot; {</span></span>
<span><span style="color: var(--shiki-color-text)">  workspace_id </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> var.workspace_id</span></span>
<span><span style="color: var(--shiki-color-text)">  namespace    </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> tailor_tailordb.prj_mgmt_db.namespace</span></span>
<span><span style="color: var(--shiki-color-text)">  type         </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> tailor_tailordb_type.user.name</span></span>
<span><span style="color: var(--shiki-color-text)">  policies </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> [{</span></span>
<span><span style="color: var(--shiki-color-text)">    actions     </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> [</span><span style="color: var(--shiki-token-string-expression)">&quot;all&quot;</span><span style="color: var(--shiki-color-text)">]</span></span>
<span><span style="color: var(--shiki-color-text)">    permit      </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&quot;allow&quot;</span></span>
<span><span style="color: var(--shiki-color-text)">    description </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&quot;allow all actions for everyone&quot;</span></span>
<span><span style="color: var(--shiki-color-text)">  }]</span></span>
<span><span style="color: var(--shiki-color-text)">}</span></span>
<span></span>
<span><span style="color: var(--shiki-token-function)">resource</span><span style="color: var(--shiki-color-text)"> &quot;tailor_tailordb_gql_permission&quot; &quot;project&quot; {</span></span>
<span><span style="color: var(--shiki-color-text)">  workspace_id </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> var.workspace_id</span></span>
<span><span style="color: var(--shiki-color-text)">  namespace    </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> tailor_tailordb.prj_mgmt_db.namespace</span></span>
<span><span style="color: var(--shiki-color-text)">  type         </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> tailor_tailordb_type.project.name</span></span>
<span><span style="color: var(--shiki-color-text)">  policies </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> [{</span></span>
<span><span style="color: var(--shiki-color-text)">    actions     </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> [</span><span style="color: var(--shiki-token-string-expression)">&quot;all&quot;</span><span style="color: var(--shiki-color-text)">]</span></span>
<span><span style="color: var(--shiki-color-text)">    permit      </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&quot;allow&quot;</span></span>
<span><span style="color: var(--shiki-color-text)">    description </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&quot;allow all actions for everyone&quot;</span></span>
<span><span style="color: var(--shiki-color-text)">  }]</span></span>
<span><span style="color: var(--shiki-color-text)">}</span></span>
<span></span>
<span><span style="color: var(--shiki-token-function)">resource</span><span style="color: var(--shiki-color-text)"> &quot;tailor_tailordb_gql_permission&quot; &quot;task&quot; {</span></span>
<span><span style="color: var(--shiki-color-text)">  workspace_id </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> var.workspace_id</span></span>
<span><span style="color: var(--shiki-color-text)">  namespace    </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> tailor_tailordb.prj_mgmt_db.namespace</span></span>
<span><span style="color: var(--shiki-color-text)">  type         </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> tailor_tailordb_type.task.name</span></span>
<span><span style="color: var(--shiki-color-text)">  policies </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> [{</span></span>
<span><span style="color: var(--shiki-color-text)">    actions     </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> [</span><span style="color: var(--shiki-token-string-expression)">&quot;all&quot;</span><span style="color: var(--shiki-color-text)">]</span></span>
<span><span style="color: var(--shiki-color-text)">    permit      </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&quot;allow&quot;</span></span>
<span><span style="color: var(--shiki-color-text)">    description </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&quot;allow all actions for everyone&quot;</span></span>
<span><span style="color: var(--shiki-color-text)">  }]</span></span>
<span><span style="color: var(--shiki-color-text)">}</span></span>
<span></span>

applications.tf (New)

This file creates the application that exposes your database through a GraphQL API:

<span><span style="color: var(--shiki-token-function)">resource</span><span style="color: var(--shiki-color-text)"> &quot;tailor_application&quot; &quot;project_management&quot; {</span></span>
<span><span style="color: var(--shiki-color-text)">  workspace_id </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> var.workspace_id</span></span>
<span></span>
<span><span style="color: var(--shiki-color-text)">  name </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&quot;project-management&quot;</span></span>
<span><span style="color: var(--shiki-color-text)">  cors </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> [</span></span>
<span><span style="color: var(--shiki-color-text)">    </span><span style="color: var(--shiki-token-string-expression)">&quot;http://localhost:8080&quot;</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)">    </span><span style="color: var(--shiki-token-string-expression)">&quot;http://localhost:8081&quot;</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)">  ]</span></span>
<span><span style="color: var(--shiki-color-text)">  allowed_ip_addresses </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> [</span></span>
<span><span style="color: var(--shiki-color-text)">    </span><span style="color: var(--shiki-token-string-expression)">&quot;0.0.0.0/0&quot;</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)">  ]</span></span>
<span><span style="color: var(--shiki-color-text)">  subgraphs </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> [</span></span>
<span><span style="color: var(--shiki-color-text)">    {</span></span>
<span><span style="color: var(--shiki-color-text)">      type      </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&quot;tailordb&quot;</span></span>
<span><span style="color: var(--shiki-color-text)">      namespace </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> tailor_tailordb.prj_mgmt_db.namespace</span></span>
<span><span style="color: var(--shiki-color-text)">    }</span></span>
<span><span style="color: var(--shiki-color-text)">  ]</span></span>
<span><span style="color: var(--shiki-color-text)">}</span></span>
<span></span>

Key Features

GraphQL Permissions

The tailor_tailordb_gql_permission resources control access to GraphQL operations on each type:

  • actions: Set to ["all"] to allow all GraphQL operations (queries, mutations, subscriptions)
  • permit: Set to "allow" to grant access
  • description: Documents the purpose of the permission policy

Application Configuration

The tailor_application resource creates an API gateway with several important configurations:

CORS (Cross-Origin Resource Sharing)

The cors field specifies which origins are allowed to make requests to your API:

<span><span style="color: var(--shiki-color-text)">cors </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> [</span></span>
<span><span style="color: var(--shiki-color-text)">  </span><span style="color: var(--shiki-token-string-expression)">&quot;http://localhost:8080&quot;</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)">  </span><span style="color: var(--shiki-token-string-expression)">&quot;http://localhost:8081&quot;</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)">]</span></span>
<span></span>

This allows frontend applications running on these local ports to access your API during development.

IP Address Restrictions

The allowed_ip_addresses field controls which IP addresses can access your application:

<span><span style="color: var(--shiki-color-text)">allowed_ip_addresses </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> [</span></span>
<span><span style="color: var(--shiki-color-text)">  </span><span style="color: var(--shiki-token-string-expression)">&quot;0.0.0.0/0&quot;</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)">]</span></span>
<span></span>

The value 0.0.0.0/0 allows access from any IP address. In production, you would typically restrict this to specific IP ranges.

Subgraphs

The subgraphs configuration connects your application to backend services:

<span><span style="color: var(--shiki-color-text)">subgraphs </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> [</span></span>
<span><span style="color: var(--shiki-color-text)">  {</span></span>
<span><span style="color: var(--shiki-color-text)">    type      </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&quot;tailordb&quot;</span></span>
<span><span style="color: var(--shiki-color-text)">    namespace </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> tailor_tailordb.prj_mgmt_db.namespace</span></span>
<span><span style="color: var(--shiki-color-text)">  }</span></span>
<span><span style="color: var(--shiki-color-text)">]</span></span>
<span></span>

This creates a GraphQL subgraph that exposes all the types and operations from your TailorDB database. The application automatically generates a unified GraphQL schema that includes all the queries and mutations for your types.

Expected Outcome

After applying this configuration with terraform apply, you should see:

  1. GraphQL permissions configured for all three types (User, Project, Task)
  2. A Tailor application named "project-management" created in your workspace
  3. A GraphQL API endpoint URL provided by the Tailor Platform
  4. The application connected to your TailorDB database namespace

You can verify the setup by:

  • Viewing the application in the Tailor Console
  • Accessing the GraphQL API endpoint (the URL will be displayed in the console)
  • Using the GraphQL playground to explore the auto-generated schema

The GraphQL API will include full CRUD operations (Create, Read, Update, Delete) for all your types, along with relationship traversal capabilities.

Next step

Continue to Step 4: Add Authentication.