PKCE code_verifier mismatch in Genesys Cloud SPA auth flow

Implementing Authorization Code flow with PKCE in Kotlin. Generating code_verifier via SecureRandom and SHA-256 for the GET /oauth/authorize call. The code_challenge matches the base64url encoding spec. But POST /oauth/token keeps returning invalid_grant with error_description: invalid code verifier.

val challenge = verifier.sha256().base64UrlEncode()

Checked the token endpoint payload, code_verifier string matches the original exactly. Am I missing a URL encoding step on the verifier before sending it to the token endpoint?