Authentication

Salesforce Toolkit supports multiple authentication methods to connect to Salesforce. This guide will help you choose the right authentication method for your use case.

Quick Reference

Here’s a quick reference table of available authentication methods:

Method

Use case

CLI Authentication

Local development with Salesforce CLI installed

OAuth Username-Password

Legacy scripts; prefer a headless integration flow for production

OAuth JWT Bearer

Server-to-server integration with a signing key

OAuth Client Credentials

Service integration as a configured Run As user

SOAP Security Token

Legacy applications needing password and security-token authentication

SOAP IP Filtering

Orgs with IP restrictions enabled

Lazy Authentication (Auto-selection)

For most use cases, you can use the lazy_login function which automatically selects the appropriate authentication method based on the provided parameters:

from sf_toolkit import SalesforceClient, lazy_login

# CLI Authentication
client = SalesforceClient(login=lazy_login(sf_cli_alias="my-org"))

# OAuth JWT Bearer Flow
with open("private_key.pem", "rb") as f:
    private_key_data = f.read()
client = SalesforceClient(
    login=lazy_login(
        username="user@example.com",
        consumer_key="your_consumer_key",
        private_key=private_key_data
    )
)

# Username-Password Flow
client = SalesforceClient(
    login=lazy_login(
        username="user@example.com",
        password="password",
        consumer_key="your_consumer_key",
        consumer_secret="your_consumer_secret"
    )
)

CLI-based Authentication

If you’re using the Salesforce CLI (sf or sfdx), this is the simplest method for local development:

from sf_toolkit import SalesforceClient, cli_login

# Use default org from CLI
client = SalesforceClient(login=cli_login())

# Use a specific org by alias or username
client = SalesforceClient(login=cli_login(alias_or_username="my-dev-org"))

# Specify the path to the CLI executable
client = SalesforceClient(login=cli_login(sf_exec_path="/custom/path/to/sf"))

This method:

  • Uses the existing authentication from your Salesforce CLI

  • Doesn’t require storing credentials in your code

  • Works with any authentication method supported by the CLI

  • Automatically handles token refresh

OAuth 2.0 Authentication

Salesforce Toolkit supports several OAuth 2.0 flows for different use cases:

The table above is a starting point, not a guarantee of security. Use a dedicated integration identity, least-privilege permissions, protected secrets, and a rotation policy. OAuth scopes do not grant permissions the user lacks. Prefer an explicit login factory when the flow is known; lazy_login selects by the presence of credential fields, so extra fields can change its selection.

Username-Password Flow

For simple scripting and personal applications:

from sf_toolkit import SalesforceClient
from sf_toolkit.auth import password_login

client = SalesforceClient(
    login=password_login(
        username="user@example.com",
        password="password",
        consumer_key="your_consumer_key",
        consumer_secret="your_consumer_secret",
        domain="login"  # or your custom domain
    )
)

Warning

This method requires storing your password in your code or configuration. Consider using other methods for production applications.

JWT Bearer Flow

For secure server-to-server integration:

import pathlib
from sf_toolkit import SalesforceClient
from sf_toolkit.auth import public_key_auth_login

# Load private key
private_key_path = pathlib.Path("path/to/private_key.key")
private_key = private_key_path.read_bytes()

client = SalesforceClient(
    login=public_key_auth_login(
        username="user@example.com",
        consumer_key="your_connected_app_consumer_key",
        private_key=private_key,
        domain="login"  # or your custom domain
    )
)

This method:

  • Does not require storing user passwords

  • Uses digital signatures to securely authenticate

  • Is ideal for automated applications and server-to-server integrations

  • Requires a connected app with a digital certificate

Encrypted keys and reusable app credentials

Install sf-toolkit[jwt]. The factory accepts PKCS#8/traditional PEM, OpenSSH RSA private keys, or an already loaded cryptography RSAPrivateKey. RSA keys must be at least 2048 bits; 3072 and 4096 bits are supported. Key material is the file contents, not a filename. Encrypted material takes private_key_passphrase as bytes or text:

