Skip to content

feat: add optional read-only API tokens - #5152

Open
grutt wants to merge 2 commits into
mainfrom
feat/read-only-api-tokens
Open

grutt wants to merge 2 commits into
mainfrom
feat/read-only-api-tokens

Conversation

@grutt

@grutt grutt commented Oct 7, 2026 •

Copy link
Copy Markdown
Member

Description

API tokens can be created as read-only. Those tokens are rejected on every gRPC call and authorized as VIEWER for tenant REST operations. Existing tokens stay unrestricted.

image image

Type of change

  • New feature (non-breaking change which adds functionality)
  • This change requires a documentation update

What's Changed

  • Store an optional readOnly flag on API tokens, defaulting to false
  • Reject read-only tokens on every gRPC call with PermissionDenied
  • Authorize read-only tokens as VIEWER on tenant REST operations
  • Leave unrestricted tokens on the existing REST and gRPC path, including the ban on managing other tokens
  • Add a read-only option to token creation and show access on the token list
  • Document token permissions, including that workers need an unrestricted token

Checklist

Changes have been:

  • Tested (unit, integration, or manually with steps specified)
  • Linted and formatted
  • Documented (where applicable)
  • Added to CHANGELOG (where applicable) -- see Keep a Changelog

🤖 AI Disclosure
  • I acknowledge that an LLM was used in the creation of this Pull Request, in accordance with Hatchet's AI_POLICY.md.

  • Details: Cursor (Grok) drafted the pull request description. The implementation was already in the working tree.

Read-only tokens are denied on gRPC and authorized as viewers on the REST API, so a credential can inspect a tenant without connecting a worker.
@vercel

vercel Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
hatchet-docs Ready Ready Preview Oct 28, 2026 10:05pm UTC

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation engine Related to the core Hatchet engine dashboard Related to the Hatchet dashboard labels Oct 7, 2026
@grutt
grutt requested review from juliusgeo and mnafees October 7, 2026 18:02
@greptile-apps

greptile-apps Bot commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 4/5

[High impact] The PR changes how API tokens are authorized across tenant REST and gRPC requests.

Fix the migration order and outstanding repository requirements before merging.

Summary

Adds optional read-only API tokens while keeping existing tokens unrestricted.

  • Token creators can save a read-only choice and see each token’s access level.
  • Read-only tokens use VIEWER permissions for tenant REST calls.
  • Read-only tokens are denied on every gRPC call.
  • The token docs explain read-only access and worker requirements.
  • The dispatcher names the streams service for durable-stream requests.
  • The operator registration comment clarifies an existing goroutine.

Reviews (2) · Last reviewed commit: "merge" · Reviewed by Greptile


func (r bearerRepo) APIToken() repository.APITokenRepository { return r.tokens }

func TestBearerTokenPermissions(t *testing.T) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Tests lack required comments

The new exported test functions have no godoc comments. The repository requires comments on exported Go functions, so this must be fixed before merging. Add short comments explaining what each test protects. The same pattern appears in TestReadOnlyTokenAuthentication, TestGenerateTenantTokenReadOnly, and the new persistence test.

Context Used: Comment and logging conventions for the Hatchet codebase (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +38 to +41
ctx, err := NewAuthN(config).Middleware(context.Background(), http.Header{"Authorization": []string{"Bearer " + testToken}})
if readOnly {
require.Equal(t, connect.CodePermissionDenied, connect.CodeOf(err))
require.Nil(t, ctx)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Client rejection lacks coverage

TestReadOnlyTokenAuthentication calls Middleware directly. It does not check that clients receive PermissionDenied through the actual request gate. Add read-only cases to the transport tests for a unary call and a stream, and assert that neither reaches the handler. This would catch future changes that break the promised client-facing error.


## PermissionDenied with a read-only token

Read-only API tokens can use viewer-authorized REST endpoints, but every gRPC call returns `PermissionDenied`, including worker registration and task completion.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about this, but don't we use gRPC for some of the read operations on the SDKs?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

on the sdk yes, but not on the MCP which is the current ask... and frankly a good idea to probably restrict bc if the agent does weird stuff it wont blow up core workloads...

i was thinking about calling these agent read only tokens potentially to make this more clear

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but not on the MCP which is the current ask

also im assuming this is true.... perhaps we should verify

@mnafees mnafees left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM on first glance, we might want to run a Claude security analysis on the code.

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Optional test failure: The load-online-migrate job failed on this PR. This check is non-mandatory and does not block merging, but may be worth investigating. View logs

Comment on lines +1 to +2
-- +goose Up
ALTER TABLE "APIToken" ADD COLUMN "readOnly" BOOLEAN NOT NULL DEFAULT false;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Migration version is too old

The new migration uses version 20261007120000, but the target branch already contains 20261028120000_v1_0_183.sql. This violates the repository requirement that new migrations have a version higher than the latest migration on main. Existing installations may fail to upgrade because they have already applied later migrations. Rename this migration to a version above 20261028120000.

Rule Used: What: Ensure every new SQL migration in cmd/hatchet-migrate/migrations/* has a version/date higher than the latest migration present on main. Why: Prevents out-of-order migrations that can fail or corrupt database schema state during deployment.... (source)

Before diving into specific issues, run through these checks:

1. **Verify your API token** — make sure `HATCHET_CLIENT_TOKEN` matches the token generated in the Hatchet dashboard for your tenant.
1. **Verify your API token** — make sure `HATCHET_CLIENT_TOKEN` matches an unrestricted token generated in the Hatchet dashboard for your tenant. Read-only tokens cannot connect workers.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Checklist breaks the punctuation rule

The rewritten checklist item still uses an em dash. The documentation guide forbids em dashes, so this requirement must be satisfied before merging. Replace it with a colon or a separate sentence.

Suggested change
1. **Verify your API token** — make sure `HATCHET_CLIENT_TOKEN` matches an unrestricted token generated in the Hatchet dashboard for your tenant. Read-only tokens cannot connect workers.
1. **Verify your API token**: make sure `HATCHET_CLIENT_TOKEN` matches an unrestricted token generated in the Hatchet dashboard for your tenant. Read-only tokens cannot connect workers.

Context Used: Writing style conventions for Hatchet documentation (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

This branch was successfully deployed

1 active deployment
Preview — 3e245d5d Deployed Oct 28, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dashboard Related to the Hatchet dashboard documentation Improvements or additions to documentation engine Related to the core Hatchet engine

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants