Okta Certified Developer study materials
Okta Certified Developer study resources

Okta Certified Developer common mistakes

Okta Certified Developer ยท Understand the traps and how to avoid them.

Mistake 1

Calling the management API with a bare `Authorization: Bearer <API token>` header but hitting the org URL's `/oauth2/v1/...` endpoints, or the reverse: sending an OIDC access token to `/api/v1/users` and getting a 401.

Okta has two distinct API surfaces with two distinct credential types. The management API (/api/v1) accepts SSWS API tokens (or OAuth 2.0 service-app tokens with the right scopes), while the OIDC/OAuth2 endpoints (/oauth2/v1/*) accept access tokens issued to clients. Candidates learn 'use a bearer token' generically and mix the two, so the token is valid but for the wrong audience.

What to do instead

Map the endpoint to its credential before writing code: /api/v1 with SSWS or an OAuth service-app token carrying okta.users.manage etc.; /oauth2/v1/userinfo and friends with a user's access token. When debugging a 401, decode the token's iss, aud, and cid claims and confirm the audience matches the resource server you are calling.

Mistake 2

Hard-coding pagination assumptions: fetching `/api/v1/users` once and treating the returned array as complete, or building 'next page' links by string-concatenating an offset instead of following the `Link` header.

The management API returns a default page size (often 200) and communicates the next page only via an RFC 5988 Link header with rel="next". Candidates test with a small dev org where everything fits on one page, so the bug never surfaces until production or a large tenant.

What to do instead

Loop while a Link header with rel="next" exists, and re-request that exact URL rather than reconstructing it. Use the official SDK's auto-paging iterator (e.g., listUsers().stream() in the Java SDK or the next() pattern in the Node SDK) so cursor semantics are handled for you.

Mistake 3

Treating a 429 as a hard failure or retrying immediately in a tight loop, causing rate-limit escalation and eventual lockout of the integration.

Okta enforces per-org and per-endpoint rate limits and returns 429 with X-Rate-Limit-Reset (epoch seconds) and X-Rate-Limit-Limit/Remaining headers. Candidates either ignore the headers or assume exponential backoff is enough without honoring the reset window.

What to do instead

On 429, read X-Rate-Limit-Reset, sleep until that timestamp (plus jitter), then retry with a bounded attempt count. Also reduce call volume up front: batch with the /api/v1/users/{id}/lifecycle/... endpoints, use bulk operations where offered, and cache stable data instead of polling.

Mistake 4

Implementing Authorization Code flow without PKCE in a public client (SPA or mobile), or putting the client secret in browser code to make it 'confidential'.

Older tutorials show the implicit flow or a secret-in-JS pattern; candidates port those to modern apps without realizing SPAs and native apps are public clients that cannot keep secrets. Okta's current guidance requires PKCE for these client types, and misconfigured clients may be rejected or silently insecure.

What to do instead

Use Authorization Code with PKCE (code_challenge/code_challenge_method=S256) for SPAs and native apps, register the app as a public client, and validate state and nonce. Keep client secrets server-side only, in a Web application (confidential) client type.

Mistake 5

Validating an ID token by decoding the JWT payload and reading claims without verifying the signature, or verifying against the wrong issuer/audience.

Decoding is trivially easy (atob/base64) and 'works' in testing, so candidates skip signature verification. They also forget that the ID token's aud is the client ID, not the API audience, and that iss must exactly match the org's authorization server URL.

What to do instead

Verify the signature against the JWKS at /oauth2/v1/keys (or the custom AS /oauth2/{asId}/v1/keys), then check iss, aud (client ID), exp, iat, and nonce for the ID token. Use a maintained library (okta-jwt-verifier, okta-react, etc.) rather than hand-rolling verification.

Mistake 6

Confusing Okta's built-in Org Authorization Server with a Custom Authorization Server, then wondering why the access token has no custom scopes or why `/oauth2/default` returns 404.

The Org AS issues tokens for Okta APIs and supports only a limited scope model; custom scopes, custom claims, and access policies live on a Custom AS (commonly default). Candidates follow a guide written for one and run it against the other, so scopes are silently dropped or endpoints 404.

What to do instead

Decide up front: Okta APIs โ†’ Org AS; protecting your own API โ†’ Custom AS. Then use the matching base URL (https://{org}/oauth2/default/v1/...) consistently for authorize, token, and JWKS calls, and define scopes and claims on that Custom AS.

Mistake 7

Configuring an OIDC app's redirect URI as a wildcard or with a trailing slash mismatch, then debugging the resulting `redirect_uri` error by changing unrelated settings.

Okta requires an exact match on redirect URIs (scheme, host, port, path), and wildcards are not allowed for most flows. Candidates copy a URI from a tutorial, change the local port, and get The redirect_uri must be an absolute URI or a mismatch error that looks like an auth failure.

What to do instead

Register every exact redirect URI the app uses (including each localhost port) and keep them in sync with the app config. Read the error/error_description query parameters on the redirect to identify the failing parameter before touching other settings.

Mistake 8

Assuming SAML and OIDC attribute mapping is automatic, so users arrive at the app with no `email`, `firstName`, or group claims and the app rejects the login.

Okta sends only what the app's profile/attribute statements define. Candidates set up the app connection but skip the attribute statements (SAML) or the claims/groups claim (OIDC), so the assertion or token is valid but missing fields the app requires. Group-based authorization fails the same way when the groups claim is not requested.

What to do instead

In the app's Sign On settings, define explicit SAML attribute statements or OIDC claim mappings (including a groups claim with the right filter and groups scope). Test with the Okta SAML/OIDC debugger or a token preview before handing off to the app team.

Mistake 9

Deactivating or deleting a user instead of suspending, or calling the wrong lifecycle endpoint (e.g., `/lifecycle/activate` on an already-active user) and treating the 403 as an auth problem.

Okta lifecycle transitions are state-machine constrained: activating an ACTIVE user, suspending a DEPROVISIONED user, or deleting a user with active app assignments returns 403 with a state-related error. Candidates learn one endpoint and reuse it for every state, then misdiagnose the error as a permissions issue.

What to do instead

Read the user's current status first, then choose the legal transition (activate, deactivate, suspend, unsuspend, reactivate, expirePassword, resetPassword, unlock). For offboarding, deactivate (reversible) rather than delete; delete only when policy requires it and after clearing assignments.

Mistake 10

Creating users with `/api/v1/users?activate=false` and then expecting them to be able to log in, or importing users without setting a password/recovery question and assuming they can authenticate.

A user created with activate=false is in STAGED status and cannot authenticate; even ACTIVE users need a credential or a recovery flow. Candidates test the create call in isolation, see a 200, and assume the account is usable, then hit 'invalid credentials' or 'user not assigned' at login.

What to do instead

Decide the onboarding path explicitly: create with activate=true plus a credentials.password or recovery_question, or create STAGED and send an activation email via /lifecycle/activate?sendEmail=true. Verify the resulting status is ACTIVE and that the user is assigned to the target app before testing login.