For the complete documentation index, see llms.txt. This page is also available as Markdown.

OAuth with an X.509 certificate

Authenticate to Okta using a Windows certificate, so the private key can be non-exportable or held in a TPM or HSM.

Background

Okta authenticates a service app by verifying a signed JWT against a public key it holds as a JWK. There are no certificates anywhere in that flow.

The management agent bridges the two. You give it a certificate thumbprint, and it finds the certificate in a Windows store, derives the public JWK from the certificate's public key, and signs each OAuth client assertion using the certificate's private key through the Windows cryptographic provider. The derived JWK is what you register in Okta.

The benefit of this approach is that Windows holds the private key, so it can be marked as non-exportable, or held in a TPM or HSM, and never has to exist as a file anywhere. Nothing else changes: to Okta, this is an ordinary private_key_jwt service app.

This design has two consequences that are worth understanding before you start:

  • Okta never sees the certificate. It receives one JWK containing a modulus and exponent, or a curve and coordinates. There is no chain, no CA, and no trust decision for Okta to make. A self-signed certificate is entirely normal here.

  • The JWK kid is the certificate thumbprint. This is what ties the key registered in Okta to the certificate on the MIM server, and it's why replacing or renewing the certificate always means registering a new key in Okta.

Certificate requirements

The management agent checks all of this when it connects, so a mistake here surfaces the first time you retrieve the schema. The certificate must be:

  • Within its validity period

  • Backed by a private key the MIM Synchronization Service account can use

  • RSA of at least 2048 bits, or EC on P-256, P-384, or P-521

  • Permitted to sign, if it carries a Key Usage extension

Issuer, subject, SANs, and extended key usage are not checked. Both self-signed and CA-issued certificates work.

RSA keys sign with RS256. EC keys sign with ES256, ES384, or ES512, matching the curve.

Step 1: Choose the certificate store

This is the step that most often goes wrong, so it's worth taking the time to get it right.

The management agent looks for the thumbprint in two places, in this order:

  1. CurrentUser\My of the account running the MIM Synchronization Service

  2. LocalMachine\My

Find out which account runs the service:

Then pick a store:

Situation
Store
Extra work

You can start PowerShell as the service account

CurrentUser\My

None. A key created by that account is already usable by it.

Group managed service account, LocalSystem, or you do not have the password

LocalMachine\My

Grant the service account read access to the private key.

The cryptographic provider requires the machine store, or the key is shared

LocalMachine\My

Grant the service account read access to the private key.

Either way, the certificate needs to be installed on the MIM server that runs the management agent.

Step 2: Create the certificate

Skip to Step 3 if you already have a certificate that meets the requirements above.

Download OktaManagementAgentKeys.ps1 to the MIM server, review it, and load it:

New-OktaManagementAgentCertificate creates a non-exportable signing certificate and writes its public JWK. The output directory must already exist, and you'll need to add -Force to overwrite an existing output file.

Run whichever of the following applies, as the account whose store you chose in Step 1.

RSA

EC

P-384 and P-521 are also accepted.

TPM-backed

Windows exposes the TPM through the Microsoft Platform Crypto Provider. Name it with -Provider:

Use an EC key in a TPM. TPM 2.0 caps RSA at 2048 bits, so a 3072-bit or 4096-bit RSA key can't be created, and P-256 is the only curve that every TPM 2.0 device supports. Support for anything beyond P-256 depends on the particular TPM.

RSA still works if you need it; use -RsaKeyLength 2048.

HSM

Create or enroll the certificate with the HSM vendor's own tooling, then treat it as an existing certificate and continue at Step 3.

The key must be usable by the MIM Synchronization Service account without any interactive steps, as there is nobody at the console during a scheduled run to authorize the use of the key.

Subject and expiry

The certificate is created with the subject CN=Lithnet Okta Management Agent and a validity of two years. Add -Subject and -NotAfter to any of the commands above to change either:

Whatever expiry you choose, record the date somewhere you'll see it before it arrives. Renewing the certificate involves work in both Okta and MIM.

If you used the LocalMachine store

Change -StoreLocation to LocalMachine in any of the commands above, and run PowerShell as an administrator. Then grant the service account access to the key:

  1. Open certlm.msc.

  2. Find the certificate under Personal > Certificates.

  3. Right-click it, then All Tasks > Manage Private Keys.

  4. Add the MIM Synchronization Service account with Read permission.

The certificate and its public JWK are ready. Go to Step 4.

Step 3: Export the public JWK

For a certificate you already have, load the tooling and convert it by thumbprint:

The thumbprint form searches CurrentUser\My then LocalMachine\My, the same order the management agent uses. If you run PowerShell as the service account, it will resolve to exactly the same certificate the connector will find.

If you are running as a different account, name the store instead so there is no ambiguity:

Only the public key is written. The private key stays in the certificate store or the hardware provider.

The result looks like this. It contains only public key material, so it's safe to email, paste into a ticket, or hand to your Okta administrator:

If you need a JWKS document instead, for a JWKS endpoint or the Okta management API, ConvertTo-OktaPublicJwks takes the same parameters and wraps the key in a keys array. Don't use this format when pasting the key into the Admin Console.

Step 4: Register the public key in Okta

Work through Creating the OAuth service app, pasting the contents of okta-ma-public.jwk.json at the public key step. Record the client ID.

Come back here once the app has its public key, scopes, and admin role.

Step 5: Configure MIM

On the management agent Connectivity page:

  1. Set Authentication method to OAuth 2.0 (X.509 certificate).

  2. Enter the app's client ID in OAuth client ID.

  3. Enter the certificate thumbprint in Certificate thumbprint. Spaces are stripped, so pasting it out of the certificate dialog is fine.

  4. Enter your Okta org URL in Tenant URL, for example https://example.okta.com. Don't use the -admin hostname.

  5. Set the log file path and log level.

  6. Save the page.

Connectivity settings for X.509 certificate authentication.

The Connectivity page shows the fields for all three authentication methods at once. With this method selected, only OAuth client ID, Certificate thumbprint, and Tenant URL are used. Leave API key and Private JWK file path empty.

Step 6: Retrieve the schema

Retrieve the management agent schema. This is the first point at which everything is exercised together: the certificate lookup, the private key, the OAuth token request, and the granted scopes. The object types and attribute directions MIM shows should match the scopes on the service app.

If it fails, see X.509 certificate troubleshooting.

Then continue with Creating the management agent.

Renewal and replacement

A renewed certificate normally has a new key pair, which means a new thumbprint, and therefore a new kid. You'll need to register a new public key in Okta and update the thumbprint in MIM. Key and certificate rotation shows you how to do this without an outage.

Last updated