Repository navigation
feat(portals): call the Auth0 CLI from the tool and bundle it (Beta) - #1739
Open
jacobovidal wants to merge 11 commits into
Open
jacobovidal wants to merge 11 commits into
jacobovidal wants to merge 11 commits into
Conversation
Add a Management API client that runs `auth0 api` instead of talking to a local proxy. The CLI owns the login and the token, so the script never holds a credential. Request bodies go to the command on stdin: they carry client secrets, and process arguments are visible to every process on the machine. Failures are mapped to the errors the rest of the code already handles: the API's status, code and message become an ApiError, a missing scope becomes the 403 the permission check reads, and a session that cannot be used asks the user to log in. The first request runs alone, then up to four run together, so several processes never refresh an expired token at the same time. The client is not used yet. A later change selects it. Co-Authored-By: Claude <noreply@anthropic.com>
Decide how the script reaches the Management API when it starts. If the plugin framework passed a proxy, that proxy is used as before. If the Auth0 CLI started the script and passed its path and the tenant, requests go through `auth0 api`. Run by hand with nothing set, the script uses `auth0` on the PATH and the CLI's active tenant. The tenant comes from the --tenant flag first, then the environment, then the CLI's active tenant. One function builds the API client for every command. Tests can no longer reach the real CLI by accident: the test helper gives every run a runner that refuses to start a process, and a test fails if the empty-environment case ever calls it. Co-Authored-By: Claude <noreply@anthropic.com>
Only setup checked scopes, and it printed the login command twice. Audit and every other call showed a bare "Insufficient scope" error. A missing scope is now explained the same way everywhere, and the advice covers both ways the Auth0 CLI can be signed in. A user login can ask for more scopes with `auth0 login --scopes`. A client-credentials (machine to machine) login cannot, so the scope has to be added to that application's Management API grant. When any one of several scopes is enough, the first one is suggested. Co-Authored-By: Claude <noreply@anthropic.com>
Each call through the Auth0 CLI takes about a second and a half, mostly the CLI starting up, so reading one thing after another made the permission check and the audit slow. The permission probes are now sent together, and their answers are read in the order of the probes, so the report and the first error do not depend on which answer came back first. The audit reads the application with its grants and connections, the resource servers, the forms, the custom domain and the organization together, once the portal itself is read. Writes stay one at a time. Co-Authored-By: Claude <noreply@anthropic.com>
The Auth0 CLI will embed the setup and audit tool as one file that `node` can run. `npm run bundle` builds that file with esbuild: one ES module with the dependencies included, no sourcemap, and the same bytes every time it runs. The first lines of the file record a hash of everything it is built from: the sources, the lockfile and the build script. A test can recompute the hash, so a bundle that is older than its sources is caught. The hash is of text with LF line endings so a Windows checkout gives the same value, and its definition is pinned by a test. The unused `auth0` package is removed. It was the source of the two moderate audit findings, and nothing imported it. esbuild is added as a development dependency at an exact version, and the lockfile keeps public registry URLs. Co-Authored-By: Claude <noreply@anthropic.com>
Add the file the Auth0 CLI will embed, built with `npm run bundle` from the sources in the _source folder. It is generated, so it is not meant to be reviewed line by line: `.gitattributes` marks it as generated so GitHub folds it, and a test fails when the sources change without the bundle being rebuilt. Co-Authored-By: Claude <noreply@anthropic.com>
The audit failed against a real tenant with "Additional properties not allowed: per_page,page". The endpoint that lists an application's connections pages by checkpoint (a count, a token to start from, and a `next` token in the response) and rejects page numbers, but every list was read with page numbers. That endpoint now has its own helper that follows the `next` token. The test double was too forgiving: it accepted page numbers on this endpoint, so no test noticed. It now behaves like the real endpoint, and a test reads an application with more connections than one page. The bundle is rebuilt in the same commit, because a test fails when the bundle is older than its sources. Co-Authored-By: Claude <noreply@anthropic.com>
`auth0 api` reads stdin until it ends for every method except GET, even when there is no body, and waits forever if it never ends. The transport closes stdin for every request, but nothing tested that. A test now runs a stand-in command that reads stdin to the end and fails after a few seconds if the request does not finish. The stand-in stops by itself, so a failing run does not keep the test process alive. Co-Authored-By: Claude <noreply@anthropic.com>
This was referenced Oct 26, 2026
jacobovidal
marked this pull request as ready for review
October 26, 2026 17:27
The scope message was matched on all of the CLI's output first, so an API error whose message quoted "lacks scope" was reported as a missing permission. The API error now comes first, its body is read to the end of the output (the CLI prints long bodies over several lines), and the status must not be part of a longer number. Co-Authored-By: Claude <noreply@anthropic.com>
The login test checked for text the message always contains, the half-set proxy test looked for the token name with a trailing comma, and no test proved that the source files are hashed in sorted order. They now check the CLI's own reason, the bare variable name, and a tree whose sorted order differs from the order a directory walk finds it. Co-Authored-By: Claude <noreply@anthropic.com>
The header of api.ts still said every request goes through the loopback proxy, which is no longer true now that the auth0 api command is used as well. The bundle is rebuilt because it carries the comment. Co-Authored-By: Claude <noreply@anthropic.com>
4 tasks
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🔧 Changes
Second of three stacked PRs (on #1738). It changes only the TypeScript tool and adds its single-file build. Nothing in the CLI uses the file yet.
auth0 apitransport. The tool calls the Management API by runningauth0 apiinstead of talking to a local proxy, so the CLI keeps the login and the token. Request bodies go to the command on stdin, because they carry client secrets and process arguments are visible to other processes. The first request runs alone and then up to four run together, so several processes never refresh an expired token at once.AUTH0_CLI_BINandAUTH0_CLI_TENANT_DOMAINif the CLI passes them, and otherwiseauth0on the PATH and the active tenant. The--tenantflag wins.auth0 login --scopesfor a user login, or adding the scope to the application's Management API grant for a client-credentials login. Onlysetupdid this before, and it printed the login command twice.setupstay one at a time.Additional properties not allowed: per_page,page): the endpoint that lists an application's connections pages by checkpoint and rejects page numbers. It now has its own helper. The test double was too forgiving and accepted page numbers there; it now behaves like the real endpoint.npm run bundlebuilds one ES module with esbuild (new dev dependency, exact version, in_sourceonly). The first lines record a hash of the sources, the lockfile and the build script; a test fails when the committed file is older than its sources..gitattributesmarks the file as generated so GitHub folds it.auth0npm package is removed. It was the source of two moderate audit findings and nothing imported it. The lockfile uses public registry URLs, and a test keeps it that way.auth0 apiwaits for stdin to end on every method except GET, so a transport that left it open would hang.Dependabot watches only
gomodandbundlerin this repository, so the TypeScript dependencies get no automated updates. Adding annpmecosystem is a.githubchange that I left for a maintainer to decide.📚 References
Stacked on #1738. Followed by #1740.
🔬 Testing
Beyond the unit tests, the built file was run by hand against a development tenant with the installed CLI (v1.32.0): an audit of two existing portals, a consumer setup and a second run that reused everything, a business setup that found its user by email, and an audit of each new portal (no errors, no warnings). Everything the runs created was deleted afterwards and checked.
That run found the paging bug above, which no unit test had caught. Flows that have not run against a real tenant yet: the interactive prompts (organization and role creation, the user picker) and
audit --fix.📝 Checklist
🤖 Generated with Claude Code