okta

v0.2.0 collector

Collects Okta organization security posture metrics

Install

epack install collector okta

Adds to epack.yaml, resolves dependencies, downloads binary.

Usage

Run all configured collectors and build a pack:

epack collect

Runs all collectors in epack.yaml and outputs an evidence pack.

Configuration

Or add manually to epack.yaml:

collectors:
  okta:
    source: https://github.com/locktivity/epack-collector-okta

Then run epack install to lock and sync.

Okta Collector Overview

The Okta collector gathers security posture metrics from your Okta organization.
At the default trust level these are org-level aggregates (percentages 0-100,
counts, and policy settings) designed to be actionable and comparable across
organizations. Higher collection levels add per-entity detail and
additional surfaces (see Collection levels below).

Output Schema

The example below is trust-level output. The collected_at_level field records
the level a given artifact was produced at.

{
  "schema_version": "1.0.0",
  "collected_at": "2026-02-25T19:46:39Z",
  "collected_at_level": "trust",
  "org_domain": "company.okta.com",

  "posture": {
    "mfa_coverage": 85,
    "mfa_phishing_resistant": 20,
    "sso_coverage": 90
  },

  "users": {
    "password_expired": 2,
    "locked_out": 0,
    "inactive": 15,
    "suspended": 3
  },

  "apps": {
    "provisioning_enabled": 40,
    "deprovisioning_enabled": 30
  },

  "privileged_access": {
    "privileged_users_count": 6,
    "super_admin_count": 2,
    "standing_privileged_users_count": 6,
    "privileged_mfa_coverage_pct": 100,
    "privileged_phishing_resistant_pct": 50
  },

  "policy": {
    "policy_count": 2,
    "mfa_required_all": false,
    "mfa_required_any": true,
    "mfa_required_coverage_pct": 33,
    "session_lifetime_min_minutes": 15,
    "session_lifetime_max_minutes": 1440,
    "idle_timeout_min_minutes": 5,
    "idle_timeout_max_minutes": 120
  },

  "device_access": {
    "managed_device_required": true,
    "managed_device_required_coverage_pct": 75,
    "managed_device_required_for_admins": true,
    "device_assurance_policies_count": 3
  }
}

Metrics Reference

posture

High-level security scores for quick assessment.

Metric Why It Matters
mfa_coverage Account takeover protection. MFA significantly reduces credential-based attacks. Low coverage leaves accounts vulnerable to password spraying and phishing.
mfa_phishing_resistant Strong authentication. Phishing-resistant factors (WebAuthn/FIDO2, U2F, and Okta FastPass) can't be phished, unlike SMS or TOTP. This is the gold standard for sensitive accounts.
sso_coverage Credential sprawl reduction. Apps not using SSO require separate passwords, increasing password fatigue and reuse risk.

users

User account health indicators.

Metric Why It Matters
password_expired Compliance and access issues. Users with expired passwords may be locked out or using workarounds that bypass security controls.
locked_out Potential attack indicator. Spikes in lockout rates may indicate brute force or credential stuffing attacks.
inactive Orphan account risk. Inactive accounts (90+ days no login) are prime targets for attackers. They may belong to departed employees or unused service accounts.
suspended Disabled account coverage. Suspended accounts should usually represent intentionally blocked access. Tracking the rate helps distinguish active workforce posture from dormant or intentionally disabled identities.

apps

Application lifecycle management health.

Metric Why It Matters
provisioning_enabled Onboarding automation. Manual provisioning delays access and increases admin burden. Automated provisioning ensures consistent access based on role.
deprovisioning_enabled Offboarding security. Without automated deprovisioning, departing employees retain app access. This is a major source of data breaches.

privileged_access

Effective admin access across directly assigned and group-inherited role assignments.

