You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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.
Add identity extractor for OAuth2 token responses
Description
Phase 1 of the Snowflake /
identityFromTokenstory (#5150). Add apure 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 requiresuserInfo. 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
identityFromTokenstory (#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:
path. Objects, arrays, null, and missing paths are rejected — a
subject that quietly resolves to a stringified JSON blob would be a
silent footgun.
providers issue 64-bit numeric IDs that float64 formatting would
truncate).
type mismatch, with a
slog.Warnthat names the path but neverthe value.
body may contain access or refresh tokens.
Dependencies: PR #5094 (already merged) — provides the
ErrIdentityResolutionFailedsentinel the helper wraps.Blocks: the OAuth2 upstream provider integration cannot consume
identity from the token response until this helper lands.
Acceptance Criteria
extractIdentityFromTokenResponse(body, cfg)helperexists in the upstream package, returning
(subject, name, email, err)(concrete shape internal to the package).null, booleans, and missing paths produce an error wrapping
ErrIdentityResolutionFailed.round-tripping).
values gracefully, with WARN-level logs that name the path but
never include the value or any body content.
any logged record at any level — asserted by a dedicated test that
embeds a unique marker in the body and checks it never surfaces.
Shopify-nested response shapes plus the type-guard edge cases above.
task lint-fixandtask testpass.Out of Scope
what the auditor does with it is unchanged.