> For the complete documentation index, see [llms.txt](https://docs.openiam.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.openiam.com/administration-guide/security/helpdesk-verification.md).

# Verify a help-desk caller

Make a help-desk technician answer questions about the caller before the caller's profile opens, with the fixed question pool, the counts and the audit actions.

## What this is, and when you need it

A technician who is a member of one designated role must answer questions about the caller before the caller's profile opens at all. One system property names that role, and until it is set the feature is entirely off — a technician opens any profile with no verification and no message saying so.

Everything the caller-facing recovery flow needs is on [Configure password recovery and account unlock](/administration-guide/security/password-recovery.md). This page is only the technician-side check.

## At a glance

|                          |                                                                                                                                                                                                                                      |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **You will end up with** | A test operator who, on opening a caller's profile, is redirected to a question screen, must answer correctly, and is blocked with a `403` on any write until they have — with one `HELPDESK_UNLOCK_ATTEMPT` audit event per attempt |
| **Where**                | **Administration → System Configuration**, category `ChallengeResponse`, plus the caller's password policy for the two counts                                                                                                        |
| **You need first**       | A least-privilege test role to nominate as the protected role, one disposable operator identity, and a disposable caller identity with a stored secret word                                                                          |
| **Takes**                | An hour, plus the property sweep wait — `org.openiam.property.value.threadsweep` is `300000` ms                                                                                                                                      |
| **Reversible**           | Yes, immediately — clearing `org.openiam.am.helpdesk.role.id` short-circuits the whole check on the next property sweep                                                                                                              |

{% hint style="danger" %}
**Do not point `org.openiam.am.helpdesk.role.id` at an existing administrator role while testing.** The instant it is set, every member of that role is subject to verification, and the same test decides which help-desk affordances their UI offers. Use a disposable role with one disposable member.
{% endhint %}

## Before you begin

Understand the switch, because both halves of it fail silently. OpenIAM waves the operator straight through — no verification at all — when `org.openiam.am.helpdesk.role.id` is blank **or** the signed-in operator is not a member of the named role. Both conditions must hold before anybody is asked anything, and neither failure produces a message: the operator simply sees the profile.

One consequence changes the order of the steps below. **With the feature off, nobody is ever prompted to set a secret word**: OpenIAM reports every user's secret word as already filled whenever the role property is blank. That is why the caller stores their secret word *before* you set the property, not after.

## Turn on caller verification

{% stepper %}
{% step %}

### Create the protected role and one test operator

**Access Control → Role → Create New Role**, name it `Help desk operators (test)`, and grant it only what a technician needs. Add exactly one disposable operator identity.
{% endstep %}

{% step %}

### Choose the attributes the operator may ask about

**Administration → System Configuration**, category `ChallengeResponse`, set `org.openiam.am.helpdesk.possibly.asked.attributes` to a comma-separated list of `USER_ATTRIBUTE` names the legitimate caller knows and the technician cannot infer from the screen.

Remember that **Email address**, **Birth date**, **Employee ID**, **Middle initial**, **Title** and **Secret word** are added automatically whenever the caller has those values, and are not configurable — see [What the operator is actually asked](#what-the-operator-is-actually-asked). Naming an attribute here makes the pool larger; nothing makes it smaller.
{% endstep %}

{% step %}

### Set the counts on the policy that resolves for the caller

Set `REQUIRED_HELPDESK_QUESTION` (shipped `2`) and `FAIL_ATTEMPTS_HELPDESK` (shipped `3`) on the password policy that resolves for the **caller**, not the operator.

A non-integer or negative value in either field silently disables that check — it becomes zero, which means "ask nothing" — and nothing on screen warns you. An inactive policy is skipped entirely, so confirm the policy's `Active` flag too. The only proof is the positive test in step 6: if the operator is not prompted, one of these is wrong.
{% endstep %}

{% step %}

### Have the caller store a secret word, before the property is set

The caller sets it themselves, on the **Personal Identification Number (PIN)** screen at `/selfservice/secret-word`. Saving it is audited as `SECRET_WORD_SAVED`. It is **write-once by design**: OpenIAM refuses to save a second value over an existing one, and no screen clears it. To change it, the stored value must be cleared first, which means a break-glass update to `USERS.SECRET_WORD` — own that process before you enable the feature.
{% endstep %}

{% step %}

### Point the property at the role, last

Set `org.openiam.am.helpdesk.role.id`. Until this moment the feature is entirely off; the instant it is set, every member of that role is subject to verification. Wait out the property sweep — `org.openiam.property.value.threadsweep` = `300000` ms.
{% endstep %}

{% step %}

### Positive test

Sign in as the operator and open the caller's profile. Expect a redirect to the question screen — that redirect *is* verification firing. Answer correctly. Expect the profile to open, one `HELPDESK_UNLOCK_ATTEMPT` audit event recorded as a success, and `HELPDESK_CONFIRMED_USER_ID` set in the operator's session.
{% endstep %}

{% step %}

### Three negative tests, all of which must fail

1. **Wrong answers**, `FAIL_ATTEMPTS_HELPDESK` + 1 times. Expect `HELPDESK_SECURITY_ANSWERS_ARE_WRONG`, then `HELPDESK_TOO_MANY_FAIL`, and `USERS.SECRET_FAIL_COUNT` above the threshold. Then prove your process for clearing it — nothing in the product clears it automatically, and only a correct answer set or a manual update resets it.
2. **A second caller** without re-verifying. Opening user B's profile with only user A confirmed must re-prompt, because the confirmed user held in the session is compared against the one being opened.
3. **A change before verification.** Reading an unverified caller's profile redirects the operator to the question screen; attempting to *change* anything is refused with `403` outright, with no redirect. Confirm the technician cannot reset a password on an unverified caller.
   {% endstep %}

{% step %}

### Optionally add MFA on top

Set `org.openiam.am.helpdesk.mfa` to `true`. Correct answers then redirect the operator to `<context>/otpSMS` and the OTP goes to the **caller's** channel, not the operator's — so confirm the caller can receive it before enabling.

The audit event records *"Answers for helpdesk security questions were correct, continuing with OTP."* and is only marked successful on the non-MFA path, so with MFA on, expect the `HELPDESK_UNLOCK_ATTEMPT` event to carry that info line rather than a success. Do not build alerting that treats the missing success as a failure.
{% endstep %}
{% endstepper %}

## Verification

| What to check                    | How                                                                                                                                                                                           |
| -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Help desk is armed               | `org.openiam.am.helpdesk.role.id` is non-blank **and** the operator is a member. Either being false disables verification silently                                                            |
| Verification really fires        | Opening the caller's profile redirects the operator to the question screen, and any attempt to change something before answering is refused with `403`                                        |
| Verification is per-caller       | Opening a second caller's profile re-prompts. `HELPDESK_CONFIRMED_USER_ID` in the operator's session is compared against the user being opened                                                |
| Caller lock state                | `SELECT SECRET_FAIL_COUNT, SECRET_WORD IS NOT NULL FROM USERS WHERE USER_ID='<id>'`                                                                                                           |
| Audit records exist              | `HELPDESK_UNLOCK_ATTEMPT` per attempt and `SECRET_WORD_SAVED` when a secret word is stored. See [Audit actions and retention](/administration-guide/reference/audit-actions-and-retention.md) |
| The counts are actually in force | Deliberately answer wrongly `FAIL_ATTEMPTS_HELPDESK` + 1 times and confirm `HELPDESK_TOO_MANY_FAIL`                                                                                           |

## When it goes wrong

| Symptom                                                                                | Cause                                                                                                                                  | Fix                                                                                                              |
| -------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| Help-desk operators see profiles with no questions                                     | `org.openiam.am.helpdesk.role.id` is blank, or the operator is not a member of that role                                               | Both must hold before anyone is asked anything; either being false waves the operator straight through, silently |
| Help-desk verification silently does nothing even with the role set                    | `REQUIRED_HELPDESK_QUESTION` is non-integer or negative — it becomes `0`, which means disabled — or the policy is inactive             | Fix the value; check the policy's `Active` flag                                                                  |
| Help-desk questions ask for data the operator can already see                          | The candidate pool is fixed; adding an attribute widens it and removes nothing                                                         | Populate attributes only the caller knows, and raise `REQUIRED_HELPDESK_QUESTION`                                |
| Help desk prompts but always with the same questions                                   | Only `REQUIRED_HELPDESK_QUESTION` candidates exist for that caller, so no shuffle is possible                                          | Populate more attributes, or add names to `org.openiam.am.helpdesk.possibly.asked.attributes`                    |
| `NOT_ENOUGH_DATA_TO_BUILD_HELPDESK_QUESTIONS`                                          | The caller has none of the candidate values and the attribute property is empty                                                        | Set the attribute list, or require a secret word at first login                                                  |
| `HELPDESK_SECURITY_ANSWERS_ARE_WRONG` and the operator cannot tell which answer failed | Deliberate. Answers are checked all-or-nothing, because telling the operator which answer failed would tell an impostor the same thing | Expected                                                                                                         |
| Caller permanently blocked from help-desk assistance                                   | `SECRET_FAIL_COUNT` exceeded `FAIL_ATTEMPTS_HELPDESK`; nothing resets it but a correct answer set or a manual update                   | Own that process before you enable the feature                                                                   |
| Cannot change a stored secret word                                                     | OpenIAM refuses to re-save a secret word while one exists                                                                              | Clear `USERS.SECRET_WORD` first, as break-glass — it produces no audit record and validates nothing              |
| Nobody is ever asked to set a secret word                                              | With the role property blank, OpenIAM reports every user's secret word as already filled                                               | Store the secret word before setting the property, as in step 4                                                  |
| Help-desk MFA sends the code to the wrong person                                       | By design the OTP goes to the **caller's** channel, not the operator's                                                                 | Confirm the caller can receive it before enabling                                                                |
| A service-desk role cannot see **Reset Password** in SelfService                       | The `RESET_PASSWORD_DIRECT_REPORT` menu item is not entitled to that role, or the operator has no direct reports                       | [Giving a service desk the reset-password action](#giving-a-service-desk-the-reset-password-action)              |
| The property change has no effect yet                                                  | The property sweep is `org.openiam.property.value.threadsweep` = `300000` ms                                                           | Wait it out before concluding anything                                                                           |

## Roll it back

Clear `org.openiam.am.helpdesk.role.id` — a blank value short-circuits the check on the next property sweep, and it is the single change that disarms the feature immediately. Then restore the recorded `REQUIRED_HELPDESK_QUESTION` and `FAIL_ATTEMPTS_HELPDESK` values on the caller's policy and re-test with the disposable identities.

A caller's `SECRET_FAIL_COUNT` is not reset by turning the feature off. Clear it deliberately, through your own documented process.

## What the operator is actually asked

OpenIAM builds the candidate list from the caller's own stored data, and the sources are fixed — you cannot add a question type, only populate more of these:

| Candidate                                                                   | Question ID                   | Present when                                   |
| --------------------------------------------------------------------------- | ----------------------------- | ---------------------------------------------- |
| Each attribute named in `org.openiam.am.helpdesk.possibly.asked.attributes` | `ATTRIBUTE0`, `ATTRIBUTE1`, … | The user has a value for that `USER_ATTRIBUTE` |
| Secret word                                                                 | `USER_SECRET`                 | `USERS.SECRET_WORD` is non-blank               |
| Email address                                                               | `EMAIL`                       | The user has any email address                 |
| Birth date                                                                  | `BIRTHDAY`                    | `BIRTHDATE` is set                             |
| Employee ID                                                                 | `EMPLOYEE_ID`                 | `EMPLOYEE_ID` is non-blank                     |
| Middle initial                                                              | `INITIALS`                    | `MIDDLE_INIT` is non-blank                     |
| Title                                                                       | `TITLE`                       | `TITLE` is non-blank                           |

The property value is split on `,`. If nothing resolves, the request fails with `NOT_ENOUGH_DATA_TO_BUILD_HELPDESK_QUESTIONS`. If more candidates exist than `REQUIRED_HELPDESK_QUESTION`, the list is shuffled and truncated, so the operator gets different questions each time; if fewer exist, the operator gets all of them — a thin profile means a weak check, silently.

**You cannot narrow the pool.** Naming a user attribute in the property makes the pool larger; it does not remove **Employee ID**, **Title**, **Email address** or any other built-in candidate, and no screen does. Where those values are widely known inside your organization, the countermeasures are to populate attributes only the caller could know, so the shuffle has better material to draw from, and to raise `REQUIRED_HELPDESK_QUESTION` so more than one has to be right.

Verification itself is per-caller and held in the operator's session under `HELPDESK_CONFIRMED_USER_ID`. Opening a different user's profile clears it and re-triggers verification. On a read OpenIAM redirects the operator to the question screen; on an attempted change it refuses with `403` instead — so a correctly-configured help desk fails *loudly* on reads and *silently* on writes, and that `403` is what you look for when testing that changes are blocked.

Wrong answers increment `USERS.SECRET_FAIL_COUNT`; exceeding `FAIL_ATTEMPTS_HELPDESK` returns `HELPDESK_TOO_MANY_FAIL`. A single correct set resets the counter to zero.

### The five `ChallengeResponse` properties

| Property                                            | Shipped   | Type                   | Label                                                        |
| --------------------------------------------------- | --------- | ---------------------- | ------------------------------------------------------------ |
| `org.openiam.am.helpdesk.role.id`                   | *(empty)* | Role                   | Help Desk Protected Role                                     |
| `org.openiam.am.helpdesk.mfa`                       | `false`   | Boolean                | Activate Multi-Factor Authentication for helpdesk validation |
| `org.openiam.am.helpdesk.possibly.asked.attributes` | *(empty)* | MultiSelect            | Select validation attributes for helpdesk inquiries          |
| `org.openiam.selfservice.challenge.response.group`  | `GLOBAL`  | ChallengeResponseGroup | Default Security Question Group                              |
| `org.openiam.ui.challenge.answers.secured`          | `true`    | Boolean                | Are Security Question Answers Secured?                       |

## Giving a service desk the reset-password action

The **Reset Password** action under direct reports is a shipped menu item resource, `RESET_PASSWORD_DIRECT_REPORT`, sitting under `VIEW_DIRECT_REPORTS` and entitled to two shipped roles. A service-desk role that cannot see it needs entitling to that menu item — see [Menus](/administration-guide/access/content-providers-and-uri-patterns.md#menus). That does not give it reach: the screen shows the operator their own direct reports, so a desk that is nobody's supervisor sees an empty list.

There is no shipped way to nominate a group that may reset any user's password without verification. OpenIAM has three paths — self-service, a supervisor resetting for a direct report, and a help-desk operator who has answered the caller's questions. A desk needing blanket reach has to be given Webconsole user administration, with the scope that implies, or the resets routed through an approval flow.

## Related

* [Configure password recovery and account unlock](/administration-guide/security/password-recovery.md) — the caller-facing half, and the `FORGET_PSWD` group in full
* [Password and authentication policy parameters](/administration-guide/reference/policy-parameters.md) — `REQUIRED_HELPDESK_QUESTION` and `FAIL_ATTEMPTS_HELPDESK` with their IDs
* [System property reference](/administration-guide/reference/system-properties.md) — the `ChallengeResponse` category

*Applies to OpenIAM 2026.8.1. Last reviewed 7 August 2026.*


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.openiam.com/administration-guide/security/helpdesk-verification.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