Metric Why It Matters
privileged_users_count Admin blast radius. Counts active users with any effective Okta admin role. This is the main denominator for privileged identity risk.
super_admin_count Highest-risk accounts. Super admins can fully control the tenant. Keep this count as low as possible.
standing_privileged_users_count Always-on privilege. In Okta, standard admin roles are effectively standing access unless additional JIT tooling is used outside the collector.
privileged_mfa_coverage_pct Privileged account protection. Measures how many active admins have any MFA factor enrolled.
privileged_phishing_resistant_pct Strong admin auth. Tracks phishing-resistant MFA coverage for privileged users, the highest-value identity target set.

policy

Aggregated security policy settings across active sign-on and MFA-enrollment evaluation.

Metric Why It Matters
policy_count Policy complexity. Number of active sign-on policies. More policies mean more nuanced access control but also more complexity to audit.
mfa_required_all Universal MFA enforcement. True only if all non-deprovisioned users are covered by an MFA requirement after policy evaluation.
mfa_required_any Any MFA enforcement. True if at least one non-deprovisioned user is covered by an MFA requirement.
mfa_required_coverage_pct Actual MFA enforcement coverage. Percentage of non-deprovisioned users covered by an MFA requirement after evaluating policy and rule scope, including group targeting.
session_lifetime_min_minutes Strictest session policy. The shortest session lifetime across active sign-on rules. Indicates your most restrictive access control.
session_lifetime_max_minutes Most permissive session. The longest session lifetime across active sign-on rules. Users under this policy have extended access windows.
idle_timeout_min_minutes Strictest idle policy. The shortest idle timeout across active sign-on rules. Protects high-risk users from unattended sessions.
idle_timeout_max_minutes Most permissive idle timeout. The longest idle timeout across active sign-on rules. Users under this policy stay logged in longer when inactive.

device_access

Device access enforcement posture based on sign-on policy rule conditions.

Metric Why It Matters
managed_device_required Device trust enforcement. True if any sign-on policy rule requires managed devices. Indicates that device-based access control is configured somewhere in the org.
managed_device_required_coverage_pct Device trust coverage. Percentage of non-deprovisioned users covered by a managed device requirement after evaluating policy and rule scope, including group targeting.
managed_device_required_for_admins Admin device trust. True if all privileged users are covered by a managed device requirement. Critical for protecting high-value admin accounts from untrusted endpoints.
device_assurance_policies_count Device assurance policies. Number of device assurance policies defined. These policies specify device requirements (OS version, encryption, etc.) that can be referenced in sign-on rules.

Collection levels

The surfaces above are the trust level. The level config knob (trust /
audit / internal) controls collection depth; levels are cumulative. See
levels.md for the full per-surface, per-level breakdown.

  • trust (default): the org-level aggregates documented above.
  • audit: adds per-entity detail (user / app / group / network-zone / IdP / hook / API-token inventories, per-policy and per-admin summaries, and 7-day counts of security-relevant system-log events).
  • internal: adds the rawest detail (per-user factor lists and activity timestamps, group member logins, per-policy rule conditions and actions, network-zone and IdP definitions, and the system-log event slice).

User profile attributes beyond login, passwords, session tokens, signing keys,
client secrets, and hook auth headers are never emitted at any level.

When a surface can't be collected (a missing scope, an unlicensed feature, or an
insufficient admin role), the run still succeeds and records why under a
top-level diagnostics.warnings array.

Use Cases

  • Security Baseline Assessment: Get a quick snapshot of your Okta security posture
  • Compliance Monitoring: Track MFA adoption, device trust, and policy enforcement over time
  • Risk Identification: Find inactive accounts, privileged exposure, unmanaged device access, and apps lacking deprovisioning
  • Benchmark Comparison: Compare posture across multiple Okta organizations

Okta Collector Configuration

Authentication Setup

OAuth 2.0 (Recommended)

OAuth 2.0 with private key JWT is the recommended authentication method. It provides:
- Scoped access (only the permissions you need)
- Short-lived tokens
- Better audit logging

Step 1: Create a Service App

  1. Go to Okta Admin Console → Applications → Applications
  2. Click "Create App Integration"
  3. Select "API Services" and click Next
  4. Name your application (e.g., "epack-collector")
  5. Click Save

