Describe the bug?
When using private-key (PrivateKeyAuth / JWKAuth) or JWTAuth client-credentials auth against an Okta org with Require DPoP enabled, the SDK acquires tokens reactively: it sends the first POST /oauth2/v1/token without a DPoP proof, lets Okta reject it with invalid_dpop_proof, then retries with a proof.
Per RFC 9449 a DPoP-capable client should attach the proof proactively. Because of the reactive approach, every token acquisition on this path:
- makes an extra round trip (3 requests to
/oauth2/v1/token instead of 2), and
- records a failed token grant in the org System Log (the rejected proofless attempt) on every acquisition — recurring noise/false alarms for admins monitoring auth failures.
What is expected to happen?
The SDK attaches a DPoP proof to the first token request (DPoP-first). No proofless request is sent, no failed grant is logged, and a DPoP-required app completes in 2 requests (use_dpop_nonce challenge + token). Non-DPoP apps are unaffected.
What is the actual behavior?
The first token request carries no DPoP proof and is rejected with invalid_dpop_proof; the SDK then retries with a proof. The proofless rejection is logged as a failed token grant in the org System Log before each successful DPoP-bound grant, and adds an extra round trip.
Reproduction Steps?
- Create an Okta OAuth service app with a private key (JWK), scoped for client-credentials, and enable Require Demonstrating Proof of Possession (DPoP) on it.
- Configure the Go SDK with
AuthorizationMode: "PrivateKey" (or JWK) using that key.
- Make any API call so the SDK fetches a token.
- In the org System Log, observe a failed
invalid_dpop_proof token grant immediately before each successful DPoP-bound grant; a network capture shows 3 requests to /oauth2/v1/token instead of 2.
Additional Information?
Proposed fix: #597 (DPoP-first — pre-generate one key, attach a proof to the first token request, reuse it across the use_dpop_nonce retry, and adapt to Bearer vs DPoP from the response). Affects all v6 releases (the reactive getAccessTokenForDpopPrivateKey flow). No public API change; non-DPoP apps unaffected.
Golang Version
go version go1.26.4 darwin/arm64 (behavior is version-independent)
SDK Version
v6.1.x (present throughout v6)
OS version
macOS (Darwin, arm64)
Describe the bug?
When using private-key (
PrivateKeyAuth/JWKAuth) orJWTAuthclient-credentials auth against an Okta org with Require DPoP enabled, the SDK acquires tokens reactively: it sends the firstPOST /oauth2/v1/tokenwithout a DPoP proof, lets Okta reject it withinvalid_dpop_proof, then retries with a proof.Per RFC 9449 a DPoP-capable client should attach the proof proactively. Because of the reactive approach, every token acquisition on this path:
/oauth2/v1/tokeninstead of 2), andWhat is expected to happen?
The SDK attaches a DPoP proof to the first token request (DPoP-first). No proofless request is sent, no failed grant is logged, and a DPoP-required app completes in 2 requests (
use_dpop_noncechallenge + token). Non-DPoP apps are unaffected.What is the actual behavior?
The first token request carries no DPoP proof and is rejected with
invalid_dpop_proof; the SDK then retries with a proof. The proofless rejection is logged as a failed token grant in the org System Log before each successful DPoP-bound grant, and adds an extra round trip.Reproduction Steps?
AuthorizationMode: "PrivateKey"(or JWK) using that key.invalid_dpop_prooftoken grant immediately before each successful DPoP-bound grant; a network capture shows 3 requests to/oauth2/v1/tokeninstead of 2.Additional Information?
Proposed fix: #597 (DPoP-first — pre-generate one key, attach a proof to the first token request, reuse it across the
use_dpop_nonceretry, and adapt to Bearer vs DPoP from the response). Affects all v6 releases (the reactivegetAccessTokenForDpopPrivateKeyflow). No public API change; non-DPoP apps unaffected.Golang Version
go version go1.26.4 darwin/arm64(behavior is version-independent)SDK Version
v6.1.x (present throughout v6)
OS version
macOS (Darwin, arm64)