Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

feat(observability): Linear OAuth token-lineage logging for revocation investigation

Open
#807 1 comment 0 reactions 1 assignee View on GitHub

Maintainers usually reply within 1 day

@isadeks is already working on this.

Since Aug 27, 2026.

Assessment

This issue has not been assessed yet.

Description

approved enhancement P1 security v1

Summary

Add resolver-local diagnostic logging to the Linear OAuth refresh path
(cdk/src/handlers/shared/linear-oauth-resolver.ts) so we can investigate a recurring
per-workspace grant revocation. Additive observability only — no behavior change to the refresh
or persist logic.

Motivation

One Linear workspace's OAuth grant is being revoked ~25h after each (re-)onboard: the platform's
refresh returns invalid_grant / "Refresh token revoked". A second workspace on the identical code
path is durable, so the refresh code itself is sound (verified: the rotated refresh_token is
persisted on success). The cause is upstream/app-side, but today's logs can't reconstruct the
token's lifecycle to prove what Linear is rejecting — we can't distinguish "a spent/rotated token
was replayed" from "a live grant was killed server-side," nor correlate a failure to the token we
last persisted, nor see the token's age at death.

Proposed logging (resolver-local, one file)

Threaded through refreshLinearToken / tryRefreshOnce / the persist path:

  1. Refresh-token fingerprint — sha256(refresh_token).slice(0,12), logged on every refresh
    outcome. Identifies which token across events; the raw token is never logged.
  2. Token age — token_age_h (now − installed_at) and since_last_refresh_h
    (now − updated_at) on each outcome. Both fields already exist on the stored bundle; no schema
    change.
  3. Rotation trail — on successful persist, log rotated <oldFp> → <newFp>, so the next
    failure can be correlated to the token we just wrote (server-side kill vs stale/race).
  4. Revocation forensics line — at "permanently rejected," one structured line:
    {workspace_id, refresh_token_fp, token_age_h, since_last_refresh_h, installed_at, updated_at}.

Non-goals

  • No change to refresh/persist behavior, cache, or the invalid_grant re-read/race handling.
  • No trigger/caller threading into other handlers (kept resolver-local to bound blast radius on a
    security-sensitive credential file; can follow up if the fingerprint+age data proves insufficient).
  • Never log token material — fingerprints (truncated sha256) only.

Acceptance criteria

  • Every refresh outcome (success, invalid_grant, failure, permanently-rejected) logs the
    refresh-token fingerprint + token_age_h + since_last_refresh_h.
  • Successful persist logs the old→new fingerprint rotation.
  • No raw token/secret value appears in any log (verified against the masking gate).
  • No behavior change: existing resolver tests pass unchanged; new tests assert the fingerprint
    is a truncated hash and never the raw token.

Security / priority

Diagnostic-only, additive; touches a credential path so reviewed accordingly (masking gate). Suggest
P1 — it unblocks an active, recurring auth outage investigation.

Dominant language
TypeScript
Stars
151
Forks
48
Avg merge
2d 11h
Merged PRs (30d)
23

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from aws-samples/sample-autonomous-cloud-coding-agents

All issues in aws-samples/sample-autonomous-cloud-coding-agents

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.