Skip to content

API Access Control causes authing with SF CLI using ExternalClientApps to get caught in a neverending auth loop #3428

@goto-dev-null

Description

@goto-dev-null

Note
Before you submit your issue, make sure that:

  • You're using the latest version of Salesforce CLI.
  • You've searched both open and closed issues for related posts.
  • You've used the doctor command to diagnose common issues.
  • You understand that GitHub Issues don't adhere to any agreement or SLA.
    • If you require immediate assistance, use official channels such as Salesforce Customer Support.

Summary

We switched to using an ExternalClientApp a while ago and fairly recently, we've run into a problem where commands hang when attempting to run commands against sandboxes when authing with JWT. It's taken a long time to track down the actual cause, but it is because the affected commands get stuck in a loop of authing then printing "Access token has expired. Updating..." until the CI User gets "Login Limit Reached" in the target org.

I've tracked this down to it being from us using an ECA that is "Packaged (Associated)", i.e. that was created in our Production Org and brought down to sandbox either during creation or by Change Set (see "Additional Information" for further details). A seemingly related issue is #3297, but the resolution for it does not solve our problem: Issue JSON Web Token (JWT)-based access tokens for named users is disabled in our ExternalClientApp.

Steps To Reproduce

IMPORTANT
Provide a repository that's configured to reproduce the issue. If you are unable to provide a repo, please explain why not. The more info we have from the start, the faster we can resolve your issue.
We may close your issue if you don't include proper instructions.

  • Generate a project with sf project generate or fork dreamhouse-lwc.
  • Provide detailed step-by-step instructions on how to reproduce the issue.

https://github.com/goto-dev-null/sf-eca-issue

This contains an ExternalClientApp created in a Developer org I created. Because API Access Control is not even an option without contacting Support, you must creating a scratch org based on an org with the setting enabled. I have a Developer org that I have had Support enable this setting for (00Dg5000000EfoE), so if you use its ID with the --source-org flag, that would enable it in the scratch org. Alternatively, if you have a Sandbox in which API Access Control can be enabled, I believe you should be able to deploy there and test.

The steps to reproduce are as follows:

  1. If using my Developer org, auth to it.
  • echo "force://PlatformCLI::5Aep8618MtpGySpPxgg6huEz_GFIAjoEP9q6xYuh7RlVzgxla.tM2PWKNYAIOyhnxPK3XAXy0N7U7SJz3wgvVXY@orgfarm-7010234278-dev-ed.develop.my.salesforce.com" | sf org login sfdx-url --sfdx-url-stdin
  1. Either create a scratch org or sandbox based on an org that has Api Access Control capability
  • sf scratch org create --set-default --source-org 00Dg5000000EfoE --target-dev-hub [email protected] --wait 30
  • Note: I have not tested this in a sandbox that is not based on our Production org
  1. Deploy just the ExternalClientApplication and ExtlClntAppOauthSettings files to the org
  • sf project deploy start --metadata ExternalClientApplication --metadata ExtlClntAppOauthSettings
  1. In the org, edit the ExternalClient App by changing the policy to Admin approved users are pre-authorized and then add the System Administrator Profile
  • sf org open --path lightning/setup/ManageExternalClientApplication/home
  1. In the org, enable the API Access Control setting (For admin-approved users, limit API access to only allowlisted connected apps)
  • sf org open --path lightning/setup/ApiAccessControl/home
  1. Set the DEBUG and SF_LOG_LEVEL environment variables (sf:oclif:AuthInfo and info, respectively)
  • PowerShell: $Env:DEBUG = 'sf:oclif:AuthInfo' ; $Env:SF_LOG_LEVEL = 'info'
  • fish: set --export DEBUG 'sf:oclif:AuthInfo' ; set --export SF_LOG_LEVEL 'info'
  • bash: export DEBUG="sf:oclif:AuthInfo" ; export SF_LOG_LEVEL="info"
  1. Auth using JWT
  • ⚠️ NOTE Adjust the below so that --username is the username for your scratch org
  • sf org login jwt --username [email protected] --alias jwtscratch --jwt-key-file ./server.key --client-id 3MVG97L7PWbPq6UxDRrTQF2k5okchEE0d7TCrD_R7tsu2_cgehE_0Yms3a0eawa06p_2Aj.kkHnRZSIDeAn9w
  1. Run an SF command for the alias above
  • ⚠️ NOTE This must be the auth that you performed by JWT; running this for the auth from creating the sandbox (probably?) won't reproduce the issue.
  • sf org display --target-org jwtscratch is the most simple, but see "Additional Information" for other commands that I can confirm suffer from it.
  1. BONUS: While the above command is running in its forever loop, you can disable the API Access Control setting, and the command will unhang.
  • sf org open --path lightning/setup/ApiAccessControl/home

⚠️ WARNING! ⚠️ After doing the above, running sf org list will hang as well, so you will need to run sf org logout --target-org jwtscratch.

Expected result

Normal output the command you ran.

Actual result

