Ask a simple question of any Jira Service Management site that has been running for a year: who can reach this portal, and how? There is no screen that answers it. External customers get added desk by desk, organizations get granted and their memberships drift, agents land on the Service Desk Team role directly or through groups nobody re-checks, and deactivated accounts stay on that role long after the person left. Portal-access visibility is a long-running ask on the JSM issue tracker (JSDCLOUD) and a recurring "who has access to our portal?" thread on Atlassian Community, and it matters most exactly when an access review or customer-data audit lands on your desk.
Why JSM cannot tell you this out of the box
- Access facts live in different places. Customer lists are per desk, organization memberships live in a separate screen, and agent access hides inside project roles and groups. No single view joins them.
- Group-granted agent access is invisible from the project. An agent on the Service Desk Team role via a group inherits access whenever the group changes, and group membership changes outside the project, where nobody auditing the desk is looking.
- Nothing is diffed over time. Even if you assemble the picture once, JSM keeps no record of what changed since, so every review starts from zero.
- Stale grants accumulate silently. Deactivated accounts stay on customer lists and roles, and organization grants can sit on a desk with zero members left in them.
The DIY approach: walk every desk through the REST API
Everything you need is in the JSM and Jira REST APIs, spread across several endpoints that you have to join yourself, per desk:
- Enumerate service desks with
GET /rest/servicedeskapi/servicedesk(paged withstartandlimit). - For each desk, list customers with direct portal access via
GET .../servicedesk/{id}/customer(an experimental endpoint, so it needs theX-ExperimentalApi: opt-inheader). - List the desk's organization grants via
GET .../servicedesk/{id}/organization, then roll up each organization's members viaGET /rest/servicedeskapi/organization/{id}/user. This is where the zero-member org grants show up. - Read the project's roles via
GET /rest/api/3/project/{key}/role, follow the Service Desk Team role URL to its actors, and note whether each grant is a direct user or a group. - Resolve every account's active flag via
GET /rest/api/3/user?accountId=to catch deactivated accounts still holding access.
The catches: the Service Desk Team role name is localized per project language, so an English-only match silently loses agent data on non-English sites; the public API does not expose a portal's open-signup setting, so "open to anyone with the link" cannot be detected directly; and a one-off script gives you a snapshot, not a record. To see drift you have to persist each run and diff it against the last, per desk, forever.
A ready-made option: Portal Governance for JSM
Portal Governance for JSM is that pattern packaged. It scans every service desk daily and on demand, builds the per-desk access matrix (customers, organization grants with membership rollups, and agent grants classified direct vs group), flags exposure (deactivated agents, group-granted access, empty organization grants, portals with zero request types), diffs each scan against the previous one so you see exactly what changed, and exports the whole matrix as audit-ready CSV. An opt-in cleanup can then remove deactivated accounts from customer lists and organizations, always as a dry-run preview first, behind an explicit confirmation, with each account re-verified as still deactivated immediately before removal. Cleanup removes portal access only: it does not deactivate accounts and does not free license seats, and removal is recoverable. Outside that opt-in cleanup, the app is read-only.
Key facts
- Native "who can reach this portal" view: none in JSM; the facts are split across customer lists, organization screens, and project roles.
- Agent access: lives on the Service Desk Team role, granted direct or via groups whose membership changes outside the project.
- DIY route: join five REST endpoints per desk, resolve active flags, and persist snapshots yourself to see drift.
- API gaps: the customer endpoint is experimental, and the portal open-signup setting is not exposed via the public API.
- Durable fix: a daily scan that builds the access matrix, flags exposure, diffs runs, and exports CSV evidence for access reviews.
Related reading: set an external identity to expire instead of letting it linger.
Written by the team at Katabarwa Labs. We build small, single-purpose Azure tools that run entirely inside your own tenant. Questions: abaho@llmgraph.ai.