Skip to content

feat(unified-identity): carry the numeric GitHub id in local OAuth JWTs (#374 slice B) #422

Closed as not planned

Description

@mashkovd

Parent

Refs #374 — Slice B of the approved design (platform-gitops/agents-state/mctl-api/proposals/issue-374-feat-unified-identity-introduce-a-swappa/tasks.md, section "Slice B"). Slice A shipped in #410 (Refs #374, released in 4.55.0, running in 4.56.0). This issue is the separate follow-up that design calls for; it must not close #374.

Goal

Carry the numeric GitHub id into locally issued OAuth JWTs, so a token resolves to the canonical principal via (github, <numeric id>) without a GitHubIDLookup round-trip, while tokens minted before the change keep working.

Scope (B1 from the design record)

  • internal/api/oauth_handlers.go (~251): switch from GitHubValidator.Validate to ValidateIdentity (internal/auth/github.go).
  • Thread the id through IssueCode and IssueJWT (internal/auth/oauth_server.go) as an optional ghid claim on jwtPayload.
  • Teach the Slice A local-OAuth federation provider to prefer ghid when present.
  • Metric oauth_jwt_without_github_id_total for tokens resolved through the login-only path.
  • Update docs/federation.md.

Line numbers are from the design record (2026-09-24) and must be re-read against main.

Acceptance (from the design, test T7)

  • A token minted after the change resolves via (github, <numeric id>) with no GitHubIDLookup call (internal/principals/resolver.go).
  • A token minted before the change still resolves through the login-only path, and increments the new metric.
  • sub is still the login; no other claim changes meaning.
  • Regression test fails if ghid is dropped from IssueJWT (mutation-verified).

Out of scope

Activity

  1. mctl-agents commented on Sep 29, 2026

    @mctl-agents
    Contributor

    mctl-agents issue-investigator has analyzed this issue and created a proposal:

    https://github.com/mctlhq/mctl-gitops/tree/main/platform-gitops/agents-state/mctl-api/proposals/issue-422-feat-unified-identity-carry-the-numeric/

    Status: proposed — pending human approval. Review requirements.md, design.md and tasks.md, then approve: signal this issue's DevLoopWorkflow (mctl-api POST /api/v1/agents/dev-loop/dev-loop-mctlhq-mctl-api-422/approve, or python -m orchestrator.temporal.cli approve dev-loop-mctlhq-mctl-api-422 --approver <your-identity>) — the workflow flips .status.yaml to accepted via the mctl-agents-approve operation and runs the Tier 2 implementer. If no DevLoopWorkflow is running for this issue (pre-Temporal proposal), run the mctl-agents-approve operation directly with service=mctl-api slug=issue-422-feat-unified-identity-carry-the-numeric.

    The approver is recorded in .status.yaml and in the gitops commit, and the implementer refuses a proposal whose control.requires_human_approval carries no named approver — so prefer the mctl-api endpoint, which takes the approver from the authenticated caller rather than from what the caller types.

  2. added a commit that references this issue on Sep 29, 2026
  3. mashkovd commented on Sep 29, 2026

    @mashkovd
    MemberAuthor

    Proposal review (not approved — waits for the owner)

    Checked issue-422-feat-unified-identity-carry-the-numeric against mctl-api main.

    What holds up. Scope is slice B only (no slice C/D, no #376 run tokens). ghid is omitempty and sub stays the login, so old verifiers and old tokens are unaffected. Explicit new parameters on IssueCode/IssueJWT/IssueRefreshToken make every call site a compile error until considered. T1 is a real mutation pin; T4 reuses the existing characterization harness for both middleware chains.

    P2 — in production the benefit lasts one hour per login. The proposal mints refreshed access tokens without ghid on the refreshstore (Postgres) path and records the column as a follow-up. But production uses that path: mctl-api 4.56.0 logs oauth refresh token store initialized at boot, AccessTokenTTL is 1h and RefreshTokenTTL 30d (internal/auth/oauth_server.go:767-768). So a Claude/ChatGPT MCP client carries ghid only on its first access token; every token after the first refresh — i.e. almost all traffic — falls back to the login-only path and the GitHubIDLookup the issue is meant to remove. The acceptance line "a token minted after the change resolves via (github, <numeric id>)" is then false for refreshed tokens.

    Suggested resolution (owner's choice):

    • (a, recommended) include a nullable github_id BIGINT column on the refresh-token table in this slice, written at IssueRefreshToken and read in RefreshAccessToken; existing rows stay NULL and keep the login-only fallback, so the migration is additive and needs no backfill; or
    • (b) keep the scope, but file the column follow-up now and state in the PR and docs/federation.md that production coverage is first-token-only until it lands.

    P3. oauth_jwt_without_github_id_total counts per validation, so after rollout it will be dominated by refreshed tokens (see P2) rather than by genuinely pre-change tokens; with (a) it becomes a clean "old tokens still in circulation" signal that should decay to zero within 30 days.

    Status: proposed, not approved.

  4. mashkovd commented on Oct 17, 2026

    @mashkovd
    MemberAuthor

    Superseded by #377 PR-B 2a (36f1a21). Local OAuth sessions now carry the canonical principal directly: pid in access tokens and principal_id in the refresh row, preserved across refresh rotation. In principal mode requests authorize directly by that principal, so carrying a numeric GitHub ID in the JWT no longer removes an additional lookup or improves the authorization path. ValidateIdentity is already used at GitHub sign-in. Closing as not planned.

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions