Okta Workflows · assurance & documentation

Know exactly what your identity automation does.

Assay reads your Okta Workflows estate and writes it down — every flow as plain, readable logic, including the loop bodies and error handlers your console never lists. Scored, dated, and ready to hand to an auditor, a new engineer, or your successor.

Runs in your browser. No credentials, no upload, no account. Thirty seconds.

Complete
Every flow
Including block bodies and handlers
Legible
As code
Each flow read back in plain logic
Measured
Scored
Five dimensions, one number
Provable
Attested
Dated and hashed for an auditor

What it does

Your automation, written down at last.

Workflows are built visually, card by card, usually under deadline. Six months later nobody can say precisely what a flow does without opening it and tracing every branch by hand. Assay reads the structure and writes the logic out — conditions, loops, calls and API requests, following the chain from one flow into the next.

Read it like code, review it like code

Every flow becomes something an engineer can scan in seconds and a reviewer can reason about. Comment cards written by the original builder are surfaced rather than buried. Auto-generated cards are suppressed. Calls into other flows are expanded where they run, so an operation reads as one continuous program.

It is the documentation your team never had time to write, generated from the estate itself — so it cannot drift out of date the way a wiki page does.

Generated from a real exportflow get_user_and_add_to_group(email, groupname): user = okta.searchUsers(query=email) if user_id != "": url = f"/api/v1/groups?search=name eq {groupname}" result = okta.hTTPRequest(method="GET", url=url) group = get(object=body, path="0.id") okta.addNewUserToGroup(group_id=group, user_id=user_id) else: return
01

The complete estate

Okta stores loop bodies and error handlers as separate flow objects inside the parent. They run in production but sit outside the console list. Across 125 public Okta template folders, recursive analysis finds 867 flows where the declared list shows 560.

02

How it all connects

A call graph showing which flow invokes which, which are entry points, and which are referenced by nothing at all. Change a helper flow knowing exactly what runs through it, and find the dead weight before you carry it into the next migration.

03

A clear picture of how it holds up

Where failures are handled, where access changes are guarded, what is traceable, what is still referenced, and which tables have a stated purpose. Five dimensions, each traced to a specific fact in your file rather than to a judgement call.

04

Evidence you can hand over

A dated, hashed attestation with a robustness score and a prioritised improvement register, written to answer an auditor asking how you know. Delivered as a document, and as structured data for your own systems.

The deliverable

Four views of the same estate.

All generated from one real folder export. The map is what the automation is — including the flows it calls, drawn inside it. The code is what it does. The report is where it stands. The register is what to do about it.

Switch between the four views
Attestation extract
Okta Workflows estate · one folder export
format 1.6.0 · 583,412 bytes · SHA-256 4f2b9e1c…8ad03e71
30
Fragile
Flows
27
18 declared · 9 hidden
Cards
237
across the estate
External calls
13
13 unguarded
Logging off
10
of 27 flows

Robustness score, by dimension

DimensionScoreWeightBasis
ResilienceFailure handling on external calls
0
30%
13 of 13 external calls run with no error policy
Privilege controlGuards on access-changing operations
20
25%
1 flow(s) can alter access, guarded no better than the calls around them
ObservabilityExecution history and traceability
63
15%
10 of 27 flows have execution logging disabled
MaintainabilityDocumentation and dead weight
29
15%
5 of 7 tables have no stated purpose
StructureReachability and visibility
72
15%
5 of 18 declared flows unreferenced; 9 block bodies invisible to the console

Control results

