Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions command-snapshot.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,20 @@
[
{
"alias": [],
"command": "org:auth:show-access-token",
"flagAliases": [],
"flagChars": ["o", "p"],
"flags": ["flags-dir", "json", "no-prompt", "target-org"],
"plugin": "@salesforce/plugin-org"
},
{
"alias": [],
"command": "org:auth:show-sfdx-auth-url",
"flagAliases": [],
"flagChars": ["o", "p"],
"flags": ["flags-dir", "json", "no-prompt", "target-org"],
"plugin": "@salesforce/plugin-org"
},
{
"alias": [],
"command": "org:create:agent-user",
Expand Down
41 changes: 41 additions & 0 deletions messages/org.auth.show-access-token.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# summary

Show the access token for an org.

# description

Displays the current access token for the specified org. Because access tokens are sensitive credentials that grant full access to an org, this command prompts for confirmation before revealing the token unless you pass --no-prompt or --json.

# flags.no-prompt.summary

Skip the security warning and reveal the access token without confirmation.

# prompt.show-access-token

You are about to reveal the access token for "%s". This token grants full access to the org with your current permissions. Sharing or logging this token is equivalent to sharing your credentials. Do you want to continue?

# warning.show-access-token

This command exposes a sensitive Access Token that allows for subsequent activity using your current authenticated session. Sharing this information is equivalent to logging someone in under the current credential, resulting in unintended access and escalation of privilege. For additional information, please review https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_auth.htm

# error.noAccessToken

No access token found for "%s". The org may need to be re-authenticated.

# examples

- Show the access token for the default org:

<%= config.bin %> <%= command.id %>

- Show the access token for a specific org:

<%= config.bin %> <%= command.id %> --target-org my-scratch-org

- Show the access token without the confirmation prompt:

<%= config.bin %> <%= command.id %> --target-org my-scratch-org --no-prompt

- Get the access token as JSON for use in scripts:

<%= config.bin %> <%= command.id %> --target-org my-scratch-org --json
41 changes: 41 additions & 0 deletions messages/org.auth.show-sfdx-auth-url.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# summary

Show the SFDX Auth URL for an org.

# description

Displays the SFDX Auth URL for the specified org. The SFDX Auth URL contains a refresh token that provides persistent access to the org without requiring re-authentication. This URL is only available for orgs authenticated via a web-based OAuth flow. Because this URL is equivalent to a permanent login credential, this command prompts for confirmation before revealing it unless you pass --no-prompt or --json.

# flags.no-prompt.summary

Skip the security warning and reveal the SFDX Auth URL without confirmation.

# prompt.show-sfdx-auth-url

You are about to reveal the SFDX Auth URL for "%s". This URL contains a refresh token that grants persistent access to the org without re-authentication. Anyone with this URL can authenticate to the org with your permissions. Do you want to continue?

# warning.show-sfdx-auth-url

This command exposes a sensitive SFDX Auth URL containing a refresh token that grants persistent access to the org. Unlike an access token, this credential does not expire and allows re-authentication without user interaction. Sharing this URL is equivalent to giving permanent login access to the org. For additional information, please review https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_auth_url.htm

# error.noRefreshToken

An SFDX Auth URL is not available for "%s". This URL is only available for orgs authenticated via a web-based login flow. Re-authenticate to the org using "sf org login web" to make it available.

# examples

- Show the SFDX Auth URL for the default org:

<%= config.bin %> <%= command.id %>

- Show the SFDX Auth URL for a specific org:

<%= config.bin %> <%= command.id %> --target-org my-scratch-org

- Show the SFDX Auth URL without the confirmation prompt:

<%= config.bin %> <%= command.id %> --target-org my-scratch-org --no-prompt

- Get the SFDX Auth URL as JSON for use in scripts:

<%= config.bin %> <%= command.id %> --target-org my-scratch-org --json
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@
},
"disable": {
"description": "Disable source tracking in an org."
},
"auth": {
"description": "Commands for printing sensitive auth info."
}
},
"external": true
Expand Down
16 changes: 16 additions & 0 deletions schemas/org-auth-show__access__token.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$ref": "#/definitions/OrgAuthShowAccessTokenResult",
"definitions": {
"OrgAuthShowAccessTokenResult": {
"type": "object",
"properties": {
"accessToken": {
"type": "string"
}
},
"required": ["accessToken"],
"additionalProperties": false
}
}
}
16 changes: 16 additions & 0 deletions schemas/org-auth-show__sfdx__auth__url.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$ref": "#/definitions/OrgAuthShowSfdxAuthUrlResult",
"definitions": {
"OrgAuthShowSfdxAuthUrlResult": {
"type": "object",
"properties": {
"sfdxAuthUrl": {
"type": "string"
}
},
"required": ["sfdxAuthUrl"],
"additionalProperties": false
}
}
}
81 changes: 81 additions & 0 deletions src/commands/org/auth/show-access-token.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* Copyright 2026, Salesforce, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { SfCommand, Flags } from '@salesforce/sf-plugins-core';
import { AuthInfo, Messages, SfError } from '@salesforce/core';

Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
const messages = Messages.loadMessages('@salesforce/plugin-org', 'org.auth.show-access-token');

