coreapi: resolve New() host + token via the active context · Entire

coreapi: resolve New() host + token via the active context

1bce5b8→main·

toothbrush·1mo ago·2 files·+91 added/-32 removed

New() now consults auth.ResolveControlPlaneTarget for its host and bearer, so entire auth use <ctx> retargets org/repo/project/grant onto that context's core and their tokens refresh silently. Replaces bearerSource with a token-func-backed providerSource; NewWithBearer auth status is untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com

Sessions

bbf4cf7240deView transcript

[?
Context-Aware Control-Plane Target ResolutionClaude Code·1 step](/content/gh/entireio/cli/session/d6b8ae84-4338-458e-ae8a-594eb414b667#timeline-bbf4cf7240de/index.html)

Changes

2

7 unmodified lines

8
9
10
11
11
12
13
5 unmodified lines

19
20
21
23
24
25
26
27
28
29
30
31
32
22
23
24
25
26
27
28
29
30
34
35
36
37
38
39
31
32
33
34
35
36
37
38
39
26 unmodified lines

66
67
68
72
73
74
75
76
77
78
79
80
81
69
70
71
72
73
74
75
76
77
78
79
80
81
84
85
82
83
84
85
88
89
86
87
88
89
90
91
2 unmodified lines

94
95
96
98
97
98
99
100

7 unmodified lines

"github.com/ogen-go/ogen/ogenerrors"

"github.com/entireio/cli/cmd/entire/cli/api"
    "github.com/entireio/cli/cmd/entire/cli/auth"

// New returns a *Client wired to talk to the Entire control plane (Core // API) as the currently logged-in user. // // The base URL is the auth/login host — the Core API is served at // /api/v1, and that host is exactly what entire login // authenticated against, so no extra configuration is needed. Override // with ENTIRE_AUTH_BASE_URL for non-default deployments (the same knob // entire login honours). // // Auth is the logged-in bearer, resolved lazily per request through // auth.TokenForResource so an RFC 8693 token exchange happens // transparently when the stored token's audience doesn't already cover // the control-plane host. // The host and bearer come from auth.ResolveControlPlaneTarget: the active // contexts.json login's core (so entire auth use <ctx> retargets the // control plane), or — when ENTIRE_AUTH_BASE_URL is set or no context is // active — the configured auth host. The Core API is served at // /api/v1. The bearer is resolved lazily per request; for an active // context it re-mints silently from the stored refresh token, and for the // static path an RFC 8693 exchange happens transparently when the stored // token's audience doesn't cover the core. func New() (*Client, error) { base := strings.TrimRight(api.AuthBaseURL(), "/") // The token exchange's resource must be the bare origin; api.OriginOnly // strips any path/query so the audience the manager keys on matches // what the server expects. src := &bearerSource{resourceBaseURL: api.OriginOnly(base)} client, err := NewClient(base+apiBasePath, src) target, err := auth.ResolveControlPlaneTarget() if err != nil { return nil, fmt.Errorf("resolve control-plane target: %w", err) } src := &providerSource{provide: target.TokenSource} client, err := NewClient(strings.TrimRight(target.CoreURL, "/")+apiBasePath, src) if err != nil { return nil, fmt.Errorf("build core API client: %w", err) }

return SessionAuth{}, ogenerrors.ErrSkipClientSecurity }

// bearerSource implements the generated SecuritySource, supplying the // logged-in user's bearer token for every request. The control plane // only uses bearerAuth from the CLI; the sessionAuth (browser cookie) // scheme is reported as ErrSkipClientSecurity so ogen's middleware // satisfies the "bearerAuth OR sessionAuth" requirement via the bearer // alone — without adding a stray Cookie: entire_session= header. // (Returning an empty SessionAuth would not skip the cookie: the // generated securitySessionAuth unconditionally calls req.AddCookie.) type bearerSource struct { resourceBaseURL string // providerSource implements the generated SecuritySource, supplying the // logged-in user's bearer token for every request from a token-provider // func (auth.ControlPlaneTarget.TokenSource). The control plane only uses // bearerAuth from the CLI; the sessionAuth (browser cookie) scheme is // reported as ErrSkipClientSecurity so ogen's middleware satisfies the // "bearerAuth OR sessionAuth" requirement via the bearer alone — without // adding a stray Cookie: entire_session= header. (Returning an empty // SessionAuth would not skip the cookie: the generated securitySessionAuth // unconditionally calls req.AddCookie.) type providerSource struct { provide func(context.Context) (string, error) }

func (b *bearerSource) BearerAuth(ctx context.Context, _ OperationName) (BearerAuth, error) { token, err := auth.TokenForResource(ctx, b.resourceBaseURL) func (p *providerSource) BearerAuth(ctx context.Context, _ OperationName) (BearerAuth, error) { token, err := p.provide(ctx) if err != nil { // Only suggest login when the user genuinely isn't logged in. // Other failures (STS rejection, network, malformed config) must // surface verbatim rather than be masked by a login hint. // Other failures (STS rejection, refresh-expired, network) already // carry descriptive messages and must surface verbatim rather than // be masked by a login hint. if errors.Is(err, auth.ErrNotLoggedIn) { return BearerAuth{}, fmt.Errorf("not logged in — run 'entire login': %w", err) } }

return BearerAuth{Token: token}, nil }

func (b *bearerSource) SessionAuth(context.Context, OperationName) (SessionAuth, error) { func (p *providerSource) SessionAuth(context.Context, OperationName) (SessionAuth, error) { // The CLI authenticates with a bearer token, never the browser // session cookie. ErrSkipClientSecurity tells ogen to drop this // scheme entirely for the request (no Cookie header added); the