Directory Sync Conflict Resolution at Scale in Okta
A plain-English guide to what happens when two systems disagree about the same person: where sync conflicts come from, how Okta imports, matches and applies data, how to decide who wins, and how to detect, resolve, and prevent conflicts when you manage tens of thousands of identities across many directories.
Every identity system tells a story about each person: their name, their job, their manager, their groups, whether they still work here. The trouble starts when two systems tell different stories at the same time. The human resources system says Priya moved to Finance on Monday. The company directory still says she is in Sales. A second directory, left over from an acquisition, spells her surname differently. A script that someone wrote three years ago keeps changing her title back. Which story is right, and how does the sign-in platform decide?
That question is the heart of directory sync conflict resolution. With a few hundred people, conflicts are rare and someone simply fixes them by hand. With tens of thousands of people, many directories, and imports running around the clock, conflicts become a constant background hum, and a poor strategy turns the hum into outages, lockouts, and quiet security gaps. This guide teaches the subject from zero. You will learn the vocabulary, how Okta pulls in and applies directory data, the different kinds of conflict, how to decide who wins, and how to detect, resolve, and prevent problems when volume grows. The companies and numbers in the examples are invented for teaching.
1What a Sync Conflict Really Is
A sync conflict is simply a disagreement between two sources of information about the same thing. Understanding it clearly makes everything else easier.
The plain definition
Okta keeps a profile for every person. That profile is filled in from one or more outside sources, such as Active Directory, another directory service, or a human resources system. Each source sends its own version of the facts. When two sources send different values for the same fact, or when a source sends something that does not fit what Okta already holds, you have a conflict. Something has to decide which value is kept.
Notice that a conflict is not always an error in the technical sense. Nothing crashes. No red warning appears. The system happily picks one value and moves on. The danger is exactly that quietness: a wrong choice made silently, thousands of times, can leave people with the wrong access or no access at all.
Why scale changes the game
- More sources. Each extra directory or feed multiplies the ways two stories can differ.
- More frequency. Imports run every hour or even more often, so a bad rule repeats itself many times a day.
- More people. A mistake that touches one percent of users is a nuisance at 200 people and a crisis at 50,000.
- More owners. Different teams own different sources and may change them without telling the identity team.
- Less visibility. Nobody can eyeball tens of thousands of profiles, so problems hide until someone complains.
Imagine a village where the post office, the school, and the clinic each keep a list of residents. When one family moves, each list is updated by a different clerk on a different day. For a while the three lists disagree. In a small village, everybody knows the truth anyway. In a city of a million, the lists must follow clear rules about whose list wins, or letters, school places, and appointments go to the wrong doors.
Throughout this guide, ask the same three questions about every kind of conflict: what disagrees, who should win, and how will we notice when it goes wrong. Those three questions are the whole discipline in miniature.
2The Vocabulary You Need
A handful of words carry most of the meaning in this topic. Learn them once and the rest reads easily.
Source of truth
The system that is trusted to be right about a particular fact. Different facts can have different sources of truth.
Profile
The record Okta keeps for a person, made of many attributes such as name, email, department, and manager.
Attribute
One named fact on a profile, such as a job title or a phone number.
Import
Pulling people and their facts from an outside source into Okta.
Push
Sending changes from Okta out to another system, such as a directory or an application.
Mastering
Declaring which source is allowed to control which attributes of a profile.
Matching
Deciding whether an incoming record is the same person as someone Okta already knows.
Linking
Joining a source record to an existing Okta profile so they behave as one identity.
Drift
The slow growth of differences between systems that were once in agreement.
Reconciliation
Comparing two systems on purpose to find and fix differences.
Idempotent
An operation that gives the same result whether it runs once or many times.
Quarantine
Holding a questionable change aside for review instead of applying it.
Think of a group project where several people edit one shared document. Each person owns certain sections. Importing is copying someone’s edits in, pushing is sending your edits out, and mastering is the agreement about who may change which section. Without that agreement, edits overwrite one another.
One more word deserves attention: stable identifier. This is a value that never changes for a person or an account even when everything else does. Names change at marriage, emails change at rebrands, and departments change monthly. A stable identifier, such as an employee number or a directory’s internal account identifier, is what lets a system keep recognizing the same person through all of that change. Almost every good conflict strategy leans on stable identifiers.
3Where Conflicts Come From
Conflicts have ordinary, human causes. Knowing the usual suspects tells you where to look first.
The common sources
- Multiple directories. Head office, acquired companies, regional teams, and old migrations each keep their own copy of a person.
- An HR system plus directories. HR knows job facts, directories know sign-in facts, and both sometimes try to describe the same thing.
- Manual edits. An administrator fixes a typo in one place and forgets the others.
- Scripts and tools. Old automation keeps writing values nobody remembers authorizing.
- Mergers and migrations. Accounts are copied between systems and briefly exist twice.
- Timing gaps. A change reaches one system hours before it reaches another.
- Data quality. Spelling variants, extra spaces, reused employee numbers, and shared mailboxes.
- Product behavior. Import settings, matching rules, and push options that interact in ways no one planned.
| Cause | Typical symptom | Where to look first |
|---|---|---|
| Two directories hold the same person | Duplicate users or a profile that flips between values | Matching rules and source priority |
| HR and directory both write titles | Title changes back after every import | Attribute mastering |
| Manual edit in one system | Value reverts at next sync | Who owns the attribute |
| Old script | Unexplained changes at odd hours | Audit trail of who changed what |
| Reused employee number | New hire inherits a former employee’s access | Identity key design |
| Slow replication | Brief lockouts or stale data | Timing and ordering |
When two mapmakers copy from different old maps, their new maps disagree in the same places every time, near the roads that were rebuilt. Conflicts cluster around change, so the busiest areas of your organization, such as reorganizations and mergers, are where to expect them.
4The Architecture of Directory Sync in Okta
To resolve conflicts, you first need a picture of how data travels into Okta and back out.
The cast of characters
- Sources. Directories such as Active Directory or LDAP, and human resources systems. They hold the original facts.
- Connectors and agents. Small programs, usually installed inside your network, that read the source and talk to Okta over outbound connections.
- The Okta profile. The unified record that applications and policies actually use.
- Mappings. Rules that translate a source’s attribute names and formats into Okta’s profile fields and back.
- Applications and targets. Where Okta sends identity data onward, sometimes including back into a directory.
flowchart LR
AD1["Directory A"] --> AG1["Agent A"]
AD2["Directory B"] --> AG2["Agent B"]
HR["HR system"] --> CON["HR connector"]
AG1 --> IMP["Okta import engine"]
AG2 --> IMP
CON --> IMP
IMP --> MAT["Matching"]
MAT --> MAP["Mappings and source priority"]
MAP --> PRO["Okta user profile"]
PRO --> APP["Applications and policies"]
PRO -->|"Push"| AD1
Read the picture left to right. Sources hand their records to Okta through agents or connectors. The import engine receives them, matching decides which Okta person each record belongs to, and mappings with source priority decide which values land in the profile. The finished profile is what applications and policies see. In some designs, Okta then pushes changes back out, which creates a second direction of traffic and a second place for conflicts to arise.
A newsroom receives wire reports from several agencies. An editor decides which reports describe the same story, which agency to trust for which details, and then publishes one article. Agents are the wires, matching is the editor deciding it is the same story, and mappings with priority decide whose facts appear in print.
5How an Import Works Inside
Every conflict is born during an import or a push. Here is what happens during an import, step by step, in plain language.
Read from the source
The agent asks the directory for the people in scope and brings back their attributes. A full import reads everyone. An incremental import reads only what changed since last time.
Stage the records
Okta holds the incoming records in a waiting area and compares them with what it already knows. Nothing has changed in the real profiles yet.
Match each record
For each incoming record, Okta applies matching rules to find an existing person. The result is a confirmed match, a partial match that needs a decision, or no match, which means a new person.
Apply mappings
Attribute values are translated and, where several sources provide the same attribute, source priority decides which value is kept.
Apply lifecycle actions
New people can be created, existing people updated, and people missing from the source can be deactivated, depending on the settings you chose.
Record the outcome
Okta logs what it created, updated, skipped, or flagged, which is the evidence you will later use to investigate conflicts.
Full versus incremental
A full import is a complete photograph. It is slower, but it can notice people who disappeared. An incremental import is a list of recent edits. It is fast and gentle, but it only knows about changes it was told about. If an incremental feed misses a change, perhaps because a replication hiccup hid it, the difference stays hidden until a full import catches it. Healthy designs combine both: frequent incrementals for freshness, periodic fulls for truth.
stateDiagram-v2
[*] --> Reading
Reading --> Staged: "records received"
Staged --> Matching
Matching --> Mapping: "match found or new person"
Matching --> NeedsReview: "ambiguous match"
Mapping --> Applying
Applying --> Logged
NeedsReview --> Logged
Logged --> [*]
A full import is a yearly stocktake where every shelf is counted. An incremental import is a daily note of what was sold. The daily notes keep you current, but only the stocktake can reveal an item that quietly vanished without a note.
6Following One Attribute Through the Pipeline
The best way to feel a conflict is to follow a single fact, such as a job title, as it moves through the system.
Suppose Priya’s job title is “Sales Manager” everywhere. On Monday, HR promotes her and records “Finance Manager”. The HR connector delivers the new title to Okta within the hour. Okta updates the profile. Applications see the new title.
Now add a complication. The corporate directory still holds “Sales Manager” because a directory administrator updates titles only quarterly. At the next directory import, the old title arrives. Whether Okta overwrites the new title with the old one depends entirely on the rule you set. If the directory has equal or higher priority for titles, the promotion is silently reversed. Priya’s profile shows “Sales Manager” again, and a policy that grants Finance tools by title quietly removes her access.
sequenceDiagram
participant HR as HR system
participant OK as Okta profile
participant DIR as Directory
HR->>OK: "Title is Finance Manager"
Note over OK: "Profile updated"
DIR->>OK: "Title is Sales Manager"
alt "Directory has higher priority"
Note over OK: "Title reverted to Sales Manager"
else "HR has higher priority"
Note over OK: "Directory value ignored"
end
The lesson is that conflict outcomes are decided by configuration, not by luck and not by which update arrived most recently. Good teams treat priority as a deliberate, documented decision, made attribute by attribute.
If a downstream policy or application rule depends on an attribute such as department or title, then a wrong value is not just cosmetic. It silently changes who can do what. Always ask which rules depend on an attribute before deciding how conflicts for it are handled.
Two clerks each hold a card with your address. When you move, you tell clerk one. If clerk two’s card is later treated as the master, your mail goes to the old house, even though you did the right thing. What matters is not who is right but which card the postman trusts.
7A Map of Conflict Types
Conflicts fall into a few families. Naming the family tells you which tool to reach for.
| Family | What disagrees | Example | Main tool |
|---|---|---|---|
| Identity key | Two people claim the same sign-in name or key | Two employees both become “asmith” | Unique username format |
| Matching | Whether two records are one person | Same person in two directories imported twice | Matching rules on strong keys |
| Attribute | The value of one field | Different job titles | Source priority per attribute |
| Group | Names, nesting, and membership | Two groups called “Admins” | Prefixes and ownership |
| Lifecycle | Whether a person is active | Disabled in one directory, active in another | Deactivation policy |
| Credential | Which password is current | Reset in two places | One password authority |
| Timing | Which change came first | Rehire arrives before the leaver record | Ordering and checks |
| Write-back | Okta and directory change the same field | Edit loop | One direction per attribute |
flowchart TD
C["Sync conflict"] --> K["Identity key"]
C --> M["Matching"]
C --> A["Attribute"]
C --> G["Group"]
C --> L["Lifecycle"]
C --> P["Credential"]
C --> T["Timing"]
C --> W["Write-back"]
A doctor does not treat every illness the same way. First she sorts symptoms into families, such as infection, injury, or allergy, and each family has its own treatments. A conflict taxonomy plays the same role: sort first, then treat.
8Identity Key Conflicts: Names That Collide
The most basic conflict is two different people wanting the same sign-in name.
Why collisions are inevitable
Names are not unique. In a company of fifty thousand, there are many people named John Smith, and short formats that use first initial and surname will collide constantly. Each directory may have solved this locally, with one adding a number to the second Smith and another adding a middle initial. When their users all flow into Okta, collisions appear that neither directory could have seen alone.
What goes wrong
- A second person with the same username is rejected, and their import fails or sits unfinished.
- Worse, a system may treat the second record as an update to the first, so one person’s details overwrite another’s.
- A new hire is given the name of a former employee, and inherits old access or old email.
How to prevent them
- Pick a username format that is unique by construction, such as including an employee number or the full email address of a unique mailbox.
- Audit all directories for overlapping names before the first big import, and fix them at the source.
- Never reuse an identifier after someone leaves, or reserve retired names for a long quiet period.
- Keep the stable account identifier as the real key, and treat the visible name as a label.
flowchart TD
N["Incoming record: asmith"] --> E{"Name already in Okta?"}
E -- "No" --> CR["Create new user"]
E -- "Yes" --> S{"Same stable identifier?"}
S -- "Yes" --> UP["Update existing user"]
S -- "No" --> QU["Collision: hold for review"]
Test your username format on a list of real names from all directories before going live. Count how many collisions it produces. If the answer is more than zero, adjust the format now, while no one is affected.
Two students named Sam Lee enroll in a school. If the school files them both under “Lee, S.”, one report card goes to the wrong family. A student number makes the confusion impossible, and the name becomes just a friendly label.
9Matching Conflicts: Wrong Merges and Missed Merges
Matching decides whether two records are the same human being. It can fail in two opposite directions, and both hurt.
Two ways to be wrong
Wrong merge
- Two different people are joined into one profile.
- One person sees the other’s access, mail, or data.
- A security incident hiding as a data problem.
- Hard to notice, because the merged profile looks tidy.
Missed merge
- One person ends up with two profiles.
- Policies and reviews apply twice, or only to one half.
- Access is split between accounts, confusing audits.
- Easy to notice, because duplicates show up in lists.
Of the two, the wrong merge is more dangerous, so a careful design leans toward missing a merge rather than making a false one. A duplicate can be cleaned up later at leisure. A false merge can expose data the moment it happens.
Choosing good matching keys
- Strong keys. Employee number, a government-independent unique person identifier from HR, or a verified corporate email.
- Weak keys. First name, last name, department, or phone number. These are fine as supporting evidence, never as the only basis.
- Combined rules. Match when a strong key agrees and a second attribute does not contradict it.
- Sample before switching on. Review the proposed matches for a few hundred people before allowing automatic linking.
quadrantChart
title Matching risk by key strength
x-axis Weak key --> Strong key
y-axis Rare data --> Common data
quadrant-1 Safe and useful
quadrant-2 Needs a second check
quadrant-3 Avoid
quadrant-4 Safe but incomplete
Employee number: [0.9, 0.8]
Corporate email: [0.75, 0.7]
Full name: [0.2, 0.9]
Phone number: [0.3, 0.3]
A bank clerk who sees two accounts for “R. Kumar” does not merge them because the names look alike. She asks for a tax number or a signed form. Names are a hint, and a unique number is proof.
10Attribute Conflicts: Two Writers, One Field
When two sources provide the same attribute, something must choose. If nothing does, the value flips back and forth.
The flip-flop symptom
The classic sign is an attribute that changes at every import. The HR feed writes “Finance”, then the directory writes “Sales”, then HR writes “Finance” again, hour after hour. Each write looks legitimate to the system. Logs fill with updates. Downstream applications receive change notifications constantly, and rules based on the attribute turn on and off like a flickering light.
Common attribute conflict patterns
| Pattern | What you see | Typical fix |
|---|---|---|
| Equal-priority writers | Value flips at every import | Give one source higher priority |
| Format mismatch | “Dr. Rao” versus “RAO, Dr” | Normalize with a mapping expression |
| Code versus label | “FIN” versus “Finance” | Translate codes to labels in one place |
| Empty overwrite | A blank value erases a real one | Ignore empty values from weaker sources |
| Stale source | Old value restores itself | Fix the stale source or lower its priority |
| Multi-value fields | Lists merged or replaced unexpectedly | Decide whether to merge or replace |
Empty values are a quiet danger. If a weaker source has no manager for someone and the system treats “no value” as a real value, it can erase the correct manager that another source supplied. Treat blanks from non-master sources as “no opinion”, not as “delete”.
flowchart TD
V["Incoming value"] --> B{"Is it blank?"}
B -- "Yes, from weaker source" --> IG["Ignore it"]
B -- "No" --> P{"Source has priority for this attribute?"}
P -- "Yes" --> AP["Apply value"]
P -- "No" --> SK["Skip and keep current"]
Two housemates each adjust the thermostat when they feel too hot or cold. The temperature swings all day. The cure is not a better thermostat; it is a house rule that says who controls it.
A worked illustration
Consider a mobile phone number. HR holds a company mobile number, the directory holds whatever the employee last typed into a self-service page, and a facilities system holds a desk phone. If all three write the same field with equal priority, the number changes every time a different import finishes first. A better design keeps three separate attributes: a work mobile owned by HR, a personal contact number owned by the employee, and a desk phone owned by facilities. Many attribute conflicts vanish once you notice that two sources were never describing the same fact, only facts with the same label. Before ranking sources, ask whether you are really looking at one attribute or several that have been squeezed under one name.
Another useful habit is to give every attribute a short written definition, such as “the number a manager should call in an emergency”. Definitions expose hidden disagreements long before data does, because two teams that both believe they own “phone” will quickly discover they mean different things.
11Profile Mastering and Source Priority
The central tool for attribute conflicts is deciding, in advance, which source owns which fact.
The principle: one owner per attribute
The cleanest designs give every attribute exactly one owner. Business facts, such as title, department, manager, start date, and employment status, are usually owned by the HR system, because HR is where those facts legitimately change. Technical facts, such as the sign-in name, the directory identifier, and group membership for infrastructure access, are owned by the directory that issues them. Contact details can be owned by whichever system people actually update, often the directory or a self-service portal.
| Attribute | Suggested owner | Reason |
|---|---|---|
| Job title | HR system | Changes through formal HR events |
| Department and cost center | HR system | Tied to organization structure |
| Manager | HR system | Reporting lines are an HR fact |
| Employment status and dates | HR system | Drives joiner, mover, leaver flows |
| Sign-in name | Issuing directory | Must match the real account |
| Directory group membership | Directory | Controls infrastructure access |
| Mobile number | User self-service or directory | Changes outside HR |
When one owner is not possible
Sometimes two sources must both contribute, such as a person who exists in two directories. Then use ranked priority: the first source wins when it has a value, the second fills in when it does not. Write the ranking down, share it with the owners of every source, and review it whenever a source is added or retired.
flowchart LR
HRS["HR system"] -->|"Priority 1: business facts"| PRF["Okta profile"]
DIRA["Main directory"] -->|"Priority 2: sign-in facts"| PRF
DIRB["Acquired directory"] -->|"Priority 3: fills gaps only"| PRF
In a hospital, the lab owns blood results, the pharmacy owns medicine lists, and reception owns contact details. A nurse would never ask reception for a blood count. Clear ownership prevents arguments about whose record is right.
12Group Conflicts: Names, Nesting, and Membership
Groups look simple, but they carry more conflict potential than people do, because they combine names, members, and nesting.
The usual troubles
- Same name, different groups. Two directories each have “Engineers”. Imported together, they look like one group, or they collide.
- Nested groups. Groups inside groups may be flattened or ignored, changing who is really a member.
- Cross-domain members. A group in one domain holds people from another, and the importing agent cannot always see them.
- Two masters. Membership is edited both in the directory and in Okta, so changes cancel each other.
- Huge groups. Groups with tens of thousands of members take long to import and push, and partial failures become likely.
Resolution approaches
- Give imported groups a prefix that names the source, so the names can never collide.
- Decide for each group whether the directory or Okta is the master, and never both.
- Prefer rules-based groups in Okta for access that depends on attributes, and keep directory groups for infrastructure.
- Test nested and cross-domain behavior with sample groups before importing the real ones.
- Split enormous groups into smaller purposeful ones.
flowchart TD
G1["Directory A: Engineers"] --> PA["Okta group: A-Engineers"]
G2["Directory B: Engineers"] --> PB["Okta group: B-Engineers"]
PA --> RULE["Rules combine members for access"]
PB --> RULE
Two sports clubs in neighboring towns are both called “The Eagles”. A league that merges their member lists without noting the town will mix up the teams. Adding the town to the name keeps them apart.
13Lifecycle Conflicts: Active, Disabled, or Gone?
Few conflicts are as costly as disagreeing about whether someone still works here.
Typical disagreements
- HR marks someone as terminated, but their account in a second directory is still enabled.
- A directory account is disabled temporarily during leave, and Okta deactivates the person permanently.
- A person is rehired, and an old deactivated profile competes with a brand new one.
- An import runs with the wrong scope and proposes to deactivate thousands of people at once.
Principles that keep lifecycle safe
- Let HR own employment status whenever an HR system exists, and treat directory flags as secondary.
- Treat a missing record carefully. A person absent from one import may have moved, not left.
- Prefer suspension over deletion for the first period after an apparent departure.
- Cap bulk actions. Stop and ask when an import would deactivate more than a small percentage of people.
- Reconcile across all directories so no leaver stays enabled somewhere.
stateDiagram-v2
[*] --> Active
Active --> OnLeave: "leave recorded"
OnLeave --> Active: "return"
Active --> Suspended: "departure signal"
Suspended --> Active: "rehire or mistake corrected"
Suspended --> Deactivated: "grace period ends"
Deactivated --> [*]
The most dangerous lifecycle conflict is the quiet one: a leaver disabled in the main system but forgotten in a smaller, older directory. That account has no owner, no monitoring, and often a password that never changes. Reconcile every directory against HR on a schedule.
When a hotel guest checks out, the front desk, housekeeping, and the key system must all agree. A card key that still opens the door a week later is the kind of leftover that causes real harm.
14Credential Conflicts: Whose Password Counts?
Passwords can be held, checked, or reset in more than one place. When they disagree, people simply cannot sign in.
Two basic models
- Delegated authentication. Okta passes the password to the directory, which says yes or no. The directory is the only authority, so there is nothing to disagree with.
- Password synchronization. Okta stores its own protected copy, updated whenever the directory password changes. Two copies exist, so mismatches are possible.
How credential conflicts appear
- A person resets their password in Okta but the directory still holds the old one.
- A directory password is changed by a help desk, and the sync to Okta is delayed.
- Policies differ: the directory demands twelve characters and the cloud accepts eight.
- An account is locked in one system while the other keeps allowing attempts.
Resolution
Choose one password authority per population, and make the other systems follow it. Align password rules between Okta and the directory. Send password resets to the authority, never around it. Where delegated authentication is used, remember that sign-in now depends on the directory being reachable, so resilience of that path matters.
sequenceDiagram
participant U as User
participant OK as Okta
participant AG as Agent
participant DC as Directory
U->>OK: "Sign in with password"
OK->>AG: "Verify this password"
AG->>DC: "Check credentials"
DC-->>AG: "Accepted"
AG-->>OK: "Accepted"
OK-->>U: "Signed in"
If a building has two security desks that each keep a list of approved visitors, a visitor approved at one desk may be turned away at the other. Having a single desk that keeps the list, and the other asking it, removes the argument.
15Timing and Ordering Conflicts
Even when every rule is right, changes can arrive in the wrong order. Time itself becomes a source of conflict.
Where timing hurts
- Replication delay. A change made in one domain controller has not yet reached the one the agent reads from.
- Import schedules. A directory import and an HR import run minutes apart, and the later one carries older data.
- Rehire before leaver. A rehire record arrives before the earlier termination has been processed.
- Move during import. A person is moved between organizational units while an import is reading, so they appear twice or not at all for one cycle.
- Clock differences. Servers disagree about the current time, so “latest change wins” picks the wrong change.
Defenses
- Keep clocks synchronized across all servers involved.
- Schedule imports so that the highest-priority source finishes last, or, better, use priority instead of arrival order.
- Read from a consistent, healthy directory controller close to the agent.
- Make updates safe to repeat, so a late arrival corrects itself on the next cycle.
- Prefer eventual convergence: design so that a wrong value fixes itself within a cycle rather than lingering.
sequenceDiagram
participant HR as HR system
participant OK as Okta
participant DIR as Directory
HR->>OK: "Rehire recorded at 09:00"
DIR->>OK: "Account still disabled at 09:05"
Note over OK: "Without priority, the older status wins"
DIR->>OK: "Account enabled at 10:00"
Note over OK: "Correct state at next cycle"
When a letter and a later phone call about the same appointment reach you in the wrong order, you must decide which to believe. A rule such as “the phone call from the doctor’s office always wins” removes the guesswork, no matter which arrives first.
Time zones, daylight changes, and clock trust
Large organizations span time zones, and some systems record local time while others record universal time. A change stamped at nine in the morning in one region and eight in the evening elsewhere may be the same instant or a day apart. If any rule compares timestamps, such as latest change wins, make sure every source is converted to one standard time first. Daylight saving changes add a further trap, because an hour of the year occurs twice and another does not occur at all, so scheduled imports can run twice or be skipped on those nights.
The safest approach is to avoid relying on timestamps for important decisions. Use priority for ownership, use stable identifiers for identity, and use time only to decide when to look again. Where time is unavoidable, keep a single trusted clock source across servers and record offsets in every log.
16Write-Back Conflicts: When Okta Changes the Source
Sync normally flows into Okta, but sometimes Okta pushes changes back to a directory. This creates a second direction, and with it the risk of loops.
Why write-back exists
Many organizations still run applications that read from the directory. If Okta manages groups or attributes centrally, those applications need the changes. So Okta writes to the directory, which then becomes both a source and a target of the same data.
The loop problem
Imagine an attribute that is imported from the directory and also pushed back. Okta changes the value, the directory stores it, the next import brings it back, Okta sees a “change” and pushes again, and so on. Best case, it wastes resources. Worst case, two slightly different transformations fight each other forever, and the value drifts or flips.
Rules that prevent loops
- Make each attribute flow in only one direction.
- Do not import an attribute that you also push, or mark one direction as authoritative.
- Use narrow write permissions so the push can only touch what it should.
- Keep privileged accounts and groups out of both import and push.
- Watch the audit logs for attributes that change repeatedly in short periods.
flowchart LR
DIR["Directory"] -->|"Import"| OK["Okta"]
OK -->|"Push"| DIR
DIR -.->|"Loop risk if same attribute"| OK
Two people who each correct the other’s spelling in a shared note can edit the same word back and forth forever. Letting only one of them own the word ends the argument.
17Detecting Conflicts: Drift and Reconciliation
You cannot resolve what you cannot see. Detection turns silent disagreements into visible, countable work.
Two detection styles
- Event-based. Watch each import and push for signs of trouble: records skipped, matches held for review, attributes changing repeatedly, users proposed for deactivation.
- Comparison-based. On a schedule, compare sources with Okta and with each other, and list the differences. This is reconciliation.
What to compare
| Comparison | What a difference means |
|---|---|
| HR active list versus enabled directory accounts | Leavers still enabled, or workers without accounts |
| Directory A versus directory B by employee number | People with accounts in both, candidates for linking |
| Okta profile versus master source, per attribute | Drift, or an unowned writer |
| Okta groups versus directory groups | Membership drift and push failures |
| Count of users per source over time | Sudden jumps that suggest scope mistakes |
flowchart TD
S1["Export from source A"] --> CMP["Comparison job"]
S2["Export from Okta"] --> CMP
CMP --> D["List of differences"]
D --> T{"Known and expected?"}
T -- "Yes" --> OK["Record and ignore"]
T -- "No" --> Q["Open a ticket with owner"]
Track the number of differences over time, not just the list. A flat, small number means healthy. A slow climb means drift is winning. A sudden spike means a recent change broke something.
A shop that counts its cash register against the day’s receipts every evening catches a missing note the same day. A shop that counts once a year will never find out when or why it vanished.
18Resolution Strategies: Choosing Who Wins
Once a conflict is seen, a rule must decide. There are only a handful of basic strategies, and each suits different facts.
Source priority
The higher-ranked source always wins. Predictable and easy to explain. Best for attributes with a clear owner.
Latest change wins
Whichever change is newest is kept. Simple, but fragile when clocks or delays distort the order.
Fill the gaps
Take the first non-empty value in a ranked list. Good for contact details with many possible sources.
Manual review
A person decides. Slow, but right for rare, risky cases such as ambiguous matches.
Quarantine
Hold the change aside and keep the old value until reviewed. Protects against mass damage.
Reject and report
Refuse the incoming change and log it. Good for data that breaks a rule, such as a malformed identifier.
Matching strategy to fact
| Kind of fact | Best strategy | Why |
|---|---|---|
| Employment status | Source priority to HR with a suspension step | Clear owner, high impact |
| Job title and department | Source priority to HR | Formal events only |
| Contact details | Fill the gaps | Many legitimate sources |
| Ambiguous person match | Manual review or quarantine | Wrong merges are risky |
| Bulk deactivation | Quarantine above a limit | Protects from scope mistakes |
| Malformed data | Reject and report | Do not spread bad values |
flowchart TD
CF["Conflict detected"] --> R{"Clear owner for this fact?"}
R -- "Yes" --> PR["Apply source priority"]
R -- "No" --> I{"Risky if wrong?"}
I -- "Yes" --> HU["Quarantine for review"]
I -- "No" --> FG["Fill the gaps from ranked sources"]
A referee in a game has a rulebook for common calls, takes a quick look at the video for close ones, and stops the game when a serious injury is possible. Different situations get different levels of care.
19Designing a Written Conflict Policy
The best conflict strategy lives on paper, agreed by the people who own each source, before the first import.
What the policy contains
- The list of all sources, with an owner and a contact for each.
- For every attribute, the owning source and the fallback order.
- The identity key and the matching rules, with examples of edge cases.
- Group ownership rules and naming prefixes.
- Lifecycle rules, including grace periods and bulk action limits.
- Who reviews quarantined items, how fast, and how decisions are recorded.
- How and when the policy itself may change.
HR owns employment facts
Title, department, manager, and status come from the HR system. Directory values for these fields are ignored once the HR record exists. Reason: formal events in HR are the only legitimate trigger for these changes.
Employee number is the matching key
Accounts are linked across directories only when the employee numbers agree and a second attribute does not contradict. Name-only matches are never automatic. Reason: false merges are costly.
Bulk deactivation is capped
An import that would deactivate more than two percent of people in a source is held for human approval. Reason: scope mistakes are far more likely than real mass departures.
flowchart LR
OWN["Source owners agree"] --> POL["Written policy"]
POL --> CFG["Okta configuration"]
CFG --> MON["Monitoring and reports"]
MON --> REV["Periodic review"]
REV --> POL
A neighborhood agreement on shared fences says who repairs which stretch and how costs are split. When a storm knocks one down, nobody argues. The agreement was written on a calm day for a stormy one.
20Scale: Volume, Rate Limits, and Batching
When the number of identities grows, the mechanics of moving data become a conflict source of their own.
What changes at scale
- Imports take longer. A full import of a very large directory can run for a long time, and the next scheduled one may start before it ends.
- Rate limits matter. Okta and the directories both limit how fast requests are accepted. Heavy imports, pushes, and automation compete for the same budget.
- Partial failures are normal. Out of a million operations, a few will fail, and the system must carry on gracefully.
- Peaks occur. Start of year, reorganizations, and acquisitions send thousands of changes at once.
Techniques
- Scope imports tightly, so only people who need Okta are read.
- Prefer incremental imports for freshness and schedule full imports outside business peaks.
- Stagger directories so they do not all import at the same minute.
- Throttle automation that calls Okta, and make it back off politely when told to slow down.
- Batch changes in sensible sizes and avoid enormous one-shot jobs.
- Split enormous groups and reduce attributes that change constantly.
| Symptom | Likely cause | Response |
|---|---|---|
| Import still running when the next starts | Too frequent or too broad | Lengthen interval, narrow scope |
| Throttling messages | Too many requests at once | Stagger and back off |
| Updates arrive late in applications | Queues behind big jobs | Move bulk work to quiet hours |
| Some records fail every night | Bad data in a few records | Fix at source, report the list |
gantt
title A staggered import day
dateFormat HH:mm
axisFormat %H:%M
section Incremental
Directory A :a1, 00:00, 10m
Directory B :a2, 00:15, 10m
HR feed :a3, 00:30, 10m
section Full
Directory A full :b1, 02:00, 60m
Directory B full :b2, 03:30, 45m
A city does not let every delivery truck enter the market at six in the morning. Slots are staggered so the gates do not jam. Imports, like trucks, need schedules once the traffic grows.
Thinking in budgets
A helpful way to plan for scale is to treat capacity as a budget that several activities share. Imports spend some of it, pushes to applications spend some, administrators using the console spend some, and automation scripts spend some. When the budget runs out, requests are slowed or refused, and the activity that suffers is often the one you can least afford to delay, such as a new hire needing access on their first morning. List every consumer of capacity, estimate the busiest hour, and leave headroom for surprises. When a consumer is not urgent, schedule it away from the busiest hour. When it is urgent, protect it by reducing less important consumers.
Remember also that a change which seems tiny can multiply. Adding one attribute to the mapping of a directory with fifty thousand people means fifty thousand more values to compare and, if they differ, fifty thousand updates flowing onward to every connected application. Estimate the multiplier before you press the button.
21Scale: Many Directories, Regions, and Agents
Large organizations rarely have one directory. Each additional one multiplies the conflict surface.
Layout choices
- One Okta connection per directory or forest. Clear boundaries, separate settings, easier troubleshooting.
- At least two agents per connection. One agent failing should not stop the import, but two agents with different directory views can also create inconsistent reads, so keep them near healthy, well-replicated controllers.
- Regional placement. Place agents close to the directories they read, to cut delays and timeouts.
Cross-directory consistency
Every attribute mapping must be defined consistently across directories, or the same person will look different depending on which directory supplied the record. Create a shared mapping standard, and use the same naming, formats, and codes. Where directories differ in structure, translate to a common shape during import instead of at every consumer.
flowchart LR
subgraph EU["Europe"]
DE["Directory EU"] --> AE1["Agent 1"]
DE --> AE2["Agent 2"]
end
subgraph US["Americas"]
DU["Directory US"] --> AU1["Agent 1"]
DU --> AU2["Agent 2"]
end
AE1 --> OK["Okta"]
AE2 --> OK
AU1 --> OK
AU2 --> OK
Keep a single table that lists, for every attribute, how each directory supplies it and how it is translated. When a conflict appears, that table is the first place to look, and it prevents new directories from inventing new formats.
A multinational company with offices in many countries needs one chart of accounts, even if each office keeps local books. Without a shared structure, head office cannot add up the results.
22Idempotency, Retries, and Partial Failure
At scale, failures are routine. The question is whether a failure leaves a mess or heals by itself.
Idempotent by design
An operation is idempotent when doing it twice has the same effect as doing it once. “Set the department to Finance” is idempotent. “Add one to the counter” is not. Sync should be built from idempotent steps, so that when an import is interrupted and run again, the people already updated stay the same and only the unfinished ones change.
Handling failure
- Retry with patience. Temporary failures such as timeouts should be retried after a growing delay, not hammered.
- Isolate bad records. One malformed person must not block ten thousand good ones.
- Report persistent failures. If the same record fails repeatedly, someone must see it and fix the data.
- Avoid half-finished states. Where a change has two parts, such as moving someone and updating their groups, check both parts afterward.
- Prefer convergence. The next cycle should repair anything the last cycle missed.
flowchart TD
OP["Operation"] --> RES{"Succeeded?"}
RES -- "Yes" --> DONE["Record success"]
RES -- "Temporary failure" --> WAIT["Wait, then retry"]
WAIT --> OP
RES -- "Permanent failure" --> REP["Report record and continue"]
A postal worker who finds a locked gate tries again later, leaves a notice for an address that does not exist, and keeps delivering the rest of the route. The route as a whole is never held hostage by one door.
23Safety Rails: Caps, Previews, and Quarantine
The goal of safety rails is simple: a bad rule should hurt a few people, not everyone.
Preview before applying
Where possible, look at what an import would do before it does it. Check counts of creates, updates, and deactivations.
Cap bulk changes
Set limits on how many users one run may deactivate or modify. Anything larger waits for a human.
Quarantine the unusual
Hold ambiguous matches, mass changes, and malformed records in a review queue while the old values stay in place.
Pilot new rules
Apply a new rule to one small group first. Compare results with expectations before widening.
Keep a kill switch
Know in advance how to pause an import or a push quickly, and who is allowed to do it.
Keep a way back
Record the settings before a change and be able to restore them. Keep exports so affected users can be restored.
flowchart LR
IMP["Import result"] --> CHK{"Within limits?"}
CHK -- "Yes" --> APL["Apply"]
CHK -- "No" --> HLD["Hold in quarantine"]
HLD --> HUM["Human review"]
HUM --> APL
HUM --> RJ["Reject and fix source"]
A safety rail that nobody tests is just a hopeful sentence in a document. Rehearse the kill switch and the restore steps on a quiet day, with the people who would use them in an emergency.
Electrical systems use fuses and circuit breakers so that a fault in one room trips one switch instead of burning the house. Caps and quarantine are fuses for your identity data.
24Security Considerations
Sync conflicts are not only an operations problem. They can be used to gain access, or they can accidentally hand it out.
How conflicts become security problems
- Account takeover by matching. If an attacker can create a directory account with an email that matches a privileged person, a weak match rule could link it to that person’s profile.
- Reused identifiers. A new hire given a former employee’s identifier may inherit their access.
- Stale leavers. Accounts left enabled in forgotten directories are favorite targets.
- Attribute-based privilege. If a rule grants access by department, then anyone who can edit department in any source can change their own access.
- Overpowered sync accounts. A service account with too many rights can write anywhere if it is stolen.
- Hidden writers. Old scripts and tools that change profiles without anyone watching.
Protective habits
- Match on strong keys that ordinary people cannot choose themselves.
- Keep privileged and administrator accounts out of automatic matching and group push.
- Give sync service accounts only the rights they use, and monitor them closely.
- Limit who can edit attributes that drive access, in every source.
- Alert on changes to matching rules, mappings, priorities, and agent registration.
- Review hidden writers and retire or document every one.
flowchart TD
ATT["Attacker edits a source attribute"] --> RULE{"Does a rule trust that attribute?"}
RULE -- "Yes" --> ACC["Gains access through the rule"]
RULE -- "No" --> BLK["No effect"]
ACC --> DET["Detected by change alert"]
If a club lets anyone who claims to be a “senior member” into the lounge, then the claim itself becomes the key. Whoever can write the claim controls the door.
25Monitoring and Alerting
Monitoring is the early warning system for conflicts. The aim is to hear about trouble from a dashboard rather than from a frustrated executive.
What to watch
| Signal | What it tells you | Alert when |
|---|---|---|
| Connected agents per directory | Whether sync and sign-in paths are healthy | Fewer than two are connected |
| Import duration and completion | Whether imports finish before the next begins | Duration climbs steadily or an import fails |
| Created, updated, deactivated counts per import | Whether a run behaves normally | Counts far above the recent average |
| Records held for review | Backlog of unresolved ambiguity | Queue grows or items age beyond target |
| Attributes changed repeatedly | Flip-flop between two writers | The same field changes many times a day |
| Duplicate profile candidates | Missed merges | New duplicates appear after an import |
| Reconciliation difference count | Overall drift | Number rises week after week |
| Configuration changes | Who altered matching, mappings, or priority | Any change outside an approved window |
| Sync service account activity | Possible misuse or lockout | Lockout or sign-in from an unexpected place |
Good alerts versus noisy alerts
An alert is only useful if someone acts on it. Every alert should name what happened, why it matters, who owns it, and what to look at first. Alerts that fire daily and are always ignored teach the team to ignore all alerts. Start with a small number of alerts that matter, tune them until they are rare and meaningful, and then add more.
flowchart LR
LOG["Import and audit logs"] --> RULES["Alert rules"]
AGT["Agent health"] --> RULES
REC["Reconciliation results"] --> RULES
RULES --> PAGE["Page on-call for urgent"]
RULES --> TKT["Ticket for routine"]
RULES --> DASH["Dashboard for trends"]
A car dashboard shows only a few lights: oil, temperature, battery. If it flashed a hundred warnings for every small vibration, the driver would cover it with tape. Choose the few warnings that truly deserve a glance and make each one mean something.
Baselines and seasons
An alert threshold is only meaningful against a baseline. Collect a few weeks of normal numbers for imports: how many people are created, updated, and deactivated on an ordinary day, and how long runs take. Then express alerts relative to that baseline, for example when the number of proposed deactivations exceeds three times the recent average. Remember seasons: the first week of a new year, graduation months, and reorganization quarters all produce legitimate spikes. Mark these in your calendar so the team can tell an expected surge from a mistake, and so that alerts are tuned instead of silenced.
Finally, test the alerts. Occasionally create a harmless fake condition in a test setup and confirm that the right person is notified within the expected time. An alert that has never been seen to fire is an assumption, not a control.
26Troubleshooting a Conflict Step by Step
When a report arrives, such as “my title keeps changing” or “I have two accounts”, a steady routine beats guesswork.
Identify the family
Is it a name collision, a matching issue, an attribute dispute, a group issue, a lifecycle disagreement, a password problem, a timing issue, or a write-back loop? Use the map from earlier to sort the symptom.
Look at the person
Find their Okta profile and each source record. Compare stable identifiers, values, and timestamps side by side.
Read the history
Check audit logs to see who or what changed the value and when. This often reveals a hidden writer or a repeating pattern.
Check the policy
Ask what the written policy says should win. If the system behaved differently, the configuration is wrong. If it matched the policy, the policy may need to change.
Fix the cause, then the case
Correct the underlying rule or source first, so the problem does not return, then repair the affected profile.
Look for siblings
If one person had the problem, others probably do too. Search for the same pattern across the population and fix them together.
flowchart TD
RP["User reports a problem"] --> FAM["Sort into a conflict family"]
FAM --> CMP["Compare Okta profile with each source"]
CMP --> HIS["Read audit history"]
HIS --> POL{"Matches written policy?"}
POL -- "No" --> CFG["Fix configuration"]
POL -- "Yes" --> REV["Review the policy itself"]
CFG --> SIB["Search for similar cases"]
REV --> SIB
Write down each solved case in a short shared note: the symptom, the cause, and the fix. After a few months this note becomes a library that makes new cases faster and teaches new team members what to expect.
A good mechanic does not replace parts at random. She listens, checks the history, tests one thing at a time, and then asks whether other cars of the same model have the same fault. Fixing the one car without asking the last question leaves the next breakdown waiting.
27The Operating Model: Roles, Queues, and Response Times
Technology alone does not resolve conflicts. People with clear roles do, and at scale the roles need to be written down.
Roles
Source owner
Responsible for the quality of one source, such as the HR system or a directory. Fixes data at its origin.
Identity platform team
Owns Okta configuration, matching, mappings, and agents, and keeps the written policy up to date.
Conflict reviewers
Handle quarantined items, ambiguous matches, and unusual cases within an agreed time.
Help desk
First contact for users. Has a short guide for common conflicts and knows when to escalate.
Security and audit
Reviews privileged exceptions, access-driving attributes, and the record of manual decisions.
Queues and response targets
| Type of item | Example | Suggested response goal |
|---|---|---|
| Urgent | Mass deactivation proposed, suspected false merge of privileged accounts | Within the hour |
| High | Leaver still enabled in a directory, sign-in blocked for a group | Same business day |
| Normal | Ambiguous match, duplicate profile, attribute dispute | Within two business days |
| Low | Cosmetic format differences | Batch weekly |
Response goals are an agreement, not a law of nature. The right numbers depend on your size and risk appetite. What matters is that they exist, that the queue is visible, and that old items are noticed. A quarantine that nobody reads is the same as having no safety rail at all, because the held change blocks real people while it waits.
flowchart TD
ITEM["Conflict item"] --> SEV{"Severity"}
SEV -- "Urgent" --> ONC["On-call identity engineer"]
SEV -- "High or normal" --> REVQ["Reviewer queue"]
SEV -- "Low" --> BAT["Weekly batch"]
ONC --> RES["Resolve and record decision"]
REVQ --> RES
BAT --> RES
A hospital emergency room sorts patients as they arrive: life-threatening cases go straight in, minor ones wait. Without sorting, the person with a headache blocks the person having a heart attack.
28Change Management and Testing
Most severe conflicts are caused by changes: a new mapping, a new source, a new rule. Handling change well prevents most trouble.
Changes that deserve extra care
- Adding or removing an organizational unit from import scope.
- Changing matching rules or the username format.
- Changing source priority or attribute mappings.
- Turning on deactivation, write-back, or group push.
- Connecting a new directory or HR source.
- Changing the sync service account or its rights.
A test set that finds problems
| Test person | What it proves |
|---|---|
| Two people with the same short name | Username format is truly unique |
| One person with accounts in two directories | Matching links correctly |
| Two similar people who are different | Matching refuses a false merge |
| Person with blank fields in one source | Blanks do not erase good data |
| Person moved between units | Moves do not look like leavers |
| Disabled, expired, and locked accounts | Lifecycle rules behave |
| Rehired former employee | No clash between old and new profile |
| Member of nested and large groups | Group behavior and size limits |
A safe sequence
Describe the change and how to undo it. Test in a non-production setup with the test people above. Preview in production if the feature allows it. Pilot with a small group and compare results with expectations. Roll out in stages, watching the monitoring signals from the earlier chapter. Keep the previous settings recorded and the way back rehearsed.
flowchart LR
DESC["Describe change and rollback"] --> TST["Test with test people"]
TST --> PRE["Preview in production"]
PRE --> PIL["Pilot small group"]
PIL --> ROL["Staged rollout"]
ROL --> OBS["Observe signals"]
Do not combine several risky changes in one window. If you change scope, matching, and priority together and something breaks, you will not know which one did it, and undoing all three loses the good work too.
A pilot runs a checklist before takeoff, tests controls one at a time, and does not experiment with new equipment during a storm. The checklist is dull and effective because the cost of failure is high.
29Mergers and Migrations: Conflicts at Their Peak
No situation produces more conflicts than combining two companies or moving from one directory to another. The best defense is preparation.
Why the peak is so high
- Two complete populations arrive together, with overlapping names, emails, and employee numbers.
- Some people hold accounts on both sides, and some roles are duplicated.
- Naming conventions, group structures, and attribute formats all differ.
- Pressure to finish quickly tempts teams to skip tests.
- The people who understood the old systems may have left.
A calm approach
Inventory both sides
Export people, groups, and attributes from the new source and list owners.
Analyze overlaps
Count collisions in names, emails, and numbers. Decide the username format and matching keys from the evidence.
Clean at the source
Fix typos, duplicates, and reused identifiers before import, not after.
Import with actions off
Bring people in without lifecycle actions, review proposed matches, and resolve ambiguities by hand.
Turn on features gradually
Enable group import, then updates, then deactivation, each after a quiet period of review.
Retire the old source slowly
Keep it read-only for a time, reconcile, and remove only when nothing depends on it.
gantt
title A merger integration outline
dateFormat YYYY-MM-DD
axisFormat %b
section Preparation
Inventory and overlap analysis :p1, 2026-01-05, 21d
Source cleanup :p2, after p1, 21d
section Integration
Import with actions off :i1, after p2, 14d
Match review and pilot :i2, after i1, 21d
Enable lifecycle actions :i3, after i2, 14d
section Retirement
Read-only and reconcile :r1, after i3, 30d
Two families moving into one house first decide where the furniture goes, sort out duplicate items, and label boxes. Moving everything in at once and sorting later leads to arguments and lost belongings.
People problems inside the technical problem
Integration projects often stumble on people more than on data. Two teams that used to compete may disagree about whose naming convention survives, whose directory is the master, and whose administrators keep their rights. Technical rules that quietly pick winners can feel like personal verdicts. Involve both sides in writing the ownership policy, explain the reasons behind each choice, and keep a record of exceptions. When a decision is based on evidence, such as a collision count or a data quality score, it is far easier to accept than one that seems to come from nowhere.
Plan also for the users. People whose usernames change need clear notice, a transition period if possible, and a place to ask questions. A well-run technical migration that surprises the users still feels like a failure to them.
30Failure Scenarios and Recovery
A short list of failures accounts for most of the bad days. Knowing them in advance makes them far less frightening.
| Failure | Symptom | Recovery | Prevention |
|---|---|---|---|
| Import deactivates many users | Mass sign-in failures soon after a run | Pause imports, reactivate people, correct scope | Caps, previews, quiet-period scope changes |
| False merge of two people | One person sees another’s access | Unlink, correct data, review the access granted | Strong keys, sample review |
| Flip-flopping attribute | Constant change events, unstable access | Set priority, stop the second writer | One owner per attribute |
| Write-back loop | Values drift in both systems | Stop the push, repair values | One direction per attribute |
| All agents for a directory down | Sync and delegated sign-in stop | Restore an agent, check network and account | Two or more agents, staggered patching |
| Source feed sends bad data | Blank or wrong values appear widely | Quarantine the feed, restore from export | Validation and thresholds on incoming data |
| Old source retired too early | Remaining users lose access | Reconnect the source, relink | Read-only period and dependency checks |
A recovery rhythm
- Stop the bleeding. Pause the import or push that is causing damage. A pause is cheap and reversible.
- Protect emergency access. Use a tightly controlled break-glass account that does not depend on the directory.
- Communicate early. Tell support teams and affected users what is happening and when to expect an update.
- Find the cause. Check recent changes first, since most incidents follow a change.
- Repair and verify. Fix the cause, restore affected people, and verify with real users.
- Learn. Write down the cause and add the alert or check that would have caught it sooner.
flowchart TD
INC["Incident"] --> STOP["Pause the suspect import or push"]
STOP --> ACC["Confirm emergency access works"]
ACC --> COM["Communicate status"]
COM --> CAU["Find recent change or cause"]
CAU --> FIX["Repair and verify"]
FIX --> LRN["Record lessons and add checks"]
When a pipe bursts, the first act is turning off the water at the main valve, not mopping the floor. Pausing the sync is that valve. Cleaning up is easy once the flood has stopped.
31Design Patterns That Work
These approaches have repeatedly proved themselves. Adapt them to your own situation.
One owner per attribute
Every attribute has a single authoritative source, written in the policy. Other sources may fill gaps but never overwrite. This removes flip-flopping at its root.
Stable identifiers as the real key
Identity is anchored to an immutable identifier, and names and emails are treated as labels that may change. Renames, moves, and rebrands then never create a new person.
Prefer missing a merge over a false merge
Matching is tuned toward caution. Ambiguous cases go to a review queue, and duplicates are cleaned up later at leisure.
Suspend before deactivating
A departure signal first suspends access and starts a grace period. Only when the period ends without correction does deactivation occur.
Fuses on every bulk action
Caps, previews, and quarantine are standard on any rule that can touch many people at once.
Reconcile on a schedule
Automatic comparison of HR, directories, and Okta runs regularly, and the number of differences is a tracked health measure.
One direction per attribute
No attribute is both imported and pushed. Where Okta manages a value for a legacy application, the directory is a target only for that attribute.
flowchart TD
SRC["Many sources"] --> OWN["One owner per attribute"]
OWN --> KEY["Stable identifiers as keys"]
KEY --> MAT["Cautious matching"]
MAT --> RAIL["Caps and quarantine"]
RAIL --> PROF["Clean Okta profile"]
PROF --> REC["Scheduled reconciliation"]
REC --> OWN
A well-run kitchen has a single head chef for each station, labels on every container, and a rule to throw out anything unmarked. The rules are not clever, but they stop mistakes from reaching the table.
32Anti-Patterns to Avoid
These habits look convenient and cause lasting trouble. Learn to recognize them early, especially in inherited setups.
Anti-patterns
- Last writer wins by accident. No priority is set, so whichever import ran last decides.
- Matching on names. Different people merged because they share a name.
- Blanks as deletes. A weaker source with an empty field erases a correct value.
- Unlimited deactivation. A scope mistake empties the company overnight.
- Both-way attributes. The same field imported and pushed, creating loops.
- Hidden writers. Scripts that change profiles with no owner or record.
- Quarantine with no reader. Held items pile up and block real people.
- Reconciling only the main directory. Leavers survive in smaller ones.
- Fixing cases, not causes. The same ticket returns every month.
- Untested rollback. The way back is discovered to be broken during the incident.
Better habits
- Explicit priority. One owner per attribute, written down.
- Strong-key matching. Employee number plus a second check.
- Blanks mean no opinion. Empty values from non-owners are ignored.
- Capped bulk actions. Previews and approval above a threshold.
- One direction per attribute. Import or push, never both.
- Known writers only. Every automation documented and monitored.
- Staffed review queue. Age of oldest item is watched.
- Reconcile every directory. HR compared with all of them.
- Root cause fixes. Search for siblings and prevent repeats.
- Rehearsed recovery. Kill switch and restore tested on quiet days.
| Anti-pattern | What it causes | Quick fix |
|---|---|---|
| No source priority | Values flip with each import | Rank sources per attribute |
| Name-only matching | False merges, data exposure | Match on employee number plus check |
| Blank overwrites | Missing managers and titles | Ignore blanks from weaker sources |
| Uncapped deactivation | Mass lockouts | Add a percentage cap and approval step |
| Hidden automation | Unexplained changes | Inventory writers and use audit logs |
The most dangerous anti-pattern is the one that has run quietly for years. A setup that has never failed feels safe, but it may simply never have met the condition that breaks it. Review old configurations as if they were new, because the people and data around them have changed.
A house with old wiring may glow happily for decades. The danger is not what it does every day but what it does on the evening when every appliance runs at once. Anti-patterns hide until the load arrives.
33Trade-Offs, Best Practices, and Common Mistakes
Every choice gives something up. Naming the trade-offs makes decisions deliberate and defensible.
The main trade-offs
| Choice | Gain | Cost | Lean toward it when |
|---|---|---|---|
| Strict single owner per attribute | Predictability, no flip-flopping | Owner mistakes spread, slower fixes outside owner | Clear authoritative system exists |
| Ranked sources with gap filling | Resilience, fewer empty fields | Harder to explain where a value came from | Several partial sources, such as contact details |
| Latest change wins | Simplicity | Fragile with clock or delay problems | Low-risk, self-service attributes |
| Cautious matching with review | Safe from false merges | Review workload and some duplicates | Privileged or sensitive populations |
| Automatic matching on strong keys | Speed and low effort | Bad source data spreads quickly | Clean, well-maintained keys |
| Quick deactivation | Faster closing of access | More false lockouts | High-risk environments with good data |
| Suspend then deactivate | Time to catch errors | Short delay before final removal | Most organizations |
| Frequent imports | Fresh data | More load, more chances to apply bad data fast | Rapidly changing populations |
| Push to directory | Legacy applications stay current | Write rights and loop risk | Applications cannot yet use Okta directly |
Best practices
- Draw every source, its owner, and its data flows before configuring anything.
- Write the conflict policy and get each source owner to agree to it.
- Audit overlaps in names, emails, and numbers across all sources first.
- Choose unique usernames and stable identifier keys.
- Rank sources per attribute and ignore blanks from non-owners.
- Prefix imported groups and decide group direction explicitly.
- Start with lifecycle actions off, preview, pilot, and roll out in stages.
- Cap bulk actions and keep a rehearsed kill switch.
- Monitor agents, import counts, review queues, and configuration changes.
- Reconcile all sources on a schedule and track the difference count.
Common mistakes
- Assuming imports from different directories will not collide.
- Treating a missing record as a leaver without a grace step.
- Forgetting that a moved account may look like a new one.
- Combining several risky changes in one window.
- Leaving the review queue unstaffed.
- Letting people who can edit access-driving attributes go unmonitored.
- Ignoring clocks and time zones across systems.
quadrantChart
title Choosing a resolution strategy
x-axis Low impact if wrong --> High impact if wrong
y-axis Clear owner exists --> No clear owner
quadrant-1 Human review
quadrant-2 Gap filling with checks
quadrant-3 Latest change or gap filling
quadrant-4 Strict priority with caps
Contact details: [0.2, 0.7]
Self-service nickname: [0.1, 0.3]
Job title: [0.6, 0.15]
Employment status: [0.9, 0.1]
Ambiguous person match: [0.9, 0.9]
This picture is a way of thinking, not a measurement. Low-impact facts with no clear owner can use flexible rules. High-impact facts with a clear owner should use strict priority with caps. High-impact facts with no clear owner deserve human attention, because that combination is where wrong guesses become incidents.
A traveler packs differently for a day trip and a month abroad. Light trips allow improvisation, while serious ones need lists and backups. Match the care you take to the cost of being wrong.
34Governance, Metrics, and Continuous Improvement
A conflict program improves only if you measure it. A few simple numbers tell you whether things are getting better or worse.
Measures worth tracking
| Measure | Why it matters | Healthy direction |
|---|---|---|
| Reconciliation differences | Overall drift between systems | Flat or falling |
| Items in the review queue and oldest age | Whether safety rails are staffed | Small and short |
| Duplicate profile candidates | Missed merges and data quality | Falling |
| Attributes with repeated changes | Hidden flip-flop conflicts | Near zero |
| Leavers still enabled anywhere | Real security exposure | Zero, quickly corrected |
| Incidents caused by sync changes | Quality of change management | Falling |
| Time to resolve by severity | Operating model health | Meets targets |
The improvement loop
- Review monthly. Look at the measures and the top causes of conflicts. One chart of the biggest cause per month is often enough.
- Fix the sources. Many conflicts trace to bad data that source owners can clean permanently. Share the list with them.
- Update the policy. When a new kind of case appears twice, add a rule for it.
- Retire old rules. Remove mappings, scripts, and exceptions that no longer serve a purpose.
- Share what you learn. Publish short notes so support, security, and source owners see patterns.
flowchart LR
MEA["Measure"] --> ANA["Find top causes"]
ANA --> FIX["Fix sources and rules"]
FIX --> POL["Update policy"]
POL --> MEA
Celebrate a falling conflict count with the source owners who made it fall. Data quality is a shared effort, and teams that see their work valued keep improving their part.
A gardener who walks the beds every week and pulls the first weeds never faces a jungle. A gardener who visits once a year faces a weekend of labor. Regular small attention beats occasional heroic cleanup.
35Worked Example: Northwind Logistics
To bring everything together, here is an invented company and a complete conflict strategy. The company, numbers, and names are made up for teaching.
The company
Northwind Logistics is a fictional freight company with 42,000 employees and contractors. It has a main corporate directory, two acquired companies with their own directories, a regional directory for warehouse staff that has never been fully cleaned, and a cloud HR system. Five years of mergers left it with 3,100 people who have accounts in more than one directory, an unknown number of orphaned accounts, and a help desk that receives about 400 identity tickets a month, a quarter of which are “my details keep changing” or “I have two accounts”.
The strategy
| Area | Decision |
|---|---|
| Attribute ownership | HR owns title, department, manager, status. Directories own sign-in names and infrastructure groups. |
| Matching | Employee number plus corporate email domain check. Name-only never automatic. Ambiguous cases to a review queue. |
| Usernames | Email-style names with company element, generated once and never reused. |
| Groups | Source prefixes, rules-based groups in Okta for access, no push to the warehouse directory except one reviewed group. |
| Lifecycle | HR status drives; suspend for ten days, then deactivate; cap of two percent per run. |
| Scale | Staggered incremental imports every thirty minutes; full imports at night; two agents per directory in the same region. |
| Monitoring | Alerts for fewer than two agents, big import counts, repeating attributes, and aging review items. |
| Reconciliation | Weekly HR versus all directories, with a published difference count. |
flowchart LR
HR["HR system"] -->|"Owns business facts"| OK["Okta profile"]
D1["Corporate directory"] -->|"Sign-in facts"| OK
D2["Acquired directory 1"] -->|"Sign-in facts, prefixed groups"| OK
D3["Acquired directory 2"] -->|"Sign-in facts, prefixed groups"| OK
D4["Warehouse directory"] -->|"Read mostly, cleaned first"| OK
OK --> Q["Review queue and caps"]
OK --> APP["Applications"]
How the first six months went
The overlap audit found 3,100 multi-directory people, of whom 140 had employee numbers that disagreed between directories because of typing errors. HR corrected them, and automatic linking then worked for nearly everyone. About 60 cases stayed in the review queue and were resolved by hand in two weeks. Source priority ended the flip-flopping of titles, and the count of attributes changing repeatedly fell from hundreds to a handful in the first month.
In month two, an administrator moved a warehouse organizational unit into a new container, and an import proposed to deactivate 1,900 people. The two percent cap held the run, an alert reached the on-call engineer within minutes, and the scope was corrected before any account was touched. In month four, reconciliation found 210 leavers still enabled in the warehouse directory, which was cleaned and added to the weekly report. By month six, identity tickets about conflicts had fallen from about one hundred a month to about twenty.
Result
Northwind now treats conflicts as a measured, owned process. The most valuable work was not clever technology. It was agreeing who owns each fact, choosing strong keys, cleaning sources, and adding fuses to every bulk action.
A city merging four old phone books into one first agrees which book is trusted for which kind of entry, then corrects the obvious errors, and only then prints. The printing is the easy part.
36Frequently Asked Questions
Short answers to questions that come up often. Okta features, limits, and menu names change over time, and some depend on your plan, so confirm exact details in the current Okta documentation.
What is a directory sync conflict?
It is a disagreement between two sources about the same fact, or a record that does not fit what Okta already holds. Something has to decide which value or identity is kept.
Does the latest change always win?
Not unless you design it that way. Outcomes depend on source priority, mappings, and matching rules. Relying on arrival order is fragile, so explicit priority is safer for important attributes.
Why does an attribute keep changing back?
Usually two sources write it with equal priority, or a stale source restores an old value. Give one source ownership, or lower the priority of the stale one.
How do I avoid merging two different people?
Match on strong keys such as employee number, add a second check, never rely on names alone, and review a sample of proposed matches before enabling automatic linking.
What if one person has accounts in several directories?
Link them to one Okta profile using reliable matching, and decide which directory supplies which attributes. Treat the extra accounts as additional sign-in sources for the same person.
Should blank values overwrite existing ones?
Generally no, unless the source is the owner and blank truly means removal. Treat blanks from non-owners as no opinion.
How do I stop a bad import from locking out thousands?
Preview where possible, cap bulk deactivation per run, change scope in quiet periods, alert on large proposed changes, and keep a rehearsed way to pause imports.
How should I handle groups with the same name in different directories?
Prefix imported groups with the source name, and use rules in Okta to combine audiences where needed.
Is it safe to push groups or attributes back to a directory?
It can be, with narrow write rights, one direction per attribute, and privileged accounts excluded. Without these, loops and unwanted changes become likely.
Who should own employment status?
The HR system, whenever one exists. Directories then follow, with a suspension step and reconciliation to catch leftovers.
How often should I reconcile?
Weekly is a common starting point for large estates, and daily for high-risk checks such as leavers still enabled. Choose a rhythm that matches your risk and capacity.
How do I know if a conflict is a security issue?
Ask whether the attribute or match drives access, whether privileged accounts are involved, and whether a person could have chosen the conflicting value themselves. If yes, treat it as security.
What should I do first in an existing messy estate?
Inventory sources and writers, run an overlap and drift report, fix the highest-risk problems such as leavers and false merges, then write the ownership policy.
Do I need a person reviewing conflicts?
Yes for ambiguous matches and unusual bulk changes. Automation handles the common cases, and humans handle the cases where being wrong is expensive.
Where should I start?
Draw your sources, audit overlaps, decide owners and matching keys, set caps and monitoring, then connect one source at a time with lifecycle actions off.
37Summary and Key Takeaways
Resolving directory sync conflicts at scale is mostly about clear ownership, careful identification, and safe change.
Key Takeaways
- Conflicts are decided by configuration. Source priority, mappings, and matching rules choose the outcome, so make them explicit and written down.
- Give every attribute one owner. HR for business facts, directories for sign-in facts, and gap filling only where no owner exists.
- Identify people by stable keys. Use unique usernames and strong matching keys, and prefer a missed merge over a false merge.
- Add fuses to bulk actions. Previews, caps, quarantine, a kill switch, and a rehearsed way back keep mistakes small.
- Detect before users do. Monitor agents and import counts, and reconcile all sources on a schedule so drift is visible.
- Operate with roles and queues. Source owners, reviewers, and on-call engineers need clear duties and response targets.
- Improve continuously. Measure, fix sources, update the policy, and retire old rules, because conflicts cluster around change.
Okta changes features, limits, and menu names over time, and some capabilities depend on your plan. Use this post to understand the ideas, and confirm exact steps and requirements in your own admin console and the current Okta documentation before building.