Skip to content

Accept the tokens that SDK 0.1.0 signs: SDK sub claims and org-wide tokens without a repo claim #658

Closed

Description

@ThomasK33

Problem

The stable SDKs 0.1.0 (Go github.com/pierrecomputer/sdk/go v0.1.0, npm @pierre/sdk 0.1.0, PyPI pierre-sdk 0.1.0) sign their own request tokens by default (PIERRE_PRIVATE_KEY or option.WithPrivateKey). open.storage rejects those tokens for two reasons:

  1. sub claim. The SDKs set sub to pierre-sdk-go, pierre-sdk-python or pierre-sdk-typescript (go/internal/credentials/credentials.go Subject, python/src/pierre/_credentials.py SUBJECT, typescript/dist/runtime/credentials.js SUBJECT, all at tag go/v0.1.0). internal/auth/verifier.go requires sub == "@pierre/storage" and answers 401 invalid token otherwise. The vendored upstream guide (docs/upstream/getting-started/authentication.md) describes sub as an agent identity "for logging", for example ci-pipeline-prod.
  2. Org-wide tokens. For meta.get and repos.list the SDKs omit the repo claim (repo,omitempty; the upstream guide says "omit for org-wide tokens"). open.storage requires repo: "org" and answers 403 token is not org-scoped.

So with the default credential path, every one of the 39 SDK 0.1.0 operations fails against open.storage, even after #656 adds the missing routes. Tokens from openstorage mint or from SDK 1.17.1 (@pierre/storage, sub: "@pierre/storage", repo: "org") still work, through option.WithToken or option.WithGetToken.

Evidence

I found this while dogfooding #656 on a local node (verify-openstorage skill, branch sdk-canonical-routes-issue656), with the SDK's own signer (auth.CreateToken with the node's org key) and only the claims below changed:

sub repo for org-wide ops meta.get repos.create
SDK default (pierre-sdk-go) omitted (SDK default) 401 invalid token 401 invalid token
@pierre/storage omitted (SDK default) 403 token is not org-scoped OK
@pierre/storage org OK OK

Desk decision needed

This changes token verification (docs/reference/authentication.md), so it needs a decision before code. Options I see:

  • Option A: accept any non-empty sub, and treat a token without a repo claim as org-wide (only org-level routes accept it; repo-scoped routes keep requiring a matching repo).
  • Option B: also accept the three SDK subjects next to @pierre/storage, and accept an omitted repo as org-wide.

Severity

High: the documented default credential path of every stable upstream SDK cannot call open.storage.


Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: high

Activity

  1. ThomasK33 commented on Nov 4, 2026

    @ThomasK33
    MemberAuthor

    Desk decision: Option A.

    1. Accept any non-empty sub. The vendored upstream guide (docs/upstream/getting-started/authentication.md:23) calls sub an "Agent identity (for logging)" and its examples use ci-pipeline-prod. Authorization stays with the signature, iss, exp, scopes and repo. An empty or missing sub stays a 401.
    2. Treat a token without a repo claim as org-wide, as the guide says ("omit for org-wide tokens"). It must behave exactly like repo: "org" does today: org-level routes accept it, and repo-scoped routes refuse it the same way they refuse repo: "org". Widen repo access only if the vendored spec documents it, and then in a separate PR.
    3. Keep minting sub: "@pierre/storage" in openstorage mint, so older verifiers keep accepting our tokens.

    This changes token verification, so the PR gets a full Codex security review on its exact head. Every place that reads sub (logs, internal/githttp/server.go, metrics) must still be safe with an arbitrary string: bounded length in logs, no use as a key without escaping.

    An owner workspace will implement it.


    Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: medium

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    upstream-compatDrift against the live code.storage API surface

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions