Repository navigation
feat(oauth): an assistant's tokens may last as long as its grant, up to a year - #27
Conversation
…to a year The signed offer asks for a year, the new protocol.AgentMaxMs. The owner picks less in the app or on the box page; both start at 30 days and offer a box no more than its agent.list says it takes, or 30 days when it says nothing. A refresh token lasts at most RefreshTTL, now a year, and never past the grant's end in the box's newest roster. Each refresh now takes that end afresh, so a grant the owner renews keeps its tokens; before, a family died at the end it had when the code was swapped, renewed or not. The access token stays at ten minutes. Moves the go/protocol pin to srcfl/ftw claude/agent-grant-year. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 49d450e48f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| return | ||
| } | ||
| s.issue(w, t.Family, cl.ID, a, scope, t.Expires) | ||
| s.issue(w, t.Family, cl.ID, a, scope, s.now().Add(RefreshTTL)) |
There was a problem hiding this comment.
Retain reuse markers for the sliding family lifetime
When a grant is repeatedly renewed and this line keeps the token family alive for more than a year, store.sweep deletes the original spent_codes entry and each rotated refresh-token row at that credential's own expires_ms, even though newer descendants remain valid. Replaying an authorization code or refresh token older than a year is then treated as an unknown credential rather than reuse, so revokeFamily is not called and the still-live family remains usable; retain these reuse markers until the family actually ends, or keep an absolute family expiry.
Useful? React with 👍 / 👎.
go.mod: main pins go/protocol at cbdd8a58 (#1687, fleetwire and webpush); this branch needs AgentMaxMs from srcfl/ftw#1686. Pin both at #1686's branch head 861fa708, which has master merged in. The pin moves to #1686's merge commit once it lands. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of #27: a refresh row was clamped to the grant's end when issued, and setGrant moves only the agent row. An assistant last used on day 10 whose owner renewed for a year on day 29 got 400 on day 31. Now a refresh token lasts RefreshTTL (a year) from issue; an agent past its end is still refused at every refresh and every call (agentGone) and swept with its tokens. The access token stays within ten minutes and never past the grant's end. The service also takes no roster end past a year from now. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
8a7bd9c6e597c4396deb05a5b7cd728f6619f97b on srcfl/ftw master. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Problem
Fredrik, 17 October 2026: an assistant's access should be able to last longer than 30 days, up to a year. srcfl/ftw#1686 raises the box's limit. FTW Cloud must offer the longer length, and an assistant's tokens must last as long as the grant the box sets, never longer.
Change
buildOfferalready takesttlSfromprotocol.AgentMaxMs, which feat(agents): an assistant's grant may last a year, and agent.list says so ftw#1686 raises to 365 days. FTW Cloud makes the offer before the owner picks a home, so it cannot ask each box what it takes. The app and the box page cap the length at what the box says it takes (longestMsinagent.listand in the box page's facts) and offer 30 days at most to a box that says nothing. Apps and box pages already out offer 30 days at most whatever the offer asks.RefreshTTLis nowprotocol.AgentMaxMs, a year. The access token stays at ten minutes.RefreshTTLfrom issue. An agent past its end in the box's newest roster is refused at every refresh and every call (agentGone) and swept with its tokens, so a refresh token is never usable past the grant. The access token stays within ten minutes and never past the grant's end. Rotation and reuse detection are unchanged.grantOfcuts an end pastnow + protocol.AgentMaxMs.Tests
TestARefreshTokenFollowsTheGrantTheBoxSets: an assistant idle since day 0, whose 30-day grant is renewed for a year on day 29, refreshes with its day-0 refresh token on day 31. Cut to five minutes, the next access token lasts at most 300 s and fails after the cut, and so does the refresh. With a refresh row clamped to the grant, it fails ("an idle assistant lost a renewed grant at its first end").TestARosterEndPastAYearIsCut: a roster end two years out is stored as at most a year from now.TestTheOfferIsSignedAndCarriesTheConsentnow pinsttlSat 365 × 86,400.go vet ./...,go test -race ./...,go test -tags ftwclouddev ./...,scripts/check-imports.sh: pass. On one full-racerun under heavy load,TestRostersAreNotDropped,TestUnsupportedVersionsAndTheRateLimitand laterTestAPurgedHomeLosesItsAgentseach failed once on a wait. Each passed on its own (-count=3and-count=4), and two more full-raceruns passed on this branch and onmain.Pairs
go/protocol):AgentMaxMsa year,longestMsinagent.listand the box page's facts. Merged; this PR pinsgo/protocolat its merge commit, 8a7bd9c6e597c4396deb05a5b7cd728f6619f97b on srcfl/ftw master.Deploy this before the Core beta with srcfl/ftw#1686 and before srcfl/ftw-app#82. New grants are safe in any order, but renewals are not: the newer box page and app offer to renew for a year from the box's
longestMsalone, and an older cloud ends every refresh family 30 days after the code swap. Deploying this first is safe: older apps and box pages still give 30 days at most, and a newer box with this cloud's year-long offer gives what the owner picks.Nothing here is deployed. Deploying is the owner's step.
🤖 Generated with Claude Code