Blog · July 5, 2026

Private key JWT and DPoP vs. the client secret: how your Okta API integrations should really authenticate

In 2026, the frictionless way to ship an integration to your identity provider still hands every customer a shared secret. For an internal app that is a small worry. For an external SaaS that reads into your Okta org, it is the wrong default — and the stronger options already exist.

Three ways an integration proves who it is

When a service application asks Okta for an access token, it authenticates in one of a few ways. A client secret is a shared symmetric string: the same value lives in the customer's Okta org and in the vendor's systems, and anyone holding it can request tokens. Private key JWT (private_key_jwt) is asymmetric: the vendor holds a private key and registers only the matchingpublic key with Okta, so nothing secret ever leaves the vendor.DPoP — Demonstrating Proof-of-Possession, RFC 9449 — goes one step further and binds each token to a key the client holds, so a token that is stolen off the wire is useless to whoever steals it.

Why a shared secret is the weak link for external SaaS

A client secret is bearer-grade access. It is a single symmetric value that sits in two places at once, and if it ever leaks — a log line, a misconfigured store, a compromised laptop — it is full API access to the customer's org until someone notices and rotates it. For an integration that reaches into many customers' identity providers, that is the highest-value credential you can hold and the easiest one to lose. The whole point of connecting to an identity system is that it is the front door; the credential to it should not be a password sitting in two databases.

What private key JWT changes

With private_key_jwt, there is no shared secret to leak, because the secret never leaves the vendor. Okta only ever sees a public key. This is not an exotic option — it is what Okta requires for its own custom service apps. Okta's guide for service-app OAuth states plainly that private key JWT is "the only supported method for OAuth service apps that want to get access tokens with Okta scopes." The secure mechanism is already in the platform, and Okta already treats it as mandatory for the sensitive path.

What DPoP adds on top

Private key JWT protects the credential. DPoP protects the token. Per Okta's own documentation, DPoP "helps prevent unauthorized parties from using leaked or stolen access tokens" by sender-constraining both access and refresh tokens so they cannot be replayed at a different endpoint. A token bound to a key you hold is worthless to an attacker who captures it. For anything reaching into an identity provider, that is exactly the property you want.

This is the industry consensus, not one vendor's opinion

The current IETF Best Current Practice for OAuth 2.0 security — RFC 9700, published January 2025 — states that it is"RECOMMENDED to use asymmetric cryptography for client authentication, such as… 'Private Key JWT'" and that servers "SHOULD use mechanisms for sender-constraining access tokens, such as mutual TLS… or… DPoP… to prevent misuse of stolen and leaked access tokens." The reasoning is exactly the one above: with asymmetric client authentication,"authorization servers do not need to store sensitive symmetric keys." And per the DPoP spec, RFC 9449, if the private key is non-extractable, DPoP "renders exfiltrated tokens alone unusable." This is not a niche preference. It is where the standards have landed.

Okta already supports all of this — everywhere except the easy path

None of this is a feature request for something Okta lacks. Custom service appsrequire private key JWT and can be set to require DPoP. Okta even uses registered public keys for OIDC token encryption, where you can "save keys to Okta or use a URL to fetch keys dynamically" — the exact JWKS-URL mechanism a secure integration wants. The building blocks are all present. The gap is that the frictionless distribution path — the one customers actually use to install an integration — still defaults to a shared client secret, and does not yet let a vendor choose the stronger options. The secure choice exists; it just is not offered where most integrations get installed.

The "easy" path still needs a Super Admin — it just hides what you approve

There is a second thing the frictionless path obscures: privilege. Installing an integration from a catalog feels lighter than a guided setup, but on access it is not. Granting an app the Okta API scopes it needs is a Super Administrator action either way; Okta restricts scope grants to super admins (see Implement OAuth for Okta with a service app). The difference is visibility. A guided setup shows you exactly which read scopes you are granting; a catalog "install and authorize" flow bundles that same super-admin grant into a single consent click, so it feels lighter while showing you less of what you actually approved. And one bundled consent can just as easily include write ormanage scopes if the integration asks for them — which is easy to wave through in a single click. For something that reads your identity system, you should see exactly what you are handing over and be able to confirm it is read-only. Read the scopes before you grant them.

Internal is one thing. Reaching into someone else's identity provider is another.

Context matters. For an app that lives entirely inside your own network, or an OIDC flow whose traffic never leaves your perimeter, a shared secret is a smaller risk. The bar should scale with blast radius. An external SaaS that authenticates into many separate customer orgs is the opposite end of that spectrum: one leaked symmetric secret is not a single-tenant problem, it is a credential that should never have been symmetric in the first place. Judge the credential by what it can reach.

AI agents make this urgent, not optional

The number of non-human identities — service accounts, automations, and now AI agents — holding real credentials is climbing fast, and every one of them authenticates to something. A credential that is easy to steal and still works after it is stolen is precisely the wrong thing to hand a growing fleet of automated actors. As more integrations run without a human in the loop, "the token cannot be replayed and there is no shared secret to leak" stops being a nice-to-have and becomes the baseline. Your service accounts deserve the same scrutiny as your users.

How Atomation connects

Atomation is a read-only Okta security and compliance engine, and our connection usesprivate_key_jwt with DPoP-bound tokens by design. There is no shared secret to copy, store, or leak, and no token to replay. On top of that, the engine auditsits own connection and flags anything beyond read — so the scanner proves its own promise. We hold this bar for ourselves because it is the bar we think every external integration into an identity provider should meet.

The pieces are already here. The easy path should use them. See the read-only assessment on your own org — the demo is open, no signup:demo.atomation.io.

Get started

A read-only Okta assessment that holds itself to the standard it recommends.

Request a scoped Okta assessment. We'll align the baseline around your org count, reporting needs, evidence requirements, and delivery model.