Attachments & REST
When you need data the plugin API doesn't expose directly — attachment bytes, SQL queries, the document's REST endpoints — the SDK gives you a signed fetch that handles authentication for you.
Access tokens
Grist short-lived access tokens authorize REST calls against the current document. useGrist() exposes:
const token = await w.getAccessToken({ readOnly: true })
// { token: string, baseUrl: string }Tokens are cached briefly (~45s) and single-flighted per readOnly flag. On 401, the cache clears and the call is retried once. You should rarely need to call getAccessToken directly — prefer w.fetchWithAuth(...).
REST fetch
const response = await w.fetchWithAuth("/api/docs/{docId}/sql", {
method: "POST",
body: JSON.stringify({ sql: "SELECT * FROM Tasks LIMIT 10" }),
headers: { "Content-Type": "application/json" },
})
const data = await response.json()path may be:
- An absolute URL (
https://...) — used as-is. - A path with leading
/— resolved against the token'sbaseUrl. - A relative path — treated as
/${path}.
For GET / HEAD the token is appended as ?auth=. For other methods it's sent as Authorization: Bearer ….
Pass readOnly: true when calling read-only endpoints; the token is scoped lower and stays valid longer.
await w.fetchWithAuth("/api/docs/.../tables/Tasks/records", { readOnly: true })Attachments
Grist attachment columns store an array of file refs. The SDK handles extracting ids and downloading bytes.
Signed URL only
const url = await w.getAttachmentUrl("123", { readOnly: true })
// Use the URL directly in <img src={url} />, <a download href={url} />, etc.Blob (preferred for large files)
const { blob, contentType } = await w.fetchAttachmentBlob("123")
const objectUrl = URL.createObjectURL(blob)
// remember to URL.revokeObjectURL(objectUrl) when unmountingBase64 (for embedding directly)
const { base64, contentType } = await w.fetchAttachmentBase64("123")
const dataUrl = `data:${contentType};base64,${base64}`Use Blob for anything more than a few KB; Base64 is convenient for inline icons or PDF previews.
Working with cells
Attachment columns hold arrays of file refs. Use the helpers from the package root:
import {
extractGristAttachmentIdsFromCell,
extractGristAttachmentId,
getAttachmentDownloadUrlForCell,
fetchAttachmentBase64ForCell,
} from "grist-widget-sdk"
const ids = extractGristAttachmentIdsFromCell(row.Photos)
const firstUrl = await getAttachmentDownloadUrlForCell(docApi, row.Photos, 0)docApi is w.fetchTable-class methods; you'd normally use this helper from a non-React context. Inside React, prefer w.getAttachmentUrl(id) after extracting ids.
Required access level
You need at least requiredAccess: "read table" for read-only tokens, and requiredAccess: "full" for read-write REST. Set this on <GristWidgetProvider> (or via w.configure({ requiredAccess: "full" }) at runtime).
Error handling
Both fetchWithAuth and attachment helpers throw on non-2xx responses with a generic message. For richer handling, inspect the Response yourself:
const response = await w.fetchWithAuth("/api/...", { readOnly: true })
if (!response.ok) {
const body = await response.text()
throw new Error(`Grist REST failed (${response.status}): ${body}`)
}For the 401 retry path, the SDK's internal token cache is cleared automatically — your code keeps working after a brief renewal.