From f9465f0e0eeb6413b0bb9cd913b7ecd4140da054 Mon Sep 17 00:00:00 2001 From: Weilu Jia Date: Wed, 6 May 2026 18:57:32 -0700 Subject: [PATCH] fix: Fix incorrect gating of ACCESS_TOKEN for template commands --- .changeset/quiet-tables-build.md | 5 ++ packages/cli/README.md | 5 +- packages/cli/src/api.ts | 52 ++++++++++++++----- packages/cli/src/commands/template/build.ts | 9 ++-- .../src/commands/template/buildWithProxy.ts | 4 +- packages/cli/src/commands/template/create.ts | 10 ++-- packages/cli/src/commands/template/list.ts | 4 +- 7 files changed, 58 insertions(+), 31 deletions(-) create mode 100644 .changeset/quiet-tables-build.md diff --git a/.changeset/quiet-tables-build.md b/.changeset/quiet-tables-build.md new file mode 100644 index 0000000000..1a4a711ed4 --- /dev/null +++ b/.changeset/quiet-tables-build.md @@ -0,0 +1,5 @@ +--- +'@e2b/cli': patch +--- + +Allow template build and create commands to authenticate with either an API key or access token. diff --git a/packages/cli/README.md b/packages/cli/README.md index 9009bd1523..9b8ceebf41 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -28,9 +28,8 @@ e2b auth login > [!NOTE] > To authenticate without the ability to open the browser, provide -> `E2B_ACCESS_TOKEN` as an environment variable. You can find your token -> in Account Settings under the Team selector at [e2b.dev/dashboard](https://e2b.dev/dashboard). Then use the CLI like this: -> `E2B_ACCESS_TOKEN=sk_e2b_... e2b template build`. +> `E2B_API_KEY` or `E2B_ACCESS_TOKEN` as an environment variable. Then use the +> CLI like this: `E2B_API_KEY=e2b_... e2b template build`. > [!IMPORTANT] > Note the distinction between `E2B_ACCESS_TOKEN` and `E2B_API_KEY`. diff --git a/packages/cli/src/api.ts b/packages/cli/src/api.ts index 29b39a50e1..1fe74e5aa6 100644 --- a/packages/cli/src/api.ts +++ b/packages/cli/src/api.ts @@ -8,6 +8,26 @@ export let apiKey = process.env.E2B_API_KEY export let accessToken = process.env.E2B_ACCESS_TOKEN export const teamId = process.env.E2B_TEAM_ID +function resolveAPIKey() { + // If apiKey is not already set (either from env var or from user config), try to get it from config file + if (!apiKey) { + const userConfig = getUserConfig() + apiKey = userConfig?.teamApiKey + } + + return apiKey +} + +function resolveAccessToken() { + // If accessToken is not already set (either from env var or from user config), try to get it from config file + if (!accessToken) { + const userConfig = getUserConfig() + accessToken = userConfig?.accessToken + } + + return accessToken +} + const authErrorBox = (keyName: string) => { let link let msg @@ -45,17 +65,13 @@ Visit ${asPrimary(link)} to get the ${msg}.`, } export function ensureAPIKey() { - // If apiKey is not already set (either from env var or from user config), try to get it from config file - if (!apiKey) { - const userConfig = getUserConfig() - apiKey = userConfig?.teamApiKey - } + const resolvedApiKey = resolveAPIKey() - if (!apiKey) { + if (!resolvedApiKey) { console.error(authErrorBox('E2B_API_KEY')) process.exit(1) } else { - return apiKey + return resolvedApiKey } } @@ -69,18 +85,26 @@ export function ensureUserConfig(): UserConfig { } export function ensureAccessToken() { - // If accessToken is not already set (either from env var or from user config), try to get it from config file - if (!accessToken) { - const userConfig = getUserConfig() - accessToken = userConfig?.accessToken - } + const resolvedAccessToken = resolveAccessToken() - if (!accessToken) { + if (!resolvedAccessToken) { console.error(authErrorBox('E2B_ACCESS_TOKEN')) process.exit(1) } else { - return accessToken + return resolvedAccessToken + } +} + +export function ensureAPIKeyOrAccessToken() { + const resolvedApiKey = resolveAPIKey() + const resolvedAccessToken = resolveAccessToken() + + if (resolvedApiKey || resolvedAccessToken) { + return { apiKey: resolvedApiKey, accessToken: resolvedAccessToken } } + + console.error(authErrorBox('E2B_API_KEY')) + process.exit(1) } /** diff --git a/packages/cli/src/commands/template/build.ts b/packages/cli/src/commands/template/build.ts index 89f9f2b11d..d8ae149016 100644 --- a/packages/cli/src/commands/template/build.ts +++ b/packages/cli/src/commands/template/build.ts @@ -8,7 +8,7 @@ import * as path from 'path' import { client, connectionConfig, - ensureAccessToken, + ensureAPIKeyOrAccessToken, resolveTeamId, } from 'src/api' import { configName, getConfigPath, loadConfig, saveConfig } from 'src/config' @@ -246,7 +246,8 @@ Migration guide: ${asPrimary('https://e2b.dev/docs/template/migration-v2')}` }) } - const accessToken = ensureAccessToken() + const credentials = ensureAPIKeyOrAccessToken() + const dockerAuthToken = credentials.accessToken ?? credentials.apiKey! process.stdout.write('\n') const newName = opts.name?.trim() @@ -377,7 +378,7 @@ Migration guide: ${asPrimary('https://e2b.dev/docs/template/migration-v2')}` if (imageUriMask == undefined) { try { child_process.execSync( - `echo "${accessToken}" | docker login docker.${connectionConfig.domain} -u _e2b_access_token --password-stdin`, + `echo "${dockerAuthToken}" | docker login docker.${connectionConfig.domain} -u _e2b_access_token --password-stdin`, { stdio: 'inherit', cwd: root, @@ -449,7 +450,7 @@ Migration guide: ${asPrimary('https://e2b.dev/docs/template/migration-v2')}` await buildWithProxy( userConfig, connectionConfig, - accessToken, + dockerAuthToken, template, root ) diff --git a/packages/cli/src/commands/template/buildWithProxy.ts b/packages/cli/src/commands/template/buildWithProxy.ts index 4893487985..c569ee8ec7 100644 --- a/packages/cli/src/commands/template/buildWithProxy.ts +++ b/packages/cli/src/commands/template/buildWithProxy.ts @@ -12,7 +12,7 @@ const PORT = 49984 export async function buildWithProxy( userConfig: UserConfig | null, connectionConfig: e2b.ConnectionConfig, - accessToken: string, + dockerAuthToken: string, template: { templateID: string; buildID: string }, root: string ) { @@ -39,7 +39,7 @@ export async function buildWithProxy( }) const accessTokenBase64Encoded = Buffer.from( - `_e2b_access_token:${accessToken}` + `_e2b_access_token:${dockerAuthToken}` ).toString('base64') const proxyServer = await proxy( diff --git a/packages/cli/src/commands/template/create.ts b/packages/cli/src/commands/template/create.ts index 2480b87ea5..5ff1b36b25 100644 --- a/packages/cli/src/commands/template/create.ts +++ b/packages/cli/src/commands/template/create.ts @@ -1,7 +1,7 @@ import * as boxen from 'boxen' import * as commander from 'commander' import { defaultBuildLogger, Template, TemplateClass } from 'e2b' -import { connectionConfig, ensureAccessToken, ensureAPIKey } from 'src/api' +import { connectionConfig, ensureAPIKeyOrAccessToken } from 'src/api' import { defaultDockerfileName, fallbackDockerfileName, @@ -68,8 +68,7 @@ export const createCommand = new commander.Command('create') } ) => { try { - // Ensure we have access token - ensureAccessToken() + const credentials = ensureAPIKeyOrAccessToken() process.stdout.write('\n') // Validate template name @@ -131,8 +130,6 @@ export const createCommand = new commander.Command('create') console.log('\nBuilding sandbox template...\n') - // Prepare API credentials for SDK - const apiKey = ensureAPIKey() const domain = connectionConfig.domain // Build the template using SDK @@ -142,7 +139,8 @@ export const createCommand = new commander.Command('create') cpuCount: cpuCount, memoryMB: memoryMB, skipCache: opts.noCache, - apiKey: apiKey, + apiKey: credentials.apiKey, + accessToken: credentials.accessToken, domain: domain, onBuildLogs: defaultBuildLogger(), }) diff --git a/packages/cli/src/commands/template/list.ts b/packages/cli/src/commands/template/list.ts index c0a934ae7c..50a8f451c7 100644 --- a/packages/cli/src/commands/template/list.ts +++ b/packages/cli/src/commands/template/list.ts @@ -4,7 +4,7 @@ import * as e2b from 'e2b' import { listAliases } from '../../utils/format' import { sortTemplatesAliases } from 'src/utils/templateSort' -import { client, ensureAccessToken, resolveTeamId } from 'src/api' +import { client, ensureAPIKeyOrAccessToken, resolveTeamId } from 'src/api' import { teamOption } from '../../options' import { handleE2BRequestError } from '../../utils/errors' @@ -16,7 +16,7 @@ export const listCommand = new commander.Command('list') .action(async (opts: { team: string; format: string }) => { try { const format = opts.format || 'pretty' - ensureAccessToken() + ensureAPIKeyOrAccessToken() process.stdout.write('\n') const templates = await listSandboxTemplates({