[13:50:08.759] INFO (sf:oclif:AuthInfo): Returning fields for a connection using JWT config.
[13:50:09.219] INFO (sf:oclif:AuthInfo): Access token has expired. Updating...
[13:50:11.523] INFO (sf:oclif:AuthInfo): Updated auth info for username: [email protected]
[13:50:11.525] INFO (sf:oclif:AuthInfo): Saved auth info for username: [email protected]
[13:50:11.803] INFO (sf:oclif:AuthInfo): Access token has expired. Updating...
[13:50:14.360] INFO (sf:oclif:AuthInfo): Updated auth info for username: [email protected]
[13:50:14.362] INFO (sf:oclif:AuthInfo): Saved auth info for username: [email protected]
[13:50:14.725] INFO (sf:oclif:AuthInfo): Access token has expired. Updating...
[13:50:16.814] INFO (sf:oclif:AuthInfo): Updated auth info for username: [email protected]
[13:50:16.816] INFO (sf:oclif:AuthInfo): Saved auth info for username: [email protected]
[13:50:17.763] INFO (sf:oclif:AuthInfo): Access token has expired. Updating...

and etc forever.

Additional information

First to call out, the issue template says You're using the latest version of Salesforce CLI.. We have been using the stable version of SF in CI, but I just tested with latest (2.110.13) and reproduced the same issue. So, while the version info for this ticket & the sf doctor results will contain information about the stable version, please rest assured that this has been reproduced on the latest as well.

Secondly, it says You've used the 'doctor' command to diagnose common issues.. The results of sf doctor are checked into the linked repo; the non-pass results are:

  • fail: [@salesforce/plugin-auth] CLI supports v2 crypto
    • ⚠️ Could this possibly be related? The docs for this seem to indicate how auth files are stored locally, so I would not think so, but want to call it out.
    • Our CI grabs the stable SF tarball, so I do not know why this is given as "fail"; we do not specify anywhere to use a specific version of the auth plugin so, afaik, we are not doing anything non-standard
  • warn: [@salesforce/plugin-deploy-retrieve] sourceApiVersion matches default target org max apiVersion
    • Admittedly, our sourceApiVersion is still on 64.0. But I do not see how that could be an actual problem.

This definitely started after we enabled the recent API Access Control security update, but it also seems to possibly be related to the recent Winter '25 release, as we never encountered the commands hanging for our long-running sandboxes until just this week when we refreshed them. Though now that I think about it, it might just be because the sandboxes did not have the setting available before refreshing.

Ultimately what this causes is our CI User hitting "Login Limit Exceeded" in the target sandbox, but it's clear that it's because the commands keep authing repeatedly until the limit is hit. (This is reflected in the Login History for our CI User, which has 1-2x/second.)

The reason that I know that this is specifically restricted to ECAs that are "Packaged (Associated)" is that, as part of troubleshooting, I created an ECA in the sandbox (still declared as "Packaged") and suddenly the issue went away: commands that used to hang for 15-60+ minutes now executed in 5 seconds. However, when I created a new identical ExternalClientApp in our DevHub/Production org and Change Set'd it to the same affected Sandboxes, the problem reappeared.

While it is in the metadata of the linked repo, the only configuration that I can think of that could be relevant is that the Scopes for the ECA are Api, Web, RefreshToken.

The commands we have encountered that have this issue include:

  • sf org list
  • sf apex run (no execution is ever started in the org)
  • sf project manifest generate
  • sf org display (not part of our CI but have experienced it locally)

Though this is by no means comprehensive; it's highly possible that other commands encounter the same issue, but our CD never made it to the point to execute them, having been hung up on the above list.

System Information

Our CI uses PowerShell 7 for scripting. The below JSON reports "bash", but as far as I can tell, that is reporting the default shell, but the shell that is actually running, because this is the result of running in the pwsh step.

{
    "architecture": "linux-x64",
    "cliVersion": "@salesforce/cli/2.108.6",
    "nodeVersion": "node-v22.19.0",
    "osVersion": "Linux 6.11.0-1018-azure",
    "rootPath": "/home/vsts/work/1/b/sf",
    "shell": "bash",
    "pluginVersions": [
        "@oclif/plugin-autocomplete 3.2.35 (core)",
        "@oclif/plugin-commands 4.1.33 (core)",
        "@oclif/plugin-help 6.2.33 (core)",
        "@oclif/plugin-not-found 3.2.68 (core)",
        "@oclif/plugin-plugins 5.4.47 (core)",
        "@oclif/plugin-search 1.2.31 (core)",
        "@oclif/plugin-update 4.7.7 (core)",
        "@oclif/plugin-version 2.2.33 (core)",
        "@oclif/plugin-warn-if-update-available 3.1.48 (core)",
        "@oclif/plugin-which 3.2.40 (core)",
        "@salesforce/cli 2.108.6 (core)",
        "agent 1.24.13 (core)",
        "apex 3.8.1 (core)",
        "api 1.3.3 (core)",
        "auth 3.9.8 (core)",
        "data 4.0.57 (core)",
        "deploy-retrieve 3.23.3 (core)",
        "info 3.4.88 (core)",
        "limits 3.3.67 (core)",
        "marketplace 1.3.8 (core)",
        "org 5.9.30 (core)",
        "packaging 2.20.5 (core)",
        "schema 3.3.82 (core)",
        "settings 2.4.48 (core)",
        "sobject 1.4.73 (core)",
        "telemetry 3.6.57 (core)",
        "templates 56.3.65 (core)",
        "trust 3.7.113 (core)",
        "user 3.6.38 (core)"
    ]
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugIssue or pull request that identifies or fixes a bugvalidatedVersion information for this issue has been validated

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions