# Restrict an API key to selected data (/docs/guides/secure/restrict-api-key-access)



Restrict an API key to selected data [#restrict-an-api-key-to-selected-data]

Use a database role when a service needs selected data, not every table.

Before you begin [#before-you-begin]

* Set `RAWTREE_API_KEY` to an administrator API key.
* Use the `analytics` database. If it does not exist, create it with the [`POST /v1/databases` endpoint](/docs/reference/api/databases#post-v1databases).
* Pass `?database=analytics` on each query. If you omit it, the Query API uses the API key's stored default database.
* Use the `events` and `private_events` tables, with `action` and `user_id` fields. Create both tables with the [table API](/docs/reference/api/tables#post-v1tablestable).

1\. Create a role [#1-create-a-role]

Create a role for the service.

```sql test
CREATE ROLE api_events_reader
```

2\. Grant table access [#2-grant-table-access]

Grant `SELECT` on the event table.

```sql test known-failure="GRANT returns code 497 after access repair (local stack)"
GRANT SELECT ON analytics.events TO api_events_reader
```

Add a column list when the key needs access to selected columns only.

3\. Create a role key [#3-create-a-role-key]

Create an API key that uses the database role.

```bash
curl -X POST 'https://api.rawtree.com/v1/keys?database=analytics' \
  --header "Authorization: Bearer $RAWTREE_API_KEY" \
  --header "Content-Type: application/json" \
  -d '{"name":"api-events-reader","database_roles":["api_events_reader"]}'
```

The response contains the new key's ID and token.

```json
{
  "id": "<key-id>",
  "token": "rt_..."
}
```

Save the `token` value as `READER_API_KEY` and the `id` value as `READER_KEY_ID`.

4\. Query the granted table [#4-query-the-granted-table]

Use the returned key to query the granted table.

```bash
curl -X POST 'https://api.rawtree.com/v1/query?database=analytics' \
  --header "Authorization: Bearer $READER_API_KEY" \
  --header "Content-Type: application/json" \
  -d '{"sql":"SELECT action, user_id FROM events"}'
```

5\. Query an ungranted table [#5-query-an-ungranted-table]

Check that the key cannot read the private table.

```bash
curl -X POST 'https://api.rawtree.com/v1/query?database=analytics' \
  --header "Authorization: Bearer $READER_API_KEY" \
  --header "Content-Type: application/json" \
  -d '{"sql":"SELECT * FROM private_events"}'
```

The request returns HTTP 400 with this response.

```json
{
  "error": "rawtree_error",
  "message": "Access denied. You don't have permission to run this query.",
  "hint": "Check the database user and role grants for the requested operation, database, table, and columns."
}
```

Check the result [#check-the-result]

Confirm that the role key reads `events` and cannot read `private_events`.

Cleanup [#cleanup]

If the service no longer needs the role key, delete it.

```bash
curl -X DELETE "https://api.rawtree.com/v1/keys/$READER_KEY_ID" \
  --header "Authorization: Bearer $RAWTREE_API_KEY"
```

Drop the role after you delete its keys.

```sql
DROP ROLE api_events_reader
```

Next steps [#next-steps]

* [Understand access control](/docs/concepts/access-control)
* [Apply row-level security](/docs/guides/secure/row-level-security)
* [Role statements](/docs/reference/sql/statements/role)
* [Grant statements](/docs/reference/sql/statements/grant)
