> 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/identities/add-a-selfservice-user-page.md).

# Add a custom user page to SelfService

Give one audience a purpose-built SelfService page that edits a slice of the user record, on its own URI pattern, visible only to the role you entitle.

## What this is, and when you need it

Binding a template to an existing pattern changes an existing screen. Sometimes you want a *new* screen — one purpose-built page editing a slice of the user record, reachable from its own SelfService menu item and visible only to the people who should use it. A mailbox-settings page is the canonical example: a handful of mail attributes, nothing else, for the staff who administer mailboxes.

## At a glance

|                          |                                                                                                                      |
| ------------------------ | -------------------------------------------------------------------------------------------------------------------- |
| **You will end up with** | A SelfService menu item opening a page that renders only the fields you chose, visible only to holders of one role   |
| **Where**                | **Access Control → Content Providers**, **Access Control → Menus → SelfService**, **Administration → Page Template** |
| **You need first**       | A keyword, the field list, and the role that should see it                                                           |
| **Takes**                | 30 to 45 minutes                                                                                                     |
| **Reversible**           | Yes — remove the menu item or unbind the pattern. No user record changes                                             |

## Before you begin

* **A keyword** for the page, used identically in two places: the pattern is named `user-template-<keyword>` and the menu URL carries `entityEditUrlExtension=<keyword>`.
* **The narrow field list.** The point of a dedicated page is that it is *not* the full user form.
* **The role that should see it.** A menu is a resource, so it is entitled like any other.

## Create the page

The mechanism is a naming convention. SelfService will render a user page for any URI pattern named `user-template-<keyword>`, and the menu item you create passes the keyword to it.

{% stepper %}
{% step %}

### Choose the keyword and create the URI pattern

Pick a keyword that identifies the page — `mailbox` — and create a URI pattern for `user-template-mailbox` under the SelfService content provider (**Access Control → Content Providers**, the provider's **URI Patterns** section).

<figure><img src="https://2965242200-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F0uHWHRgcad6P03ehqgmX%2Fuploads%2Fgit-blob-3314c90e9c369706099e99627fcbae3dc1c1f718%2Fuser-cust-page-2.png?alt=media" alt="The URI pattern edit form for /selfservice/user-template-mailbox on the home content provider, with Is Authorization Disabled ticked"><figcaption></figcaption></figure>

The pattern must follow `user-template-<keyword>` exactly. The keyword is yours; the prefix is not negotiable.
{% endstep %}

{% step %}

### Add the SelfService menu item that points at it

Go to **Access Control → Menus → SelfService**, select the parent menu you want the item to sit under, and add a child node to it. Give the new node a display name — *Mailbox settings* — and set its URL to the SelfService user screen with the keyword attached:

{% code overflow="wrap" %}

```
/selfservice/?frameURL=/selfservice/users?entityEditUrlExtension=mailbox
```

{% endcode %}

<figure><img src="https://2965242200-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F0uHWHRgcad6P03ehqgmX%2Fuploads%2Fgit-blob-67369f25ba4420aeca959f285b99207c96b55dab%2Fuser-cust-page-1.png?alt=media" alt="The SELFSERVICE menu tree with the new Manage users mailbox node selected under Access Management, and its Menu Metadata panel showing the URL and Display Name"><figcaption></figcaption></figure>

`entityEditUrlExtension` carries the keyword through to the user screen, which is what makes the request resolve against the `user-template-mailbox` pattern rather than the default SelfService user pattern. The value here and the suffix of the pattern in step 1 must be the same string. If they disagree, the menu opens a path your template is not bound to, and you get whatever *is* bound to it.
{% endstep %}

{% step %}

### Create the page template and bind it to the pattern

Create a new template of type **User Page Template**, add exactly the fields this page should edit, and bind it to the `user-template-mailbox` pattern in its **URI Patterns** section.

<figure><img src="https://2965242200-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F0uHWHRgcad6P03ehqgmX%2Fuploads%2Fgit-blob-7000b0be7bb42a15a53e912f01af02eb6c128dbb%2Fuser-cust-page-3.png?alt=media" alt="The Edit Page Template screen for the Mailbox template, bound in its URI Patterns section to /selfservice/user-template-mailbox on the home content provider"><figcaption></figcaption></figure>

Because the pattern is new, there is nothing to unbind — this is the one case where the trap above cannot bite you. Keep the field list narrow: the point of a dedicated page is that it is not the full user form.
{% endstep %}

{% step %}

### Restrict the menu item by role

A menu is a resource, so it is entitled like any other. Associate the new menu node with a role, and entitle only the people who administer mailboxes with that role.

{% hint style="warning" %}
**Clear `Is public` on the node, or the role does nothing.** A public menu item is shown to everyone regardless of entitlement, so a node left public with a role attached is still visible to every SelfService user — and nothing on the screen contradicts you. The same flag is how an item is taken out of a portal: clear it on **Edit profile** or **Change password** and they stop appearing.

**Then save twice.** The dialog's **Save** does not persist anything — it updates the tree held in the browser and closes the dialog. Only **Save Menu Tree** sends it to the server, so leaving without that second save loses the change silently, which reads as the entitlement not working.
{% endhint %}

<figure><img src="https://2965242200-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F0uHWHRgcad6P03ehqgmX%2Fuploads%2Fgit-blob-88731f4d69aeaf851f810bd7b2d59e35ba6943fd%2Fuser-cust-page-4.png?alt=media" alt="SelfService with the Access Management menu open, showing the new Manage users mailbox item at the top of the list"><figcaption></figcaption></figure>

<figure><img src="https://2965242200-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F0uHWHRgcad6P03ehqgmX%2Fuploads%2Fgit-blob-d735bac73552067fb2201e98a6f31968dafc68d6%2Fuser-cust-page-5.png?alt=media" alt="The SelfService Edit User page rendered by the Mailbox template, showing the custom Mailbox type, Restricted, APCL and License fields"><figcaption></figcaption></figure>

This step is optional only in the sense that the product does not force it. Leave it out and every SelfService user sees the menu item — and the template behind it decides what they may edit, which is a thin place to put your access control. Restrict the menu, then rely on the template for presentation.
{% endstep %}
{% endstepper %}

## Verification

| What to check               | Where                                                                                              |
| --------------------------- | -------------------------------------------------------------------------------------------------- |
| The pattern exists          | The content provider's **URI Patterns** section lists `user-template-<keyword>`                    |
| The template is bound to it | The pattern is listed in your template's own **URI Patterns** section, and in no other template's  |
| The template saved          | An audit event described "Save page template"; reopen it and read the field list back              |
| The menu item resolves      | Open it in SelfService as a user who holds the role: the page renders your fields and nothing else |
| The restriction holds       | Sign in as a user *without* the role and confirm the menu item is absent                           |

## When it goes wrong

| Symptom                                                                                            | Cause to check                                                                                                                                            | Fix                                                                            |
| -------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
| The page renders the default user fields                                                           | The `entityEditUrlExtension` value and the pattern's suffix are not the same string, so the request resolved against the default SelfService user pattern | Make the keyword identical in both places                                      |
| The page renders nothing at all                                                                    | No template is bound to `user-template-<keyword>`. Nothing is thrown; only a debug line `Page template was null.` is logged                               | Bind your template to that pattern                                             |
| `This page is linked to more than one template. Each page must be linked to exactly one template.` | Two templates resolve for the pattern — `PAGE_MULTIPLIED_TEMPLATE`                                                                                        | Unbind the pattern from all but one template                                   |
| Some fields on the page are missing for some users                                                 | A field that is neither public nor entitled to the requester is silently absent from the rendered form                                                    | Mark the field public, or entitle its resource to the people who use this page |
| Every SelfService user can see the menu item                                                       | The menu node was never associated with a role                                                                                                            | Associate it, and entitle only the intended population                         |
| The menu item is there but the page 404s                                                           | The pattern was created under the wrong content provider                                                                                                  | Create it under the SelfService content provider                               |

## What renders on the page, and what does not

Adding a field to the template is necessary and not sufficient. OpenIAM keeps an element on the rendered form only when the field is **public**, or the request is an administrative one, or the requester is entitled to the field's own resource. A field that is neither public nor entitled is added to the template successfully and then silently absent from the screen — which looks identical, to the person filling in the form, to a field you forgot. On a SelfService page edited by ordinary users, that is the check to make first when a field you configured is not there.

Read-only is a separate control, and there are two of them. Clear the field's **Editable** flag when it should always be read-only on this page; write a conditional rule with the `disable` action — which the screen labels **Deactivate** — when it depends on another field's value. The rule editor does not render at all until the template holds at least one field besides the one being edited. Both are documented in [Page template reference](/administration-guide/identities/page-templates-and-custom-fields/page-template-reference.md#conditional-rules).

Restricting the menu item restricts *reaching* the page. It does not restrict what a determined user can submit: the template decides which fields the save carries, and server-side validation is the custom validator, not the menu entitlement.

## Why this, and not two templates on one pattern

This is also the only way to make a form vary by *who is using it*. Binding two templates to one URI pattern and entitling them to different roles does not produce a role-dependent form: the entitlement check happens *after* resolution, on the single template the lookup returned, so entitlement is a gate rather than a selector. Pass it and you get that template; fail it and you get **no** template. Two templates on one pattern is an ambiguous lookup that fails for everybody, with `PAGE_MULTIPLIED_TEMPLATE`. The one axis on which a pattern may legitimately carry more than one template is the **metadata type**, which describes the object being edited and not the person editing it — see [How the product picks the template for a request](/administration-guide/identities/page-templates-and-custom-fields.md#how-the-product-picks-the-template-for-a-request).

## Roll it back

Remove the menu node, or unbind the pattern from the template. Both are immediate and neither changes any user record. The pattern and the template can be left in place, unbound, if you expect to need them again.

## Related

* [Build a page template](/administration-guide/identities/page-templates-and-custom-fields.md) — the template itself, and how a request picks one
* [Page template reference](/administration-guide/identities/page-templates-and-custom-fields/page-template-reference.md) — the field types, the rule actions and the Groovy contracts
* [Content providers and URI patterns](/administration-guide/access/content-providers-and-uri-patterns.md) — creating the pattern
* [Scope a delegated administrator](/administration-guide/identities/delegated-administration.md) — the other half of restricting who may edit whom

*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/identities/add-a-selfservice-user-page.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.
