<iframe src="https://www.googletagmanager.com/ns.html?id=GTM-M74D8PB" height="0" width="0" style="display:none;visibility:hidden">
Loading
Skip to NavigationSkip to Main Content
0D54z0000AE79DVCQZOkta Classic EngineAuthenticationAnswered2024-08-29T00:26:48.000Z2024-08-27T07:22:11.000Z2024-08-29T00:26:48.000Z
Client Credentials OAuth for Okta with DPoP enabled

Followed steps in the docs but it's a mix of https://developer.okta.com/docs/guides/implement-oauth-for-okta-serviceapp/main/ and 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 https://8gwifi.org/jwkconvertfunctions.jsp)
  • Create and sign the client_credentials JWT using jwt.io

Payload:

{

"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:

{

"typ": "dpop+jwt",

"alg": "RS256",

"jwk": {

"kty": "RSA",

"e": "AQAB",

"use": "sig",

"kid": "<private key kid>",

"alg": "RS256",

"n": "<private key n>"

}

}

Payload:

{

  "htm": "POST",

  "htu": "https://dev-<account#>.okta.com/oauth2/v1/token",

 "iat": <epoch now>

}

curl --location 'https://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

{

"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

{

  "htm": "POST",

  "htu": "https://dev-<account#>.okta.com/oauth2/v1/token",

 "iat": <epoch now>,

"nonce": "<response header dpop-nonce from HTTP 400>",

"jti": "<any random character>"

}

{

"token_type": "DPoP",

"expires_in": 3600,

"access_token": "<access_token with DPoP>",

"scope": "okta.users.read"

}

curl --location 'https://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?


This question is closed.
Loading
Client Credentials OAuth for Okta with DPoP enabled