How do I make sure Users have access to only their own Documents and BLOBs?

The best way to ensure that Users have access to only their own Documents or BLOBs is to implement Ownership. Ownership is the mechanism which allows applications to specify an owner per Document or BLOB. Once a User is assigned as a Document’s Owner, any member of a Group that has Document access with that Owner (with self, .*, or the specific Owner User ID) in the Group’s policy can access that Document. Ownership resource types in Groups make this kind of access possible.

This guide will demonstrate the steps needed to implement Ownership in an application. Using manual API calls, we will set up a simple Doctor and Patient app. The Patient Users can search and view only their data, whereas Doctors can search and view all Patient data. We focus on Documents in this example, but the same operations can be applied to BLOBs.

To perform all requests, you can use a Full Admin user which has full access to your account. For instructions on creating a Full Admin user, see the TrueVault Quick Start Guide.

Application Structure

For this example application, we will create two Patient Users (Bob and Susie) and one Doctor User. We will populate a Vault with patient data. For simplicity’s sake, Patient Documents will contain only first_name and last_name fields. Patient Users will be allowed to search and read only their own data within the Vault, whereas Doctor Users will be allowed to search and read all Patient Documents.

We will build the application using Ownership to control access to these Documents. This allows us to conveniently store all Patient Documents in one Vault using one Schema, without sacrificing access restriction flexibility.

Application Setup

Create a Vault

First we need to create the Vault that all Patient Documents will be stored in:

Request
curl https://api.truevault.com/v1/vaults \
    -X POST \
    -u ${ADMIN_API_KEY}: \
    -d "name=doctor_patient_example"
Response
{
    "result": "success",
    "transaction_id": "00000000-0000-0000-0000-000000000000",
    "vault": {
        "id": "00000000-0000-0000-0000-000000000000",
        "name": "doctor_patient_example"
    }
}

For more information on using Vaults, see our Vaults API documentation.

Create a Schema

In order to search the Patient Documents, we must create a Schema.

Schema
{
    "name": "patient_document",
    "fields": [
        {
            "name": "first_name",
            "index": true,
            "type": "string"
        },
        {
            "index": 1,
            "name": "last_name",
            "type": "string"
        }
    ]
}
Request
curl https://api.truevault.com/v1/vaults/${VAULT_ID}/schemas \
    -X POST \
    -u ${ADMIN_API_KEY}: \
    -d "schema=ewogICAibmFtZSI6ICJwYXRpZW50X2RvY3VtZW50IiwKICAgImZpZWxkcyI6IFsKICAgICAgewogICAgICAgICAibmFtZSI6ICJmaXJzdF9uYW1lIiwKICAgICAgICAgImluZGV4IjogdHJ1ZSwKICAgICAgICAgInR5cGUiOiAic3RyaW5nIgogICAgICB9LAogICAgICB7CiAgICAgICAgICJuYW1lIjogImxhc3RfbmFtZSIsCiAgICAgICAgICJpbmRleCI6IHRydWUsCiAgICAgICAgICJ0eXBlIjogInN0cmluZyIKICAgICAgfQogICBdCn0="
Response
{
  "result": "success",
  "schema": {
    "fields": [
      {
        "index": 1,
        "name": "first_name",
        "type": "string"
      },
      {
        "index": 1,
        "name": "last_name",
        "type": "string"
      }
    ],
    "id": "00000000-0000-0000-0000-000000000000",
    "name": "patient_document",
    "vault_id": "00000000-0000-0000-0000-000000000000"
  },
  "transaction_id": "00000000-0000-0000-0000-000000000000"
}

For more information on using Schemas, see our Schemas API documentation.

Patients

Create Patient Users

Let’s create two Patient Users: Bob and Susie. Patients will be able to see their own documents, but they won’t be able to see each other’s documents. To create these users, issue this command once for Bob and once for Susie:

Request
curl https://api.truevault.com/v1/users \
    -X POST \
    -u ${ADMIN_API_KEY}: \
    -d "username=bob&password=deadbeef&attributes=e30="
Response
{
    "result": "success",
    "transaction_id": "00000000-0000-0000-0000-000000000000",
    "user": {
        "access_key": null,
        "access_token": ".eJwljbsOwjAMAP8lK1hyEru",
        "account_id": "00000000-0000-0000-0000-000000000000",
        "api_key": "00000000-0000-0000-0000-000000000000",
        "id": "00000000-0000-0000-0000-000000000000",
        "status": "ACTIVATED",
        "user_id": "00000000-0000-0000-0000-000000000000",
        "username": "bob"
    }
}

For more information on Users, see our Users API documentation.

Create the Patient Group

In order for these Users to have access to their own Documents, we need to create a Group with a Policy that allows Read and Search with Owner=self. You can add any number of users to this Group, and they will all have access to their own Documents:

Policy (Replace the Vault ID with the actual Vault ID)
[
    {
        "Resources":[
            "Vault::00000000-0000-0000-0000-000000000000::Search::",
            "Vault::00000000-0000-0000-0000-000000000000::Document::$[Owner=self]"
        ],
        "Activities":"R"
    }
]
Request
curl https://api.truevault.com/v1/groups \
    -X POST \
    -u ${ADMIN_API_KEY}: \
    -d "name=patient_group&user_ids=${BOB_USER_ID},${SUSIE_USER_ID}&policy=WwogICAgewogICAgICAgICJSZXNvdXJjZXMiOlsKICAgICAgICAgICAgIlZhdWx0OjowMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDA6OlNlYXJjaDo6IiwKICAgICAgICAgICAgIlZhdWx0OjowMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDA6OkRvY3VtZW50OjokW093bmVyPXNlbGZdIgogICAgICAgIF0sCiAgICAgICAgIkFjdGl2aXRpZXMiOiJSIgogICAgfQpd"
Response
{
  "group": {
    "group_id": "00000000-0000-0000-0000-000000000000",
    "id": "00000000-0000-0000-0000-000000000000",
    "name": "patient_group",
    "policy": [
      {
        "Activities": "R",
        "Resources": [
          "Vault::00000000-0000-0000-0000-000000000000::Search::",
          "Vault::00000000-0000-0000-0000-000000000000::Document::$[Owner=self]"
        ]
      }
    ],
    "user_ids": [
      "00000000-0000-0000-0000-000000000000",
      "00000000-0000-0000-0000-000000000000"
    ]
  },
  "result": "success",
  "transaction_id": "00000000-0000-0000-0000-000000000000"
}

For more information on using Groups, see our Groups API documentation.

Create Documents with Owners

Now that we have some Patient Users, let’s create some Documents that hold their data. First let’s create Bob’s Document.

Document
{
    "first_name": "Bob",
    "last_name": "Carlson"
}
Request
curl https://api.truevault.com/v1/vaults/${VAULT_ID}/documents \
    -u ${ADMIN_API_KEY}: \
    -X POST \
    -d "schema_id=${SCHEMA_ID}&owner_id=${BOB_USER_ID}&document=ewogICAgImZpcnN0X25hbWUiOiAiQm9iIiwKICAgICJsYXN0X25hbWUiOiAiQ2FybHNvbiIKfQ=="
Response
{
  "document": {
    "id": "00000000-0000-0000-0000-000000000000",
    "owner_id": "00000000-0000-0000-0000-000000000000",
    "vault_id": "00000000-0000-0000-0000-000000000000"
  },
  "document_id": "00000000-0000-0000-0000-000000000000",
  "result": "success",
  "transaction_id": "00000000-0000-0000-0000-000000000000"
}

We’ll also create Susie’s Document:

Document
{
    "first_name": "Susie",
    "last_name": "Carlson"
}
Request
curl https://api.truevault.com/v1/vaults/${VAULT_ID}/documents \
    -u ${ADMIN_API_KEY}: \
    -X POST \
    -d "schema_id=${SCHEMA_ID}&owner_id=${SUSIE_USER_ID}&document=ewogICAgImZpcnN0X25hbWUiOiAiU3VzaWUiLAogICAgImxhc3RfbmFtZSI6ICJDYXJsc29uIgp9"
Response
{
  "document": {
    "id": "00000000-0000-0000-0000-000000000000",
    "owner_id": "00000000-0000-0000-0000-000000000000",
    "vault_id": "00000000-0000-0000-0000-000000000000"
  },
  "document_id": "00000000-0000-0000-0000-000000000000",
  "result": "success",
  "transaction_id": "00000000-0000-0000-0000-000000000000"
}

For more information on Documents, see our Documents API documentation.

Search with Patient Users

To demonstrate how Bob can now only view his Documents, let’s use Bob’s User Access Token to search for all Documents in the patient_documents vault. We can accomplish this by using a wildcard search type of * on the first_name field:

Search Option (Replace the Schema ID with the actual Schema ID)
{
    "filter": {
        "first_name": {
            "type": "wildcard",
            "value": "*",
            "case_sensitive": false
        },
    },
    "full_document": true,
    "sort": [
        {
            "first_name":"asc"
        }
    ],
    "schema_id": "00000000-0000-0000-0000-000000000000"
}
Request
curl https://api.truevault.com/v1/vaults/${VAULT_ID}/search \
    -u ${BOB_ACCESS_TOKEN}: \
    -X POST \
    -d "search_option=ewogICAgImZpbHRlciI6IHsKICAgICAgICAiZmlyc3RfbmFtZSI6IHsKICAgICAgICAgICAgInR5cGUiOiAid2lsZGNhcmQiLAogICAgICAgICAgICAidmFsdWUiOiAiKiIsCiAgICAgICAgICAgICJjYXNlX3NlbnNpdGl2ZSI6IGZhbHNlCiAgICAgICAgfQogICAgfSwKICAgICJmdWxsX2RvY3VtZW50IjogdHJ1ZSwKICAgICJzb3J0IjogWwogICAgICAgIHsKICAgICAgICAgICAgImZpcnN0X25hbWUiOiJhc2MiCiAgICAgICAgfQogICAgXSwKICAgICJzY2hlbWFfaWQiOiAiMDAwMDAwMDAtMDAwMC0wMDAwLTAwMDAtMDAwMDAwMDAwMDAwIgp9"
Response
{
  "data": {
    "documents": [
      {
        "document": "ewogICAgImZpcnN0X25hbWUiOiAiQm9iIiwKICAgICJsYXN0X25hbWUiOiAiQ2FybHNvbiIKfQ==",
        "document_id": "00000000-0000-0000-0000-000000000000",
        "owner_id": "00000000-0000-0000-0000-000000000000"
      }
    ],
    "info": {
      "current_page": 1,
      "num_pages": 1,
      "per_page": 100,
      "total_result_count": 1
    }
  },
  "result": "success",
  "transaction_id": "00000000-0000-0000-0000-000000000000"
}

Note that even though we are searching for ALL Documents in the Vault, only the Document owned by Bob is included in the results. Susie’s Documents are hidden from Bob! In fact, if you use Bob’s User Access Token to GET Susie’s Document specifically, you will receive a 404 Not Found error.

You can try searching with Susie’s User Access Token to see that she only gets back her Document in the results:

Request
curl https://api.truevault.com/v1/vaults/${VAULT_ID}/search \
    -u ${SUSIE_ACCESS_TOKEN}: \
    -X POST \
    -d "search_option=ewogICAgImZpbHRlciI6IHsKICAgICAgICAiZmlyc3RfbmFtZSI6IHsKICAgICAgICAgICAgInR5cGUiOiAid2lsZGNhcmQiLAogICAgICAgICAgICAidmFsdWUiOiAiKiIsCiAgICAgICAgICAgICJjYXNlX3NlbnNpdGl2ZSI6IGZhbHNlCiAgICAgICAgfQogICAgfSwKICAgICJmdWxsX2RvY3VtZW50IjogdHJ1ZSwKICAgICJzb3J0IjogWwogICAgICAgIHsKICAgICAgICAgICAgImZpcnN0X25hbWUiOiJhc2MiCiAgICAgICAgfQogICAgXSwKICAgICJzY2hlbWFfaWQiOiAiMDAwMDAwMDAtMDAwMC0wMDAwLTAwMDAtMDAwMDAwMDAwMDAwIgp9"
Response
{
  "data": {
    "documents": [
      {
        "document": "ewogICAgImZpcnN0X25hbWUiOiAiU3VzaWUiLAogICAgImxhc3RfbmFtZSI6ICJDYXJsc29uIgp9",
        "document_id": "00000000-0000-0000-0000-000000000000",
        "owner_id": "00000000-0000-0000-0000-000000000000"
      }
    ],
    "info": {
      "current_page": 1,
      "num_pages": 1,
      "per_page": 100,
      "total_result_count": 1
    }
  },
  "result": "success",
  "transaction_id": "00000000-0000-0000-0000-000000000000"
}

For more information on searching Documents, see our Search API documentation.

Doctors

We’ve successfully allowed Patients to see only their data. Now we need to allow Doctors to be able to see all Patient data. Let’s create a Doctor User and add them to a Doctor Group that supports this kind of access.

Create a Doctor User

First let’s create a new Doctor User:

Request
curl https://api.truevault.com/v1/users \
    -X POST \
    -u ${ADMIN_API_KEY}: \
    -d "username=doctor&password=deadbeef&attributes=e30="
