title: OAuth2 (Okta) token generation fails with 401 unauthorized response - client_credentials grant type
body: <p>I ran into a problem where my AJAX request fails with error code 401 - Unauthorized, while trying to get an OAuth2 (Okta) Token.</p>
  <p>The preview tab shows an error as follows:</p>
  <pre><code>Browser requests to the token endpoint must use Proof Key for Code Exchange
  </code></pre>
  <p>Does this mean I can't use the client_credentials grant type for client side requests?</p>
  <p>Here is my AJAX request:</p>
  <pre class="lang-js prettyprint-override"><code>$.ajax({
      url: dataParsed.TokenServiceEndpoint,
      type: &quot;POST&quot;,
      contentType: &quot;application/x-www-form-urlencoded&quot;,
      datatype: &quot;application/json&quot;,
      headers: {
          &quot;Authorization&quot;: &quot;Basic &quot; + btoa(dataParsed.TokenServiceUser + &quot;:&quot; + dataParsed.TokenServicePassword)
      },
      data: {
          &quot;grant_type&quot;: &quot;client_credentials&quot;
      }
  }
  </code></pre>
  <p>A similar request works using postman, but I am not sure what the difference is between the two, or how to make it work through ajax.</p>
  <p>Here is the request exported from Postman:</p>
  <pre><code>Content-Type: application/x-www-form-urlencoded
  Authorization: Basic *************
  User-Agent: PostmanRuntime/7.29.0
  Accept: */*
  Postman-Token: fd2c4617-a4bb-4d28-88bd-1aa84c2a7404
  Host: *****
  Accept-Encoding: gzip, deflate, br
  Connection: keep-alive
  Content-Length: 29
  Cookie: JSESSIONID=3B62F82EE85BC8574756101635CC3B14
   
  grant_type=client_credentials
   
  HTTP/1.1 200 OK
  Date: Fri, 18 Mar 2022 14:41:42 GMT
  Server: nginx
  Content-Type: application/json
  x-okta-request-id: YjSaJqln-TB3pOn9kgwmsQAABSw
  x-xss-protection: 0
  p3p: CP=&quot;HONK&quot;
  x-rate-limit-limit: 20000
  x-rate-limit-remaining: 19971
  x-rate-limit-reset: 1647614537
  cache-control: no-cache, no-store
  pragma: no-cache
  expires: 0
  expect-ct: report-uri=&quot;*****&quot;, max-age=0
  x-content-type-options: nosniff
  Strict-Transport-Security: max-age=315360000; includeSubDomains
  X-Robots-Tag: noindex,nofollow
  set-cookie: sid=&quot;&quot;; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/
  set-cookie: autolaunch_triggered=&quot;&quot;; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/
  set-cookie: JSESSIONID=AA2D48FFC46A8AC0E1D139D038CE98AB; Path=/; Secure; HttpOnly
  Keep-Alive: timeout=5, max=100
  Connection: Keep-Alive
  Transfer-Encoding: chunked
  </code></pre>