import os
from pathlib import Path
from sf_toolkit import SalesforceClient
from sf_toolkit.auth import public_key_auth_login

# The app/key may be shared; bind the exact Salesforce username explicitly.
login = public_key_auth_login(
    username=os.environ["SF_USERNAME"],
    consumer_key=os.environ["SF_CONSUMER_KEY"],
    private_key=Path(os.environ["SF_JWT_KEY_FILE"]).read_bytes(),
    private_key_passphrase=os.environ["SF_JWT_KEY_PASSPHRASE"],
    domain="company--uat.sandbox.my.salesforce.com",
)
client = SalesforceClient(login=login, api_version=66)
try:
    client.get("/services/oauth2/userinfo")
finally:
    client.close()

lazy_login forwards private_key_passphrase too. Alternatively, use sf_toolkit.auth.load_private_key(material, passphrase) and pass the returned RSA key object without a passphrase. Decrypted keys stay in memory and are not written to disk. Never log the input key, passphrase, or token.

External Client App setup and certificate lifecycle

In Salesforce External Client App Manager, enable OAuth, the api scope, and JWT Bearer Flow. Upload the public certificate, never the private key. Pre-authorize the integration user through the app policy and an assigned permission set. Use the Consumer Key as consumer_key; JWT bearer does not need a Consumer Secret. Follow Salesforce’s current setup guidance for your org: External Client App authorization.

The RSA key itself has no expiry, but its X.509 certificate does. Same-key certificate renewal extends certificate validity; it is not private-key rotation. Renew before expiration, rotate compromised/aging keys separately, and retain independent recovery access. The toolkit supplies Metadata API primitives, not a renewal scheduler or secret store. Some OAuth settings are not exposed through metadata, so preserving returned XML does not guarantee that updating it preserves every Salesforce security policy.

After changing a certificate, verify with a new client and no cached token so success establishes a fresh JWT login. Use a separate connection name if the old client is still open; do not mutate a live client’s credentials.

Local cryptographic tests verify key loading and assertion construction, not Salesforce’s acceptance of a JWT audience for every login/My Domain/sandbox configuration. Validate audience behavior against the intended provider endpoint in a sandbox; no audience policy change is inferred from local tests alone.

Client Credentials Flow

For service-to-service integration as a designated Salesforce Run As user:

from sf_toolkit import SalesforceClient
from sf_toolkit.auth import client_credentials_flow_login
client = SalesforceClient(
    login=client_credentials_flow_login(
        consumer_key="your_consumer_key",
        consumer_secret="your_consumer_secret",
         domain="company.my.salesforce.com"
    )
)

This method:

  • Salesforce selects the user through the app’s Run As policy, not a username parameter

  • Requires an External Client App (or existing Connected App) configured for client credentials

  • Is useful for background service integrations

Use the org-specific My Domain hostname, not login.salesforce.com or test.salesforce.com. For a sandbox this commonly resembles company--uat.sandbox.my.salesforce.com. Pass only the hostname, without https:// or a path. JWT/password flows also accept login/test shorthand where permitted by the org. Allow configuration changes to propagate before testing.

For an External Client App, enable Client Credentials Flow in both OAuth Settings and Policies, configure the dedicated Run As integration user, and copy the Consumer Key/Secret into protected configuration. When using lazy_login, omit username, password, and private_key for this flow. Scopes and the Run As user’s permissions must both permit the operation.

SOAP Authentication

Salesforce Toolkit supports various SOAP-based authentication methods for compatibility with different security configurations:

Security Token Authentication

For orgs that require a security token with the password:

from sf_toolkit import SalesforceClient
from sf_toolkit.auth import security_token_login

client = SalesforceClient(
    login=security_token_login(
        username="user@example.com",
        password="password",
        security_token="your_security_token",
        client_id="YourAppName",  # Optional identifier for your app
        domain="login",  # Or your custom domain
        api_version=63.0  # Salesforce API version
    )
)

IP Filtering Authentication

For orgs with IP filtering enabled that allow specific IPs to skip the security token:

from sf_toolkit import SalesforceClient
from sf_toolkit.auth import ip_filtering_non_service_login

client = SalesforceClient(
    login=ip_filtering_non_service_login(
        username="user@example.com",
        password="password",
        client_id="YourAppName",  # Optional
        domain="login",  # Or your custom domain
        api_version=63.0  # Salesforce API version
    )
)

Organization-Scoped Login

For logging in to a specific organization within a multi-org setup:

from sf_toolkit import SalesforceClient
from sf_toolkit.auth import ip_filtering_org_login

client = SalesforceClient(
    login=ip_filtering_org_login(
        username="user@example.com",
        password="password",
        organizationId="00Dxxxxxxxxxx",  # Your org ID
        client_id="YourAppName",  # Optional
        domain="login",  # Or your custom domain
        api_version=63.0  # Salesforce API version
    )
)

Using Tokens Directly

If you already have a Salesforce access token and instance URL:

from sf_toolkit import SalesforceClient
from sf_toolkit.auth import SalesforceToken
from httpx import URL

# Create a token directly
token = SalesforceToken(
    instance=URL("https://myinstance.my.salesforce.com"),
    token="00D..."  # Your access token
)

# Use the token
client = SalesforceClient(token=token)

Token Refresh and Callbacks

You can register a callback function to be executed when a token is refreshed:

def token_updated(token):
    # Save token to database or file
    print(f"Token updated for {token.instance}")
    with open("token.txt", "w") as f:
        f.write(f"{token.instance}|{token.token}")

client = SalesforceClient(
    login=cli_login(),
    token_refresh_callback=token_updated
)

Best Practices

  1. Don’t hardcode credentials: Store secrets in environment variables or a secure credential store.

    import os
    
    client = SalesforceClient(
        login=password_login(
            username=os.environ["SF_USERNAME"],
            password=os.environ["SF_PASSWORD"],
            consumer_key=os.environ["SF_CONSUMER_KEY"],
            consumer_secret=os.environ["SF_CONSUMER_SECRET"]
        )
    )
    
  2. Use the strongest authentication method available: - JWT Bearer for server applications - CLI login for development - Avoid storing passwords in code

  3. Implement token persistence to avoid unnecessary authentications:

    import os
    import json
    from httpx import URL
    from sf_toolkit import SalesforceClient
    from sf_toolkit.auth import SalesforceToken, cli_login
    
    # Try to load saved token
    token = None
    token_file = "saved_token.json"
    
    if os.path.exists(token_file):
        try:
            with open(token_file, "r") as f:
                data = json.load(f)
                token = SalesforceToken(
                    instance=URL(data["instance"]),
                    token=data["token"]
                )
        except Exception as e:
            print(f"Error loading token: {e}")
    
    # Save token on refresh
    def save_token(token):
        with open(token_file, "w") as f:
            json.dump({
                "instance": str(token.instance),
                "token": token.token
            }, f)
    
    # Create client with token or login method
    client = SalesforceClient(
        login=None if token else cli_login(),
        token=token,
        token_refresh_callback=save_token
    )
    
  4. Handle token expiration gracefully: Salesforce Toolkit automatically attempts to refresh tokens when they expire during a request.

Authentication Classes

Under the hood, these authentication methods use these core classes:

  • SalesforceAuth - HTTPX authentication class that handles token management and refresh

  • SalesforceToken - Named tuple that represents a Salesforce access token with instance URL

  • SalesforceLogin - A callable that performs the authentication flow and returns a token

  • TokenRefreshCallback - A callable type for token refresh callbacks