Response
{
  "result": "success",
  "transaction_id": "00000000-0000-0000-0000-000000000000",
  "user": {
    "access_key": null,
    "access_token": ".eJwljbsOwjAMAP8lK1hyEru",
    "account_id": "00000000-0000-0000-0000-000000000000",
    "api_key": "00000000-0000-0000-0000-000000000000",
    "id": "00000000-0000-0000-0000-000000000000",
    "status": "ACTIVATED",
    "user_id": "00000000-0000-0000-0000-000000000000",
    "username": "doctor"
  }
}

Create the Doctor Group

Next we create a Group that allows its members to search and read all Documents owned by any User in the patient_documents Vault. The $[Owner=.*] resource type allows this kind of access:

Policy (Replace the Vault ID with the actual Vault ID)
[
    {
        "Resources":[
            "Vault::00000000-0000-0000-0000-000000000000::Search::",
            "Vault::00000000-0000-0000-0000-000000000000::Document::$[Owner=.*]"
        ],
        "Activities":"R"
    }
]
Request
curl https://api.truevault.com/v1/groups \
    -X POST \
    -u ${ADMIN_API_KEY}: \
    -d "name=doctor_group&user_ids=${DOCTOR_USER_ID}&policy=WwogICAgewogICAgICAgICJSZXNvdXJjZXMiOlsKICAgICAgICAgICAgIlZhdWx0OjowMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDA6OlNlYXJjaDo6IiwKICAgICAgICAgICAgIlZhdWx0OjowMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDA6OkRvY3VtZW50OjokW093bmVyPS4qXSIKICAgICAgICBdLAogICAgICAgICJBY3Rpdml0aWVzIjoiUiIKICAgIH0KXQ=="
Response
{
  "group": {
    "group_id": "00000000-0000-0000-0000-000000000000",
    "id": "00000000-0000-0000-0000-000000000000",
    "name": "doctor_group",
    "policy": [
      {
        "Activities": "R",
        "Resources": [
          "Vault::00000000-0000-0000-0000-000000000000::Search::",
          "Vault::00000000-0000-0000-0000-000000000000::Document::$[Owner=.*]"
        ]
      }
    ],
    "user_ids": [
      "00000000-0000-0000-0000-000000000000"
    ]
  },
  "result": "success",
  "transaction_id": "00000000-0000-0000-0000-000000000000"
}

Search with the Doctor User

If we issue the same search command as before with the Doctor user, we indeed see both Bob and Susie’s Documents in the results:

Request
curl https://api.truevault.com/v1/vaults/${VAULT_ID}/search \
    -u ${DOCTOR_ACCESS_TOKEN}: \
    -X POST \
    -d "search_option=ewogICAgImZpbHRlciI6IHsKICAgICAgICAiZmlyc3RfbmFtZSI6IHsKICAgICAgICAgICAgInR5cGUiOiAid2lsZGNhcmQiLAogICAgICAgICAgICAidmFsdWUiOiAiKiIsCiAgICAgICAgICAgICJjYXNlX3NlbnNpdGl2ZSI6IGZhbHNlCiAgICAgICAgfQogICAgfSwKICAgICJmdWxsX2RvY3VtZW50IjogdHJ1ZSwKICAgICJzb3J0IjogWwogICAgICAgIHsKICAgICAgICAgICAgImZpcnN0X25hbWUiOiJhc2MiCiAgICAgICAgfQogICAgXSwKICAgICJzY2hlbWFfaWQiOiAiMDAwMDAwMDAtMDAwMC0wMDAwLTAwMDAtMDAwMDAwMDAwMDAwIgp9"
Response
{
  "data": {
    "documents": [
      {
        "document": "ewogICAgImZpcnN0X25hbWUiOiAiQm9iIiwKICAgICJsYXN0X25hbWUiOiAiQ2FybHNvbiIKfQ==",
        "document_id": "00000000-0000-0000-0000-000000000000",
        "owner_id": "00000000-0000-0000-0000-000000000000"
      },
      {
        "document": "ewogICAgImZpcnN0X25hbWUiOiAiU3VzaWUiLAogICAgImxhc3RfbmFtZSI6ICJDYXJsc29uIgp9",
        "document_id": "00000000-0000-0000-0000-000000000000",
        "owner_id": "00000000-0000-0000-0000-000000000000"
      }
    ],
    "info": {
      "current_page": 1,
      "num_pages": 1,
      "per_page": 100,
      "total_result_count": 2
    }
  },
  "result": "success",
  "transaction_id": "00000000-0000-0000-0000-000000000000"
}

Conclusion

That’s it! This simple Doctor and Patient application is just one example of what you can achieve with Ownership. For further help building more complex use cases, check out the Ownership section in our documentation.

Have more questions? Try asking on StackOverflow and tag your question with truevault.