---
title: "Authentication"
description: "API keys and OAuth 2.1 with PKCE, device flow and dynamic client registration. Every credential acts as one person, on one plane, and never does more than that person."
canonical: "https://gtable.app/docs/start/authentication"
updated: "2026-10-05"
---

# Authentication

Every credential gtable issues belongs to a person. An API key, an OAuth access token and an
agent's connection all act **as** someone, with that person's permissions, narrowed by the
scopes the credential was given. There is no ambient admin key and no service account.

## Send it as a bearer token

```http
Authorization: Bearer gt_live_…
```

Keys start with `gt_`. Keys issued before gtable took its current name start with `dva_`; they
keep working and need no change. An OAuth access token has the same format and is checked the
same way.

A credential is minted on **one plane** and is only accepted there. A key made in an app works
in that app; an agent connected to a suite reaches the apps ticked when it was approved; a
Studio key works on the Studio's Builder API. Presented to the other side, it is not a weaker
credential, it is no credential at all (`401`).

## API keys

|         | In an app                                         | In the Studio                                                      |
| ------- | ------------------------------------------------- | ------------------------------------------------------------------ |
| Where   | **Settings**, **Connections**, **For developers** | the **Developer** page                                             |
| Acts as | you, in that app                                  | you, as a builder of **one** organisation, chosen when you make it |
| Expiry  | 90 days                                           | 90 days by default, or a number of days you choose, or never       |

A key is shown once, when it is made. Revoking it, in the same place, takes effect at once.

**Keys are made and revoked by a person in a browser.** A key, or an agent connected by OAuth,
cannot make another key or revoke one, and neither operation is an MCP tool. That way a key
that leaks can be revoked and stays revoked: it cannot have minted a successor.

**A Studio key acts in one organisation.** It cannot reach your other organisations, even though
you can.

## Scopes

| Scope           | Lets a credential                                                                                      | Available in an app |
| --------------- | ------------------------------------------------------------------------------------------------------ | ------------------- |
| `records:read`  | read the rows you can see, their comments and history, your saved views, SQL reads, the change history | yes                 |
| `records:write` | create, change and delete rows, comment, upload files, undo                                            | yes                 |
| `schema:read`   | see the tables and fields you have access to, and the app's rules                                      | yes                 |
| `schema:write`  | change tables, fields and rules                                                                        | Studio only         |
| `pages:read`    | read pages, their code and history                                                                     | yes                 |
| `pages:write`   | create, edit and publish pages: an app's in the Studio, your own in an app                             | yes                 |
| `members:read`  | see who is in an app and the directory                                                                 | yes                 |
| `members:write` | add people, change their groups, make invite links                                                     | Studio only         |
| `account:read`  | see organisations, suites, apps, plan and usage                                                        | Studio only         |
| `account:write` | start, leave or delete an organisation, close your account                                             | Studio only         |

A credential can only ever be **narrower** than the person behind it. A key with
`records:write`, made by someone who may only read, still cannot write.

Check what a credential is holding:

```bash
curl "https://your-suite.gtable.app/your-app/v1/me" -H "Authorization: Bearer $GTABLE_TOKEN"
```

## OAuth 2.1, for agents and tools

MCP clients and other tools connect with OAuth, so nobody pastes a key into them. The Studio and
every suite are each their own authorisation server.

- **Discovery.** `/.well-known/oauth-authorization-server` (RFC 8414) and
  `/.well-known/oauth-protected-resource` (RFC 9728) on the Studio and on every suite's address.
  An unauthenticated MCP request answers `401` with a `WWW-Authenticate` header naming where to
  authorise, which is why a client can connect with nothing but a URL.
- **Authorization code with PKCE**, `S256` only. Every client is public; there is no client
  secret, no `plain` method and no implicit flow.
- **Device flow** (`urn:ietf:params:oauth:grant-type:device_code`), for a machine with no
  browser: a CI runner, a server over SSH.
- **Dynamic client registration** (RFC 7591) at `/oauth/register`. A client that publishes its
  own metadata document needs no registration at all.
- **Refresh tokens rotate.** Each refresh returns a new one. Presenting an old one again is
  treated as proof that somebody has a copy, and the whole grant is revoked.

| Endpoint             | Path, on the Studio or the suite's address |
| -------------------- | ------------------------------------------ |
| Authorize            | `/authorize`                               |
| Token                | `/oauth/token`                             |
| Device authorization | `/oauth/device`                            |
| Registration         | `/oauth/register`                          |
| Revocation           | `/oauth/revoke`                            |

An access token lasts 30 days and its refresh token 90.

### Consent is a person in a browser

The consent page shows the name the client gave itself **and** the address its answer will be
sent to. Check that address before you approve. The scopes granted are the ones you tick,
intersected with what you hold. On a suite, you also choose which of its apps the connection may
reach; in the Studio, which organisation.

## Limits on signing in

Signing in and the OAuth endpoints are limited per address per minute, and answer `429` with
`rate_limited` when the limit is reached. Wait a minute and retry.
