Identity Multi-cloud

Configure Okta FastPass and Device Assurance for Phishing-Resistant Passwordless Login

A 3,500-seat fintech keeps getting phished. Not the clumsy kind — the attackers run a real-time reverse proxy (Evilginx-style) that sits between the employee and the real Okta login, relays the password, relays the OTP, and replays the captured session cookie from their own infrastructure minutes later. Every “MFA” the company has — SMS, TOTP, push-with-number-matching — falls to it, because none of those factors are bound to the origin the user actually visited. The CISO’s mandate after the third incident is blunt: remove the password from the login entirely, make the only accepted factor one that is cryptographically tied to both the device and the real Okta domain, and refuse to authenticate any device that is not managed, encrypted, and running a healthy EDR agent. That is exactly what Okta FastPass plus Device Assurance deliver, and this guide is the step-by-step rollout — enrollment, policies, the Verify integration, the device-signal plumbing, validation, and a clean rollback — that gets you from “password + push” to phishing-resistant passwordless without locking anyone out on day one.

FastPass is Okta Verify acting as a local authenticator: it answers a WebAuthn/FIDO2-style challenge using a hardware-bound private key (Secure Enclave on macOS/iOS, TPM-backed keystore on Windows/Android) and verifies the request actually came from your real Okta org URL — so a proxied login from a look-alike domain simply fails. Device Assurance is the gate in front of it: a policy that inspects device posture (OS version, disk encryption, screen-lock, biometric, and third-party signals like a CrowdStrike Falcon Zero Trust Assessment score) and only lets a session proceed if the device meets the bar. Together they turn authentication from “something the user knows and can be tricked into relaying” into “something a healthy, enrolled device proves it possesses.” This guide assumes Okta is your primary workforce IdP, federated to Microsoft Entra ID so downstream Azure/Microsoft 365 resources accept the resulting token.

Prerequisites

Target topology

Configure Okta FastPass and Device Assurance for Phishing-Resistant Passwordless Login — topology

The flow is straightforward once you see the choke points. A user on a managed laptop opens an app — say the Akamai-fronted internal portal, or Microsoft 365. The app redirects to Okta for sign-in. Okta evaluates the Global Session Policy (do we even start a session for this user from this context) and then the app’s Authentication Policy (what does this app require). The authentication policy demands “Phishing resistant” assurance and a passing Device Assurance policy. Okta Verify / FastPass on the device answers the challenge with its hardware-bound key, signs an assertion scoped to the real Okta org URL, and supplies device-posture claims — OS version, disk encryption, management state, and the CrowdStrike Falcon ZTA score pulled via the device-signal integration. If posture passes and the cryptographic origin check passes, Okta issues the session and federates an OIDC/SAML token onward to Entra ID for the Microsoft estate. Everything that can be expressed as policy is managed as code through Terraform and shipped via GitHub Actions (or Jenkins, or promoted with Argo CD if you GitOps your config), with ServiceNow carrying the change approval and Dynatrace/Datadog watching the auth success-rate and latency so a bad policy push shows up as a graph, not a flood of help-desk tickets.

1. Confirm Identity Engine and enable the device-trust plumbing

First, verify you are on OIE and that the org can hold device context. You can do most of this in the Admin Console, but it is worth scripting the read so the state is captured in your runbook.

Pull org and authenticator state with the API (token sourced from Vault, never inlined):

# Fetch the short-lived Okta API token from HashiCorp Vault, not from disk
export OKTA_API_TOKEN=$(vault kv get -field=token secret/okta/admin-api)
export OKTA_ORG="https://kloudvin.okta.com"

# Confirm Okta Verify authenticator exists and is active
curl -s -H "Authorization: SSWS ${OKTA_API_TOKEN}" \
     -H "Accept: application/json" \
     "${OKTA_ORG}/api/v1/authenticators" \
  | jq '.[] | select(.key=="okta_verify") | {key, status, name}'

You want "status": "ACTIVE". In the Admin Console, go to Security → Authenticators, and on the Okta Verify authenticator open its settings:

Leave the policies themselves for later steps — right now you are only confirming the authenticator is on and capable.

2. Push Okta Verify and define enrollment

Passwordless dies on rollout if users have to self-enroll under pressure. Push the app silently through MDM so it is already installed when the policy flips.

A Jamf macOS deployment uses the Okta Verify pkg plus a managed-app-config profile that pre-fills the org URL so users do not type it:

<!-- Jamf / macOS managed app config payload (excerpt) -->
<dict>
  <key>OktaVerify.ManagementHint</key>
  <string>jamf</string>
  <key>OktaVerify.OrgUrl</key>
  <string>https://kloudvin.okta.com</string>
</dict>

For Windows via Intune, deploy the Okta Verify MSIX/Win32 app and a configuration that sets the same OrgUrl. On mobile, push from the managed app store (Intune Company Portal / Jamf).

Now control who can enroll and how with an Authenticator Enrollment Policy (Security → Authenticators → Enrollment). Create a policy targeting your pilot group:

Bind the policy to the pilot group only. Order matters: Okta evaluates enrollment policies top-down and stops at the first match, so the pilot policy must sit above the catch-all default.

3. Build the Device Assurance policies

Device Assurance is per-OS — you create one policy per platform and reference them from authentication policies. Go to Security → Device Assurance Policies → Add a policy, and build one per OS. A macOS policy might require:

If you manage Okta as code, express the same thing in Terraform so it is reviewable and revertable:

resource "okta_policy_device_assurance_macos" "corp_macos" {
  name                    = "Corp-macOS-Assurance"
  os_version              = "14.5.0"
  disk_encryption_type    = ["ALL_INTERNAL_VOLUMES"]
  secure_hardware_present = true
  screenlock_type         = ["BIOMETRIC"]

  # Bind device health to CrowdStrike Falcon's Zero Trust Assessment
  third_party_signal_providers = true
  tpsp_crowd_strike_agent_id   = "<falcon-customer-id>"
  tpsp_crowd_strike_customer_id = "<falcon-cid>"
}

Create the Windows equivalent (okta_policy_device_assurance_windows) requiring BitLocker, a minimum build, secure-boot/TPM, and the same Falcon signal. The CrowdStrike Falcon integration is configured once under Security → Device Integrations → Endpoint security software — you authorize Okta to read the Falcon ZTA signal, and from then on any Device Assurance policy can reference “CrowdStrike Falcon healthy” as a condition. This is the bridge that lets an identity decision depend on EDR posture: a laptop whose Falcon sensor is disabled or whose ZTA score has cratered stops satisfying assurance and is refused, even with a valid FastPass key.

4. Wire device-management attestation (so “managed” is provable)

Device Assurance can check “is this device managed by our MDM” — but only if Okta can verify the MDM’s attestation. Under Security → Device Integrations → Endpoint management, add your MDM as an attestation source: Jamf Pro for macOS, Intune / Entra ID for Windows. For the Windows/Entra path you register Okta as able to read device-compliance state from Entra, which closes the loop with Microsoft Entra ID: the same device object Entra trusts for Conditional Access is the one Okta trusts for Device Assurance, so the two platforms agree on “is this a corporate device” instead of each guessing.

Once attestation is live, you can add Registered/Managed as a hard requirement in the relevant Device Assurance policies. A device that is jailbroken, unmanaged, or has had Okta Verify side-loaded onto a personal machine then fails the managed check and never reaches the FastPass prompt.

5. Set the Global Session Policy and per-app Authentication Policies

This is where passwordless actually takes effect. Two layers:

Global Session Policy (Security → Global Session Policy) decides whether to establish an Okta session at all. Add a rule above the default, scoped to the passwordless groups, that requires the user to authenticate and forbids password as a primary factor. Keep the default rule untouched as the fall-through for everyone not yet migrated.

Authentication Policies (Security → Authentication Policies) are per-app and are where you demand phishing resistance and device posture. For each high-value app (start with the Okta Dashboard itself, then Microsoft 365, then your internal apps behind Akamai), edit the policy’s rule:

Expressed in Terraform, an app authentication-policy rule that demands phishing-resistant + device assurance looks like:

resource "okta_app_signon_policy_rule" "m365_phish_resistant" {
  policy_id                   = okta_app_signon_policy.m365.id
  name                        = "M365-PhishResistant-ManagedDevice"
  priority                    = 1
  access                      = "ALLOW"

  factor_mode                 = "2FA"
  re_authentication_frequency = "PT8H"

  # Require the phishing-resistant assurance level (FastPass / FIDO2)
  constraints = [jsonencode({
    possession = {
      required             = true,
      phishingResistant    = "REQUIRED",
      hardwareProtection   = "REQUIRED",
      userVerification     = "REQUIRED"
    }
  })]

  # Gate on device posture
  device_assurance_included = [okta_policy_device_assurance_macos.corp_macos.id]
  device_is_managed         = true
  device_is_registered      = true
}

Ship this through your pipeline rather than clicking it in prod. Wire terraform plan into a GitHub Actions PR check (authenticating with an OIDC-issued, short-lived credential and the Okta token from Vault, never a stored secret) so a reviewer sees the policy diff before it merges; run terraform apply on merge. Teams already running GitOps can have Argo CD reconcile the rendered Okta config, or drive the same apply from a Jenkins stage. Whichever you use, attach a ServiceNow change record to the merge so there is an approved, auditable trail for “we removed the password from M365 for the Engineering group.”

6. Federate the session to Entra ID

So the Microsoft estate honors the passwordless login, Okta must be the SAML/OIDC IdP for Entra. In Entra, this is the WS-Fed/SAML federation where Okta is the claims provider; the practical effect is that once a user clears FastPass + Device Assurance at Okta, the resulting assertion flows to Entra ID and Microsoft 365 / Azure resources accept it without a second password prompt. Keep one detail straight: enforce phishing-resistance and device posture at Okta (the IdP), and let Entra Conditional Access act as defense-in-depth (e.g. “require compliant device”) rather than the primary control — otherwise you maintain two policy engines that can silently disagree. Because attestation (step 4) makes Okta and Entra share the same device-compliance truth, the two layers reinforce instead of fighting.