C-02
Every external-call card has error handling
13 of 13 external-call cards use the default finish policy.
Fail
C-07
Privileged flows are inventoried
1 flow(s) can alter access.
Review
C-09
Tables holding identity data have a stated purpose
5 of 7 tables have an empty description.
Fail
C-10
Execution history is retained where appropriate
10 of 27 flows have execution logging disabled.
Fail
C-12
No unreferenced flows
5 of 18 declared flows neither call nor are called within this export.
Fail
C-01
Every flow has an identifiable owner
The export format carries no owner field.
Not assessed
C-05
No dormant or disabled flows
The export format carries no enablement state or last-run timestamp.
Not assessed
The same operation, written out — including the flow it calls
flow add_users_from_a_table_to_an_okta_group():
    rows = stash.searchRows2(sort_direction="asc", sort_limit=200, stash=table[…], …)
    for each item in rows, …:
        # ─── enter Get user Okta id and add to group ───
            raw_output = okta.searchUsers(resultset="First Matching Record", query=email)
            # unguarded — flow stops here on failure
            if id != "":
                compose = compose(text="/api/v1/groups?search=profile.name eq "{{…", 3hugqyie0=groupname)
                status_code = okta.hTTPRequest(requesttype="GET", request_relative_url=compose)
                # unguarded — flow stops here on failure
                get = get(object=body, path="0.id")
                status2 = okta.addNewUserToGroup(group_id=get, user_id=id)
                # unguarded — flow stops here on failure
                join()
            else:
                return
        # ─── back ───
Drag any card · click for what it evaluates
SoundWorth reviewing No error handling Called flow Block body
Improvement register
Four items, in priority order
Effort is our estimate for a team already familiar with this estate
R1Attach a failure path to every external callHigh prioritySmall effort
What to change

13 of 13 external calls stop the flow on failure. Workflows supports a single shared handler flow referenced from each card.

What changes as a result

A rate limit or a transient error retries, or records itself, instead of leaving a change half-applied.

R2Stop discarding failures inside iterationHigh priorityMedium effort
What to change

A governance write runs inside a loop set to ignore errors, so per-item failures disappear.

What changes as a result

A partially applied change is reported as partial rather than as success.

R3Enable execution history where access changesMedium prioritySmall effort
What to change

10 of 27 flows have logging switched off, including flows on the grant path.

What changes as a result

Every access change leaves a record an auditor can retrieve.

R4Document the tables, remove the dead weightMedium prioritySmall effort
What to change

5 of 7 tables carry no stated purpose, and 5 flows are referenced by nothing.

What changes as a result

A new engineer can tell what each table holds and which flows still matter.

Assay reports and does not remediate. These items are written so your team, your integrator or a third party can act on them — and so the next attestation can measure whether they were.

Who it’s for

Three people ask three different questions.

Platform & IAM engineering

“What does this actually do?”

You inherited an estate. The person who built it has moved on.

  • Every flow readable in minutes
  • Dependency map before you change anything
  • Dead and unreferenced flows identified
  • Onboard an engineer in a day
Security & GRC

“How do we know, and can we prove it?”

Audit season asks what automation can change access, and who signed it off.

  • Privileged operations inventoried
  • Dated, hashed evidence
  • Independent — no vendor grading itself
  • Drift measured between cycles
MSPs & delivery partners

“Is what we built any good?”

You run automation across many tenants and need a consistent standard.

  • Per-tenant pricing
  • Same score across every client
  • Hand clients a professional artefact
  • Proof of quality at handover

Independence

A goldsmith cannot certify their own gold.

An assay office is the historic institution of independent verification: it tests the metal and strikes a hallmark, and the mark carries weight precisely because the seller did not issue it.

That is the basis of this company. A platform vendor can build excellent posture tooling — and it can never be independent evidence about itself. Assay has no commercial relationship with Okta, takes no position on whether a finding reflects well or badly on anyone, and does not sell the remediation for the problems it reports.

We also publish what we cannot tell you. The export format carries no owner field, no enabled-or-disabled marker and no last-run timestamp, so controls depending on those are reported as not assessed rather than passed. A green tick you cannot rely on is worth less than an honest gap.

Start with your own estate.

Run the free analysis on a folder export and see what is actually in there. If it is useful, the attestation is the next step — and the first five baselines are free in exchange for a conversation about the findings.

Analyse an export Get in touch