Step 2: Configure Public Key

  1. In the app settings, go to "Client Credentials"
  2. Edit the "Client authentication" section
  3. Select "Public key / Private key"
  4. Disable DPoP: Uncheck "Require Demonstrating Proof of Possession (DPoP) header in token requests"
  5. In the "Public keys" section below, click "Edit"
  6. Keep "Save keys in Okta" selected
  7. Click "Generate new key"
  8. Important: When prompted, choose PEM format (not JWK/JSON)
  9. Download the private key immediately - Okta only shows it once
  10. Save the private key securely (e.g., ~/.okta/epack-private-key.pem)
  11. Copy the Key ID: After saving, expand the key details to find the Key ID (a string like abc123xyz...). You'll need this for your epack config.

Step 3: Grant API Scopes

  1. Go to the Okta API Scopes tab
    The scopes you need depend on the collection level. A scope you
    don't grant isn't fatal: the surfaces that need it are skipped with a
    diagnostics.warnings entry rather than failing the run.

  2. Click Grant next to each scope you need:

Trust level (the default):
- okta.users.read
- okta.groups.read
- okta.apps.read
- okta.policies.read
- okta.roles.read
- okta.deviceAssurance.read (device-access surface; needs the Device Assurance feature)

Audit and internal additionally need: okta.authenticators.read,
okta.networkZones.read, okta.idps.read, okta.eventHooks.read,
okta.inlineHooks.read, okta.logs.read, okta.orgs.read,
okta.apiTokens.read.

Step 4: Assign Admin Role

OAuth scopes alone aren't enough - the service app needs an admin role to access org-wide resources.

  1. Go to Security → Administrators
  2. Click Add Administrator
  3. In the "Admin" field, search for and select your service app (e.g., "epack-collector")
  4. Under "Role", select Read Only Administrator (assign it org-wide, not constrained to a resource set)
  5. Click Save Changes

Privileged-access note: listing who holds admin roles is gated behind a
Super Administrator-level role; Read-Only Administrator cannot. With Read-Only
Admin, the privileged_access surface is skipped with a diagnostic. Grant the
app Super Administrator if you need privileged-user counts; otherwise
Read-Only Admin is sufficient for every other surface.

Step 5: Configure epack

collectors:
  okta:
    source: locktivity/epack-collector-okta@^0.2
    config:
      org_domain: your-org.okta.com
      client_id: 0oa1234567890abcdef   # From app settings
      key_id: abc123xyz                # From public key settings
      level: trust                     # trust (default) | audit | internal
    secrets:
      - OKTA_PRIVATE_KEY               # PEM-encoded private key

Set the environment variable (use the PEM file you downloaded):

export OKTA_PRIVATE_KEY="$(cat ~/.okta/epack-private-key.pem)"

API Token (Legacy)

API tokens are simpler to set up but less secure:
- Tokens don't expire automatically
- Tokens have full permissions of the user who created them
- Harder to audit