7. Pilot enrollment walkthrough

With policies bound to the pilot group only, walk a pilot user through it once and document it for the rollout guide:

  1. Okta Verify is already installed (pushed in step 2). User opens it and taps Add account; the org URL is pre-filled.
  2. User authenticates once with their existing factor to bootstrap enrollment, then enables FastPass and sets up biometric/PIN user-verification.
  3. The device generates a hardware-bound keypair (Secure Enclave / TPM) and registers the public key with Okta. The device now appears under Directory → Devices.
  4. User signs out and signs back in to the Okta Dashboard — they should get a silent or one-tap FastPass prompt and no password field.

Have the pilot group live with it for at least a week. IT first, precisely because they run the unmanaged VMs, the old OS versions, and the second laptops that will surface every Device Assurance edge case before a non-technical user hits them.

Validation

Prove it works and prove the failure cases fail. Do all of these before widening the rollout.

# 1. Confirm the device registered a FastPass (hardware-protected) key
curl -s -H "Authorization: SSWS ${OKTA_API_TOKEN}" \
     "${OKTA_ORG}/api/v1/users/${PILOT_USER_ID}/factors" \
  | jq '.[] | select(.factorType=="signed_nonce") | {factorType, provider, status}'

# 2. Pull the System Log and verify the sign-in used a phishing-resistant factor
curl -s -H "Authorization: SSWS ${OKTA_API_TOKEN}" \
     "${OKTA_ORG}/api/v1/logs?filter=eventType+eq+%22user.authentication.auth_via_mfa%22&limit=5" \
  | jq '.[] | {actor: .actor.alternateId, factor: .authenticationContext.credentialType, result: .outcome.result}'

Then the manual checks that matter most:

Rollback / teardown

Because every change was scoped to groups and shipped as code, rollback is fast and surgical — which is the whole point of staging it this way.

  1. Immediate, per-app: in the app’s Authentication Policy rule, change the requirement from Phishing resistant back to your previous assurance (e.g. “Password / IdP + Any factor”) and detach the Device Assurance policy. Users can sign in with the old method within seconds. If you manage it in Terraform, revert the commit and apply.
  2. Restore the password factor: in the Authenticator Enrollment Policy for the affected group, set Password back to Required/Optional. Until you do, those users have no password to fall back to.
  3. Group-level kill switch: move users out of the passwordless group (or flip the group rule) so they fall through to the untouched default policies. This is the cleanest mass-rollback and the reason the default policies were never edited.
  4. Full teardown: delete the per-OS Device Assurance policies and the pilot enrollment policy, and disable FastPass on the Okta Verify authenticator. Leave Okta Verify installed — re-enrollment is then trivial when you retry.

Keep the break-glass FIDO2 admin excluded from all of this throughout; it is your guaranteed way back into the org if a rollback step itself goes wrong.

Common pitfalls

Security notes

This rollout is Zero Trust at the front door: the only accepted factor is hardware-bound and origin-checked, so credential phishing, OTP relay, and session-cookie replay from look-alike domains all stop working — which was the threat that started the project. Posture is continuous, not one-time: tie the CrowdStrike Falcon ZTA signal in so a device whose EDR is unhealthy loses access regardless of a valid key, and require secure hardware so private keys never leave the Secure Enclave/TPM. Keep the Okta admin API token short-lived and pulled from HashiCorp Vault, never committed to the Terraform repo. Retain a FIDO2 break-glass path and exclude it from policy. Pipe every DENY and policy change to your SIEM, and route a sustained denial spike to a ServiceNow incident so security investigates a ticket, not a log line.

Cost notes

The licensing reality: FastPass and Device Assurance require Okta Adaptive MFA / Identity Engine tiers (Device Assurance is typically an add-on) — confirm entitlement before you design, because the policy controls above assume it. The non-license costs are mostly one-time: the MDM to push Okta Verify and provide attestation (you likely already run Jamf/Intune), the CrowdStrike Falcon integration (already deployed if EDR is in place — Okta consumes the existing signal at no extra agent cost), and the engineering time to template policies in Terraform. Against that, the savings compound: passwordless removes the single largest help-desk category — password resets — and phishing-resistant auth removes the incident-response and breach exposure that one successful credential-relay can cost. Run it through your GitHub Actions/CI as code rather than click-ops, and the ongoing operational cost is a code review per change, with Datadog/Dynatrace giving you the success-rate signal that keeps a bad push from becoming an outage.

OktaFastPassDevice AssurancePasswordlessPhishing-ResistantZero Trust
Need this built for real?

Vinod is a Senior Cloud Architect (22+ yrs) — available for Azure / AWS / GCP architecture, landing zones, and migrations.

Work with me

Comments

Keep Reading