Skip to content

datasource-oauth: admit http for local_egress-listed loopback addresses, so the authorization-code + PKCE grant can be proven against a local stub #1101

Open

Description

@antoinetoussaint-byte

The authorization-code + PKCE grant of a callable source cannot be proven against a local stub provider. The datasource-oauth/providers registration refuses every non-https authorize and token URL, including addresses that datasource-oauth/local_egress lists. The "Local egress" section says the allowance covers that exchange.

Found while proving obin-ai/platform-core#42 at v0.0.95. The full proof (script, stub, command, output) is in https://github.com/obin-ai/platform-core/issues/42#issuecomment-6134054905.

Evidence (v0.0.95, 4580390a)

  • The refusal. ConfigureDatasourceOAuth (module/services/accounts/code/pkg/business/datasource_oauth.go:33) returns
    datasource OAuth endpoints must be absolute HTTPS URLs
    at datasource_oauth.go:54 for any authorize_url / token_url whose scheme is not https.
    • accounts calls it during setup at module/services/accounts/code/work.go:370 and returns the error.
    • So a registration naming a loopback http stub stops accounts. I read this from the code; I did not boot it with such a registration.
  • The documentation says otherwise. module/CALLABLE_SOURCES.md:221 ("Local egress"): "It applies to the token exchange (refresh, client_credentials, authorization-code) and the operation call alike."
  • The registration is the only thing in the way.
    • The token exchange itself accepts http (pkg/datasource/apisource/client.go:377).
    • local_egress admits the listed loopback ip:port at dial time (pkg/datasource/apisource/local_egress.go:61).
    • With local_egress=127.0.0.1:18080,127.0.0.1:18081, the client_credentials grant against an http stub on those addresses passed end to end on v0.0.95: connect, declare, datasource.Invoke, Lookup, the stub received the host-minted bearer, and the credential was sealed cfs1:vault-transit:.
    • Command, from a platform-core checkout with that value in an uncommitted configurations/local/datasource-oauth.env, CLI 0.1.185:
      codefly run service frontend --fixture dev-admin --headless --naming-scope pc42
      HOST_LOG=<that log> ./run.sh
      
  • The consent redirect can already be driven locally over the API. Nothing beyond the registration blocks it:
    1. BeginDatasourceAccountLink (pkg/business/datasource_directory.go:259) returns oauthAccountLinker.AuthorizeURL (datasource_oauth.go:91), with an S256 code_challenge.
    2. A stub /authorize can auto-consent and redirect to redirect_uri with code and state.
    3. CompleteDatasourceAccountLink takes them.
    4. The host exchanges the code with its code_verifier (datasource_oauth.go:139).
  • No TLS workaround. Serving the stub over https would need a certificate the host trusts, meaning a mounted CA. That breaks the security posture (no mounted files), so the authorization-code grant stays not verified on Generate service secret configuration declarations from topology #42.

Ask

Admit http for a datasource-oauth/providers registration only when both of these hold:

  1. Under the same local-runtime refusal rules as feat(accounts): a local runtime may list loopback stubs a callable source can reach #1089:

    • the Codefly environment is local, and
    • the process is not in a Kubernetes pod.

    That is the predicate configureLocalEgress uses (work.go:2657, work.go:2703: isLocal && !infra.InCluster()).

  2. Both authorize_url and token_url name an exact ip:port entry of local_egress: a loopback IP literal, no hostname (not localhost), and the same port.

Everything else refuses exactly as today: non-local runtimes, unlisted addresses, hostnames, and http anywhere outside that case.

Startup order matters here. configureLocalEgress runs first in requireStartupConfiguration; ConfigureDatasourceOAuth must read the allowance it installed, not re-parse the value differently.

Done when

  • The full consent redirect is proven locally against a loopback http stub. A test (and/or the documented local proof) covers the whole chain:
    1. BeginDatasourceAccountLink;
    2. stub /authorize auto-consents;
    3. redirect with code / state;
    4. CompleteDatasourceAccountLink;
    5. the token exchange, with the stub checking code_verifier against the S256 code_challenge it received;
    6. a sealed envelope;
    7. a successful InvokeSourceOperation on the resulting personal source.
  • A non-local runtime still refuses an http registration (environment not local, or in-cluster), naming the key.
  • An http registration whose address is not listed in local_egress is refused, as is a hostname spelling.
  • CALLABLE_SOURCES.md "Local egress" and module/configurations/README.md describe the rule.

Related: #1049 (callable sources), #1087 / #1089 (local egress).

Not started. Filed from obin-ai/platform-core#42 with the owner's approval.

Activity

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