export type OrgAuthShowAccessTokenResult = {
accessToken: string;
};

export default class OrgAuthShowAccessToken extends SfCommand<OrgAuthShowAccessTokenResult> {
public static readonly summary = messages.getMessage('summary');
public static readonly description = messages.getMessage('description');
public static readonly examples = messages.getMessages('examples');

public static readonly flags = {
'target-org': Flags.requiredOrg(),
'no-prompt': Flags.boolean({
summary: messages.getMessage('flags.no-prompt.summary'),
char: 'p',
}),
};

public async run(): Promise<OrgAuthShowAccessTokenResult> {
const { flags } = await this.parse(OrgAuthShowAccessToken);

const org = flags['target-org'];
const username = org.getUsername();
try {
// The auth file can have a stale access token. Refresh it before getting the fields
await org.refreshAuth();
} catch (error) {
// Even if this fails, we want to display the information we can read from the auth file
this.warn('Unable to refresh auth for org. Access token may be stale.');
}

// Don't ask for confirmation if --json or --no-prompt is passed
if (!this.jsonEnabled() && !flags['no-prompt']) {
const confirmed = await this.confirm({
message: messages.getMessage('prompt.show-access-token', [username]),
ms: 30_000,
});
if (!confirmed) {
throw new SfError('Show access token confirmation denied or timed out.');
}
} else {
// Note: We don't show this warning if the user has already been prompted
this.warn(messages.getMessage('warning.show-access-token'));
}

const authInfo = await AuthInfo.create({ username });
const { accessToken } = authInfo.getFields(true);

if (!accessToken) {
throw messages.createError('error.noAccessToken', [username]);
}

this.table({
overflow: 'wrap',
data: [{ key: 'Access Token', value: accessToken }],
});

return { accessToken };
}
}
74 changes: 74 additions & 0 deletions src/commands/org/auth/show-sfdx-auth-url.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Copyright 2026, Salesforce, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { SfCommand, Flags } from '@salesforce/sf-plugins-core';
import { AuthInfo, Messages, SfError } from '@salesforce/core';

Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
const messages = Messages.loadMessages('@salesforce/plugin-org', 'org.auth.show-sfdx-auth-url');

export type OrgAuthShowSfdxAuthUrlResult = {
sfdxAuthUrl: string;
};

export default class OrgAuthShowSfdxAuthUrl extends SfCommand<OrgAuthShowSfdxAuthUrlResult> {
public static readonly summary = messages.getMessage('summary');
public static readonly description = messages.getMessage('description');
public static readonly examples = messages.getMessages('examples');

public static readonly flags = {
'target-org': Flags.requiredOrg(),
'no-prompt': Flags.boolean({
summary: messages.getMessage('flags.no-prompt.summary'),
char: 'p',
}),
};

public async run(): Promise<OrgAuthShowSfdxAuthUrlResult> {
const { flags } = await this.parse(OrgAuthShowSfdxAuthUrl);

const org = flags['target-org'];
const username = org.getUsername();

if (!this.jsonEnabled() && !flags['no-prompt']) {
const confirmed = await this.confirm({
message: messages.getMessage('prompt.show-sfdx-auth-url', [username]),
ms: 30_000,
});
if (!confirmed) {
throw new SfError('Show SFDX auth URL confirmation denied or timed out.');
}
} else {
this.warn(messages.getMessage('warning.show-sfdx-auth-url'));
}

const authInfo = await AuthInfo.create({ username });
const { refreshToken } = authInfo.getFields(true);

if (!refreshToken) {
throw messages.createError('error.noRefreshToken', [username]);
}

const sfdxAuthUrl = authInfo.getSfdxAuthUrl();

this.table({
overflow: 'wrap',
data: [{ key: 'SFDX Auth URL', value: sfdxAuthUrl }],
});

return { sfdxAuthUrl };
}
}
Loading
Loading