Step 1: Create an API Token

  1. Go to Okta Admin Console → Security → API → Tokens
  2. Click "Create Token"
  3. Name it (e.g., "epack-collector")
  4. Copy the token value immediately (it won't be shown again)

Step 2: Configure epack

collectors:
  okta:
    source: locktivity/epack-collector-okta@^0.2
    config:
      org_domain: your-org.okta.com
    secrets:
      - OKTA_API_TOKEN

Set the environment variable:

export OKTA_API_TOKEN="00abcdef..."

Configuration Options

Option Required Description
org_domain Yes Your Okta organization domain (e.g., company.okta.com)
client_id For OAuth OAuth 2.0 client ID from your service app
key_id For OAuth Key ID from the public key settings in your Okta app
level No Collection depth: trust (default), audit, or internal. See levels.md. Unrecognized values fall back to trust.

Environment Variables

Variable Description
OKTA_PRIVATE_KEY PEM-encoded RSA private key for OAuth 2.0
OKTA_API_TOKEN SSWS API token (legacy authentication)

Troubleshooting

"Authentication required" error

Ensure either:
- client_id, key_id config and OKTA_PRIVATE_KEY env var are all set (for OAuth), OR
- OKTA_API_TOKEN env var is set (for API token auth)

"Token exchange failed" or "invalid_client - JWT kid is invalid" error

For OAuth 2.0:
- Verify the client_id is correct
- Verify the key_id matches the Key ID shown in Okta (General → Client Credentials → Public Keys)
- Ensure the private key matches the public key configured in Okta (they're a matched pair)
- Make sure DPoP is disabled

(A missing OAuth scope does not fail the token exchange — Okta drops ungranted
scopes from the issued token, and the affected surface degrades; see "Missing
data" below.)

"Rate limited" errors

The collector handles rate limits automatically with exponential backoff. If you see persistent rate limit errors:
- Reduce collection frequency
- Contact Okta support to increase rate limits

Missing data / a surface is zeroed

When a surface can't be collected, the run still succeeds and records why under
diagnostics.warnings in the output. Common causes:

  • Missing scope. Each surface needs its scope granted for the level you're running (see Step 3 and levels.md).
  • privileged_access is zero. Listing admin-role assignments needs a Super Administrator-level role; Read-Only Admin can't (see the privileged-access note in Step 4).
  • device_access is empty. Needs okta.deviceAssurance.read and the Device Assurance feature.
  • A feature isn't licensed. Custom admin roles need Okta Identity Governance; the custom-role inventory is skipped otherwise.
  • API token auth. Access is governed by the token owner's admin role rather than scopes; ensure that role covers the surfaces you need.

Examples

Basic Usage

Using OAuth 2.0 (Recommended)

stream: myorg/okta-posture

collectors:
  okta:
    source: locktivity/epack-collector-okta@^0.2
    config:
      org_domain: company.okta.com
      client_id: 0oa1234567890abcdef
      key_id: abc123xyz
      level: trust   # optional: trust (default) | audit | internal — see levels.md
    secrets:
      - OKTA_PRIVATE_KEY

Then run:

export OKTA_PRIVATE_KEY="$(cat /path/to/private-key.pem)"
epack collect

See Configuration for OAuth 2.0 setup instructions.

Using API Token (Legacy)

stream: myorg/okta-posture

collectors:
  okta:
    source: locktivity/epack-collector-okta@^0.2
    config:
      org_domain: company.okta.com
    secrets:
      - OKTA_API_TOKEN

Then run:

export OKTA_API_TOKEN=00abcdef...
epack collect

Sample Output

{
  "protocol_version": 1,
  "data": {
    "schema_version": "1.0.0",
    "collected_at": "2026-02-25T14:00:00Z",
    "collected_at_level": "trust",
    "org_domain": "company.okta.com",
    "posture": {
      "mfa_coverage": 85,
      "mfa_phishing_resistant": 20,
      "sso_coverage": 90
    },
    "users": {
      "password_expired": 2,
      "locked_out": 0,
      "inactive": 15,
      "suspended": 3
    },
    "apps": {
      "provisioning_enabled": 40,
      "deprovisioning_enabled": 30
    },
    "privileged_access": {
      "privileged_users_count": 6,
      "super_admin_count": 2,
      "standing_privileged_users_count": 6,
      "privileged_mfa_coverage_pct": 100,
      "privileged_phishing_resistant_pct": 50
    },
    "policy": {
      "policy_count": 2,
      "mfa_required_all": false,
      "mfa_required_any": true,
      "mfa_required_coverage_pct": 33,
      "session_lifetime_min_minutes": 15,
      "session_lifetime_max_minutes": 1440,
      "idle_timeout_min_minutes": 5,
      "idle_timeout_max_minutes": 120
    }
  }
}

This is trust-level output (org-level aggregates; coverage values are percentages
0-100). The audit and internal levels add per-entity inventories and extra
surfaces. See Overview for metric descriptions and levels.md
for the per-level breakdown.

CI/CD Integration

GitHub Actions (with OAuth 2.0)

name: Collect Evidence

on:
  schedule:
    - cron: "0 0 * * 1"  # Weekly on Monday
  workflow_dispatch:

jobs:
  collect:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install epack
        run: |
          curl -sSL https://github.com/locktivity/epack/releases/latest/download/epack-linux-amd64 -o epack
          chmod +x epack
          sudo mv epack /usr/local/bin/

      - name: Collect evidence
        run: epack collect --frozen
        env:
          OKTA_PRIVATE_KEY: ${{ secrets.OKTA_PRIVATE_KEY }}

      - name: Upload pack
        uses: actions/upload-artifact@v4
        with:
          name: evidence-pack
          path: "*.pack"

Store the Okta private key as a repository secret named OKTA_PRIVATE_KEY.

Multiple Okta Organizations

To collect from multiple Okta orgs, define separate collectors:

stream: mycompany/identity-posture

collectors:
  okta-prod:
    source: locktivity/epack-collector-okta@^0.2
    config:
      org_domain: company.okta.com
      client_id: 0oa1234567890abcdef
      key_id: prodkey123
    secrets:
      - OKTA_PROD_PRIVATE_KEY

  okta-preview:
    source: locktivity/epack-collector-okta@^0.2
    config:
      org_domain: company.oktapreview.com
      client_id: 0oa0987654321fedcba
      key_id: previewkey456
    secrets:
      - OKTA_PREVIEW_PRIVATE_KEY

Then set both environment variables:

export OKTA_PROD_PRIVATE_KEY="$(cat prod-key.pem)"
export OKTA_PREVIEW_PRIVATE_KEY="$(cat preview-key.pem)"
epack collect
v0.2.0 Latest
2026-05-20

**Full Changelog**: https://github.com/locktivity/epack-collector-okta/compare/v0.1.7...v0.2.0

darwin/amd64 darwin/arm64 linux/amd64 linux/arm64
v0.1.7
2026-04-22

**Full Changelog**: https://github.com/locktivity/epack-collector-okta/compare/v0.1.6...v0.1.7

darwin/amd64 darwin/arm64 linux/amd64 linux/arm64
v0.1.6
2026-04-02

**Full Changelog**: https://github.com/locktivity/epack-collector-okta/compare/v0.1.5...v0.1.6

darwin/amd64 darwin/arm64 linux/amd64 linux/arm64
v0.1.5
2026-03-18

**Full Changelog**: https://github.com/locktivity/epack-collector-okta/compare/v0.1.4...v0.1.5

darwin/amd64 darwin/arm64 linux/amd64 linux/arm64
v0.1.4
2026-03-02

**Full Changelog**: https://github.com/locktivity/epack-collector-okta/compare/v0.1.2...v0.1.4

darwin/amd64 darwin/arm64 linux/amd64 linux/arm64
v0.1.3
2026-02-27

**Full Changelog**: https://github.com/locktivity/epack-collector-okta/compare/v0.1.0...v0.1.3

darwin/amd64 darwin/arm64 linux/amd64 linux/arm64
v0.1.2
2026-02-27

**Full Changelog**: https://github.com/locktivity/epack-collector-okta/compare/v0.1.0...v0.1.2

darwin/amd64 darwin/arm64 linux/amd64 linux/arm64
v0.1.1
2026-02-27

**Full Changelog**: https://github.com/locktivity/epack-collector-okta/commits/v0.1.1

darwin/amd64 darwin/arm64 linux/amd64 linux/arm64
v0.1.0
2026-02-26

**Full Changelog**: https://github.com/locktivity/epack-collector-okta/commits/v0.1.0

darwin/amd64 darwin/arm64 linux/amd64 linux/arm64

Details

Publisher
locktivity
Latest
v0.2.0
Protocol
v1

Platforms

darwin/amd64 darwin/arm64 linux/amd64 linux/arm64

Links