Skip to main content

Mint a data credential

Before a tool connects to a cell over the PostgreSQL wire or Arrow Flight SQL, it needs a per-database credential, a real identity that resolves through a directory entity to real grants, so the login carries exactly the permissions that identity has and no more. This guide mints one over the public admin API, for both a workspace and a clean room.

A data credential is distinct from an API key or OAuth token: those authenticate a program to the HTTP API; a data credential authenticates a SQL/Flight client to a database on a cell. You use the HTTP API (with an API key or OAuth token) to mint the data credential.

What you need​

  • A caller authenticated to the public API (see Programmatic authentication).
  • The catalog.credentials.mint permission to issue, rotate, or revoke; or catalog.credentials.read to list credentials and read connection endpoints. These are deliberately narrow, a credential-minting client does not need broad data-admin authority.
  • Membership in the target workspace or clean room, and a database_id that belongs to that scope. The API confines every call to the caller's own workspace or clean room: a database in another one is refused.

All paths below are under the admin base /api/public/v1/admin.

Mint a credential for a workspace​

curl -sS -X POST \
https://<node>/api/public/v1/admin/workspaces/<workspace_id>/databases/<database_id>/credentials \
-H "Authorization: Bearer <api-key-or-oauth-token>" \
-H "Content-Type: application/json" \
-d '{
"permission_set": "read",
"label": "powerbi-analysts"
}'

Request fields:

FieldRequiredMeaning
permission_setno (default read)The permission profile the credential carries.
entity_idnoThe directory entity the credential acts as; defaults to the acting caller.
labelnoA human label for later identification.
expires_atnoAn expiry for the credential.

The 201 response carries the one-time secret and the connection details:

{
"tenant_kind": "workspace",
"tenant_id": "<workspace_id>",
"credential": { "credential_id": "…", "secret": "…" },
"connection": {
"database_id": "<database_id>",
"username": "…",
"available": true,
"protocols": ["postgres", "flight-sql"],
"external_endpoints": [
{ "proto": "postgres", "host": "<node>", "port": 9950 }
],
"secure": true
}
}
The secret is shown once

The credential.secret is returned only in this mint response and is never retrievable again. Store it in your secrets manager immediately. Listing credentials (below) returns metadata only, never the secret.

The connection.username and the one-time secret are what a BI tool or SQL client presents to the SQL or Flight surface. See Connect a BI or reporting tool.

List, rotate, and revoke​

# List (metadata only, no secrets)
curl -sS https://<node>/api/public/v1/admin/workspaces/<workspace_id>/databases/<database_id>/credentials \
-H "Authorization: Bearer <token>"

# Rotate: issues a new secret; the existing one is honored for a grace window
curl -sS -X POST \
https://<node>/api/public/v1/admin/workspaces/<workspace_id>/databases/<database_id>/credentials/<credential_id>/rotate \
-H "Authorization: Bearer <token>"

# Revoke
curl -sS -X DELETE \
https://<node>/api/public/v1/admin/workspaces/<workspace_id>/databases/<database_id>/credentials/<credential_id> \
-H "Authorization: Bearer <token>"

To read the reachable connection endpoints for a database without minting:

curl -sS https://<node>/api/public/v1/admin/workspaces/<workspace_id>/databases/<database_id>/endpoints \
-H "Authorization: Bearer <token>"

Clean rooms​

A clean room mints credentials through the same shapes, under /api/public/v1/admin/cleanrooms/<cleanroom_id>/…:

OperationMethod + path
IssuePOST …/cleanrooms/{cleanroom_id}/databases/{database_id}/credentials
ListGET …/cleanrooms/{cleanroom_id}/databases/{database_id}/credentials
RotatePOST …/cleanrooms/{cleanroom_id}/databases/{database_id}/credentials/{credential_id}/rotate
RevokeDELETE …/cleanrooms/{cleanroom_id}/databases/{database_id}/credentials/{credential_id}
EndpointsGET …/cleanrooms/{cleanroom_id}/databases/{database_id}/endpoints

The same scope confinement applies: the caller must be a clean-room member and the database_id must belong to that clean room.

Where the credential is valid​

Figure: a minted data credential is presented to the cell's data surfaces. The SQL wire and Arrow Flight SQL are Live; the Iceberg REST catalog serves catalog reads only (Partial). Delta Sharing is served, but it does not take a minted data credential (amber, dotted): its recipients carry their own bearer token, issued on the sharing admin surface.

Table equivalent

SurfaceWhat the credential can doStatus
PostgreSQL wire (:9950)Full governed reads/writes for BI and SQL toolsLive
Arrow Flight SQL (:59950)High-throughput columnar pullsLive
Iceberg REST catalogCatalog reads (list/load); writes are in-memory, non-persistentPartial
External Delta Sharing protocolNothing. Delta Sharing recipients are created on the sharing admin surface and present their own bearer recipient token, with grants made per shareDifferent credential: see connect a BI tool
One credential, org-wide

A data credential replicates across the org (mint once, use anywhere in the node), and the endpoint returned is always the node's external gateway. The mint API is a thin front door over the cell's data plane, it adds no store of its own, and it never returns a stored secret after the mint.

Verify it worked​

#CheckHow
1The credential authenticatesA connection succeeds and resolves to a directory entity, not to an anonymous session
2It carries the right authorityA query returns exactly what that entity is entitled to, with row filters and column masks applied
3It is attributableActivity shows against the entity, so the credential is not a shared identity in disguise
4It is revocableRevoking it ends access on the next use rather than at expiry

Step 2 is the point of the whole exercise. A credential that authenticates but carries more authority than intended is worse than one that does not work, because nothing looks wrong.

When it does not work​

SymptomMost likely causeWhat to do
Authentication is refusedThe credential is revoked, expired, or for another entityCredentials resolve to an entity. Check which one you minted it for
It connects but returns nothingPolicy filtered everything, or no catalog is boundAn empty result under policy is not an error. Check the entity's grants first
A table is missing entirelyEnumeration is need-to-know filteredThe surface will not advertise a table you could not query
It works from one place and not anotherThe surface is not enabled, or the posture blocks itNot every access method is on in every deployment
Rotation broke a running clientThe old credential was revoked before the client picked up the new oneRotate by issuing first and revoking after the switch