UniAuth.ID

Migrating from Okta

UniAuth is a standards-compliant OIDC provider. If your app uses Okta's discovery URL and any certified OIDC library, migration is mostly swapping the issuer. This page covers the edge cases.

Endpoint Mapping

OktaUniAuth
/.well-known/openid-configuration/.well-known/openid-configuration
/oauth2/default/.well-known/openid-configuration/.well-known/openid-configuration
/oauth2/v1/keys/.well-known/jwks.json
/oauth2/v1/authorize/api/oauth/authorize
/oauth2/v1/token/api/oauth/token
/oauth2/v1/userinfo/api/oauth/userinfo
/oauth2/v1/logout/api/oauth/end-session
/oauth2/v1/revoke/api/oauth/revoke
/oauth2/v1/introspect/api/oauth/introspect
/oauth2/v1/device/authorize/api/oauth/device
/oauth2/v1/clients/api/oauth/register

Authorization Servers: Okta has multiple (Org AS + Custom AS at/oauth2/{asId}). UniAuth has one, rooted at https://uniauth.id. Point your library at that issuer; discovery does the rest.

Claim Mapping

Okta claimUniAuth claimNotes
subsubOkta ties sub to user ID; UniAuth uses pairwise HMAC (different per app)
emailemailStandard
email_verifiedemail_verifiedStandard
namenameStandard
given_namegiven_nameStandard
family_namefamily_nameStandard
preferred_usernamepreferred_usernameStandard
localelocaleStandard
zoneinfozoneinfoStandard
groupsgroupsRequires 'groups' scope on both sides
cid / uid / scpOkta-specific; UniAuth uses standard aud + scope
idp / idp_typeOkta federation metadata; use groups claim instead
auth_timeauth_timeStandard
amramrBoth emit pwd, mfa, otp, hwk, face, fpt
acracrUniAuth: urn:uniauth:acr:pwd / :mfa / :passkey

Key Behavioral Differences

1. Pairwise subject identifiers

Okta's sub is the internal user ID, identical across apps. UniAuth computes a per-client pairwisesub so two apps see different values for the same user. If you correlate users across apps via sub, stop — use email or federated identity instead.

2. Access tokens are opaque on Okta Org AS

Okta's Org Authorization Server emits opaque access tokens that must be introspected. UniAuth always emits JWT access tokens (HS256). If your resource server was calling /introspect on every request, switch to local JWT verification via our JWKS — faster, cheaper, no network.

3. Hooks / Inline Hooks → Custom Claims

Okta Inline Hooks run a synchronous webhook during token issuance to inject claims. UniAuth equivalents:

  • Static / DB-driven claims → per-client Custom Claim Mappings in the developer console (static:value, user.field, role)
  • Dynamic / external lookup → call your backend from the client after login; do not block token issuance

4. Authorization Policies

Okta has per-AS policies with client / user / MFA / network conditions. UniAuth equivalents live in the admin console:

  • Network zones / IP allowlistip_access_list (admin → Conditional Access)
  • MFA step-up → request acr_values=urn:uniauth:acr:mfa in the authorize request
  • User group restrictions → restrict per client via access_policies
  • Risk-based auth → built-in threat detection (new IP / new UA / impossible travel); surfaces as access decisions

5. Sign-on rules / Device Trust

Okta Device Trust requires their MDM integration. UniAuth uses cookie-based Trusted Devices (signed, expiring, revocable) that skip 2FA on known devices — configurable lifetime, user-revocable from /account/security.

User Migration

Three common strategies:

Gradual (recommended)

Keep Okta live. When a user signs in to UniAuth for the first time, provision the account via SCIM from Okta or via bulk import (POST /api/admin/users/import).

Passwords: users reset on first login (magic link or password reset) — password hashes don't migrate.

Export + bulk import

Export users via Okta Users API (GET /api/v1/users), transform to the UniAuth import JSON schema, POST to /api/admin/users/import (max 10,000 per request).

Users will need to set a password or use magic links on first login.

SCIM from Okta

UniAuth exposes SCIM 2.0. Configure Okta as the SCIM client pointing at your UniAuth tenant; Okta pushes users + groups. Useful during coexistence.

Minimal Code Diff

If you used a certified OIDC library (openid-client, spring-boot-starter-oauth2-client, mozilla-django-oidc, omniauth_openid_connect), usually this is it:

- issuer:   https://{yourOrg}.okta.com/oauth2/default
- issuer:   https://{yourOrg}.okta.com
+ issuer:   https://uniauth.id
- client_id:     0oa…
- client_secret: …
+ client_id:     uni_…
+ client_secret: unis_…

Next