Skip to content

Add identity extractor for OAuth2 token responses #5152

@jhrozek

Description

@jhrozek

Add identity extractor for OAuth2 token responses

Description

Phase 1 of the Snowflake / identityFromToken story (#5150). Add a
pure helper that takes a raw OAuth2 token-endpoint response body and a
config struct and returns the extracted user identity (subject, name,
email), using gjson dot-notation paths into the JSON envelope. This is
the foundational building block consumed by the OAuth2 upstream
provider in a later phase — no operator surface, no runtime wiring,
no I/O.

Context

MCPExternalAuthConfig's OAuth2 upstream type currently requires
userInfo. Some providers (Snowflake, Slack v2, Shopify online tokens)
have no usable userinfo endpoint but include user identity directly in
the token-endpoint response body. The identityFromToken story (#5150)
adds a sibling extraction mechanism that pulls identity from configured
gjson paths into that response body.

Splitting the pure helper out keeps the surface deterministic and the
test matrix tractable. Key design points:

  • Only scalar string and number values are accepted for the subject
    path. Objects, arrays, null, and missing paths are rejected — a
    subject that quietly resolves to a stringified JSON blob would be a
    silent footgun.
  • Numeric subjects preserve integer precision beyond 2^53 (some
    providers issue 64-bit numeric IDs that float64 formatting would
    truncate).
  • Optional name / email paths degrade silently to empty string on
    type mismatch, with a slog.Warn that names the path but never
    the value.
  • Errors must never include any portion of the response body — the
    body may contain access or refresh tokens.

Dependencies: PR #5094 (already merged) — provides the
ErrIdentityResolutionFailed sentinel the helper wraps.
Blocks: the OAuth2 upstream provider integration cannot consume
identity from the token response until this helper lands.

Acceptance Criteria

  • A pure extractIdentityFromTokenResponse(body, cfg) helper
    exists in the upstream package, returning (subject, name, email, err) (concrete shape internal to the package).
  • Subject path enforces scalar-only resolution; objects, arrays,
    null, booleans, and missing paths produce an error wrapping
    ErrIdentityResolutionFailed.
  • Numeric subjects retain full integer precision (no float64
    round-tripping).
  • Optional name and email paths handle missing or wrong-typed
    values gracefully, with WARN-level logs that name the path but
    never include the value or any body content.
  • No part of the response body appears in any returned error or
    any logged record at any level — asserted by a dedicated test that
    embeds a unique marker in the body and checks it never surfaces.
  • No I/O in the helper; pure function.
  • Unit tests cover realistic Snowflake-flat, Slack-nested, and
    Shopify-nested response shapes plus the type-guard edge cases above.
  • task lint-fix and task test pass.

Out of Scope

  • The CRD type and its admission validation.
  • Wiring into the OAuth2 upstream provider's identity-resolution chain.
  • Operator-side translation from CRD to runtime config.
  • YAML examples.
  • Audit-log changes — the helper just produces an identity value;
    what the auditor does with it is unchanged.

Metadata

Metadata

Assignees

No one assigned

    Labels

    authenhancementNew feature or requestgoPull requests that update go codeoauth

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions