# Client Credentials OAuth for Okta with DPoP enabled

**URL:** <https://devforum.okta.com/t/client-credentials-oauth-for-okta-with-dpop-enabled/30239>\
**Category:** OAuth/OIDC\
**Created:** [August 27, 2024, 7:31am UTC](https://devforum.okta.com/t/client-credentials-oauth-for-okta-with-dpop-enabled/30239 "2024-08-27T07:31:25Z")\
**Posts on this page:** 1\
**Showing post:** 1

<div class="post-metadata">

**Author:** ![markfigr](https://avatars.discourse-cdn.com/v4/letter/m/e9a140/32.png) [@markfigr](https://devforum.okta.com/u/markfigr)\
**Post date:** [August 27, 2024, 7:31am UTC](https://devforum.okta.com/t/client-credentials-oauth-for-okta-with-dpop-enabled/30239/1 "2024-08-27T07:31:25Z")

</div>

Followed steps in the docs but it’s a mix of [Implement OAuth for Okta with a service app | Okta Developer](https://developer.okta.com/docs/guides/implement-oauth-for-okta-serviceapp/main/) and [Configure OAuth 2.0 Demonstrating Proof-of-Possession | Okta Developer](https://developer.okta.com/docs/guides/dpop/nonoktaresourceserver/main/). I get the access\_token but calling Okta API /api/v1/users returns HTTP 400.

- Create App Integration \> select API Services

- Edit Client Credentials \> select Public key / Private key \> Add key \> copy private JWK key \> Save

- In General Settings by default Require Demonstrating Proof of Possession(DPoP) header in token requests is True

- Okta API Scopes Tab \> Grant okta.users.read

- Admin Roles Tab \> Assign Read-only Administrator \> Save changes

- Convert private JWK key to public PEM and private PEM (I use 8gwifi .org/jwkconvertfunctions.jsp)

- Create and sign the client\_credentials JWT using jwt .io

Payload:

```auto
{
"aud": "https://dev-<account#> .okta .com/oauth2/v1/token",
"iss": "<app_client_id>",
"sub": "<app_client_id>",
"exp": <epoch in future>
}

```

- Create and sign the DPoP JWT using jwt .io

Header:

```auto
{
"typ": "dpop+jwt",
"alg": "RS256",
"jwk": {
"kty": "RSA",
"e": "AQAB",
"use": "sig",
"kid": "<private key kid>",
"alg": "RS256",
"n": "<private key n>"
}
}

```

Payload:

```auto

{
"htm": "POST",
"htu": "https://dev-<account#> .okta .com/oauth2/v1/token",
"iat": <epoch now>
}

```

- Call POST on dev-\<account#\>.okta.com/oauth2/v1/token

```auto
curl --location 'dev-<account#>.okta .com/oauth2/v1/token' \
--header 'DPoP: <DPoP JWT>' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'scope=okta.users.read' \
--data-urlencode 'client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' \
--data-urlencode 'client_assertion=<client_credentials JWT>'

```

- Receive HTTP 400 and use response header ‘dpop-nonce’ to create new DPoP JWT

```auto
{
"error": "use_dpop_nonce",
"error_description": "Authorization server requires nonce in DPoP proof."
}

```

- Create and sign the DPoP with nonce JWT using jwt .io by using the same header but adding nonce and jti in payload

```auto
{
"htm": "POST",
"htu": "dev-<account#>.okta .com/oauth2/v1/token",
"iat": <epoch now>,
"nonce": "<response header dpop-nonce from HTTP 400>",
"jti": "<any random character>"
}

```

- Call the same POST on dev-\<account#\>.okta .com/oauth2/v1/token but change DPoP header with the new DPoP with nonce JWT

Receive a HTTP 200

```auto
{
"token_type": "DPoP",
"expires_in": 3600,
"access_token": "<access_token with DPoP>",
"scope": "okta.users.read"
}

```

- Call GET on dev-\<account#\>.okta .com/oauth2/v1/users

```auto

curl --location 'dev-<account#>.okta .com/api/v1/users' \
--header 'DPoP: <DPoP JWT>' \
--header 'Authorization: DPoP <access_token with DPoP>'

```

- HTTP 400 Bad Request with a blank body

How do I fix this and which step is it failing?

---

_[View the full topic](https://devforum.okta.com/t/client-credentials-oauth-for-okta-with-dpop-enabled/30239)._
