Skip to content

feat(plugins): add loopback proxy with scope enforcement and secret stripping - #1728

Open
developerkunal wants to merge 1 commit into
DXCDT-2603/plugin-storefrom
DXCDT-2606/loopback-proxy
Open

developerkunal wants to merge 1 commit into
DXCDT-2603/plugin-storefrom
DXCDT-2606/loopback-proxy

Conversation

@developerkunal

@developerkunal developerkunal commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

🔧 Changes

Adds internal/plugins/proxy, which sits between a plugin process and the Auth0 Management API. A plugin never gets the real access token. It gets a random secret for the run and calls a local HTTPS proxy, which swaps in the real token on the calls it decides to forward. Nothing calls the proxy yet, so there is no user visible change.

The proxy listens on 127.0.0.1 on a random port with a certificate made for that run, and a plugin is pointed at it through AUTH0_PLUGIN_DOMAIN and AUTH0_PLUGIN_MANAGEMENT_TOKEN.

Requests are denied by default

  • The bearer secret must match, and the Host header must be the proxy address.
  • Paths must already be canonical and start with /api/v2/. Odd paths are rejected, never repaired, so the path that is checked is the path that is forwarded.
  • Every call must match a rule in the scope table, and one of the scopes the command declared must satisfy it. Otherwise the call gets a 403 that names the missing scope when there is one.
  • Only a few safe headers are forwarded, and the plugin's own Authorization header is dropped.

Responses

  • Secret fields are removed by key name, at any depth, from every JSON response. A response the proxy cannot inspect (non JSON, compressed or too large) is replaced with a 502. So is an upstream redirect, because the token should never be sent anywhere the proxy did not choose.
  • When the tenant answers 401, concurrent calls share one token refresh and the request is retried once. A session that cannot be renewed gives the plugin a session_expired error.

Fail closed. The proxy refuses to start if the registry index does not publish a scope table or a list of secret fields, because forwarding without either would be fail open.

Existing code. In internal/plugins/registry, scopeTable and secretFields were opaque raw JSON. They are now typed and validated. This is a deliberate change: an index with either field in any other shape is now rejected when parsed.

📚 References

DXCDT-2606. Part of the plugin framework stack of 11 PRs, and it builds on the one below it (DXCDT-2603).

🔬 Testing

The new code is covered by unit tests.

📝 Checklist

  • All new/changed/fixed functionality is covered by tests (or N/A)
  • I have added documentation for all new/changed functionality (or N/A)

@developerkunal
developerkunal requested a review from a team as a code owner October 24, 2026 14:47
Comment thread internal/plugins/proxy/proxy.go Resolved
@developerkunal
developerkunal force-pushed the DXCDT-2606/loopback-proxy branch from 9ca63e8 to 172b55b Compare October 24, 2026 15:30
@developerkunal
developerkunal force-pushed the DXCDT-2606/loopback-proxy branch 2 times, most recently from 2063021 to 3460887 Compare November 2, 2026 14:31
…tripping

- Adds internal/plugins/proxy, a per-run HTTPS proxy on 127.0.0.1 that a plugin calls with a per-run secret instead of the real token.
- Denies by default: paths must be canonical and under /api/v2/, methods are allowlisted, and each call must match a rule in the scope table that one of the command's declared scopes satisfies. A denied call gets a 403 that names the missing scope.
- Removes secret fields from every JSON response, rejects responses it cannot inspect, and drops request headers that are not on an allowlist.
- Refreshes the token once for concurrent 401s, caps refreshes per run, bounds in-flight calls, and exposes a one-line summary of the calls it denied.
- Types the scopeTable and secretFields index fields in the registry package with schema validation shared with the proxy.
@developerkunal
developerkunal force-pushed the DXCDT-2606/loopback-proxy branch from 3460887 to b892768 Compare November 2, 2026 19:37

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant