Guides / n8n × Salesforce / Authentication

Salesforce "missing code_challenge parameter": when PKCE is required

Fix Salesforce missing code_challenge errors by implementing the PKCE authorization-code flow correctly.

Advertisement
Illustrated troubleshooting diagram for Salesforce "missing code_challenge parameter": when PKCE is required.
Short answer: Generate a random code verifier, calculate its SHA-256 S256 code challenge, and include both challenge and method in the authorization URL. Save the verifier in a server-side session tied to the user’s state value. When Salesforce redirects back with an authorization code, send the original verifier to the token endpoint. Do not generate a new verifier during the callback.

PKCE in two steps

PKCE binds the authorization code to the client that began the flow. Step one sends the challenge; step two proves possession of the verifier:

Authorization request:

Token request:

Use the correct Salesforce host for your environment and follow the app’s secret policy. The exact parameters must match the official OAuth flow documentation.

POST https://login.salesforce.com/services/oauth2/token
grant_type=authorization_code
code=AUTHORIZATION_CODE
client_id=CLIENT_ID
redirect_uri=REDIRECT_URI
code_verifier=ORIGINAL_VERIFIER

Why adding only the verifier fails

Salesforce cannot validate a verifier if no challenge was attached to the authorization request. The authorization server needs the first-half commitment before it issues the code. Adding code_verifier only at the token endpoint produces a different error or leaves the original missing-challenge problem unchanged.

The challenge must be derived from the verifier using the method configured in the request. S256 is the normal choice. Do not hash the verifier twice, use standard base64 with unsafe characters, or accidentally URL-encode the already encoded value twice.

Advertisement

Keep the verifier in the right session

Store the verifier server-side with the OAuth state and a short expiration. The callback should look up state, confirm the user session, retrieve the verifier, and then exchange the code. Never put the verifier in a public URL or expose it to unrelated browser scripts.

Example session record:

Delete the verifier after a successful or definitively failed exchange. This prevents accidental reuse and reduces sensitive session data.

{
  "state": "random-state",
  "codeVerifier": "server-side-only",
  "createdAt": "2026-09-12T18:00:00Z",
  "redirectUri": "https://app.example.com/oauth/callback"
}

Check the Salesforce app policy

The error can be caused by the client configuration rather than the code. Inspect the External Client App or Connected App OAuth policy and confirm whether “Require Proof Key for Code Exchange (PKCE) extension for Supported Authorization Flows” is enabled. If enabled, the client must implement PKCE. If the app is an older connected app and its creation or policy options differ from current guidance, check Salesforce’s current setup documentation before changing production security settings.

Also verify permitted users, scopes, callback URL, and whether a client secret is required for the web-server flow. PKCE does not replace every other authentication parameter.

Common implementation mistakes

The redirect URI must match the registered URI exactly, including trailing slash, path, and scheme. The client ID must identify the same app in both steps. The code can be used only once and may expire quickly. A callback handled by a different server instance may not find the session unless the session store is shared.

Check URL encoding. Use a standards-compliant URL builder rather than concatenating values containing plus signs, slashes, or equals signs. Log parameter names and lengths, not secret values.

Test cases

Test a fresh authorization with PKCE, a callback with a missing state, a changed redirect URI, a verifier from a different session, a reused code, and an expired session. Test production and sandbox separately. Confirm that a failed exchange does not leave a live authorization code or verifier in logs.

Use a browser network trace only in a controlled environment and redact the authorization code immediately. The authorization URL may contain client ID and redirect URI, but it should not contain the verifier.

Migration from a non-PKCE client

Add a PKCE utility with unit tests first. Add state and verifier storage. Add the challenge to authorization URLs. Add the verifier to token exchange. Test one org. Then enable or enforce the policy for the intended client after the implementation is proven.

Do not silently support two incompatible flows by guessing from the error. Make the app configuration explicit so an administrator can see whether PKCE is required.

The trap: generating challenge and verifier in different code paths without persisting the pairing. They can both look valid and still fail because Salesforce expects the original verifier.

Verify the cryptography with a unit test

The same verifier must produce the same challenge every time. Test that the verifier contains only allowed characters, that the challenge is base64url without unsafe padding, and that a known verifier produces the expected S256 digest. Then test that a different verifier is rejected by your client before it reaches Salesforce.

Keep the crypto helper independent from routing and Salesforce HTTP calls. This makes the security-sensitive code easier to review and prevents a framework upgrade from changing encoding behavior unnoticed.

Diagnose a distributed callback

If authorization begins on one application instance and returns to another, an in-memory session can lose the verifier. Use a shared encrypted session store or an encrypted, short-lived server-side transaction record keyed by state. Expire abandoned transactions and rate-limit callback attempts.

Test the callback with a deliberately expired transaction, a changed state value, and a verifier from another session. Each case should stop before token exchange and tell the user to restart. This prevents a confusing Salesforce error from masking a session-management defect in the application.

Also test concurrent authorizations in two browser tabs. Each tab needs a separate state and verifier pairing. A single session variable that is overwritten by the second tab can make the first tab fail even though the cryptographic helper is correct.

When upgrading an OAuth library, compare the generated authorization URL and token form body with a known-good fixture. Libraries sometimes change padding, encoding, or parameter omission between major versions.

Keep a small security review note with the library version, PKCE method, session storage choice, and callback expiration. This gives future maintainers a concrete baseline when Salesforce changes an app policy or an OAuth dependency is upgraded.

That baseline should be checked in every environment before release.

Keep the public client ID separate from the verifier and client secret. The ID can appear in an authorization URL; the verifier and secret belong in protected server-side transaction storage. This distinction is useful during a security review because it shows which values are identifiers and which values could be used to complete or replay an authorization attempt.

Verify the exact encoded values

Use a known verifier fixture and assert that the SHA-256 digest is base64url encoded without padding before it is placed in the authorization URL. At callback, retrieve the original verifier by state and compare the redirect URI with the value used in step one. This catches double encoding and session overwrite defects that can look like a Salesforce policy failure.

Where these facts come from

Advertisement
Advertisement