Forge `devops:securityInfoProvider`: 401 "scope does not match" when linking a workspace (`linkedWorkspaces/bulk`)

Hi,

I’m building a Forge app with the devops:securityInfoProvider module to show security data in Jira’s Security tab. It has the read:security:jira and write:security:jira scopes.

My understanding is that this works in two steps. First the app links its workspace by calling POST /rest/security/1.0/linkedWorkspaces/bulk, so that Jira knows the workspace exists. After that, Jira calls the app back (fetchWorkspaces, searchContainers) so an admin can connect a container to a project. The vulnerabilities themselves are pushed separately with POST /rest/security/1.0/bulk.

The problem is that linking always fails. Using the app’s own token (api.asApp().requestJira), I get:

  • POST /rest/security/1.0/bulk (push vulnerabilities) → 400 “At least one vulnerability is required”. So the API is reachable and the scope is accepted (I just sent an empty list).
  • GET /rest/security/1.0/linkedWorkspaces401 “Unauthorized; scope does not match”
  • POST /rest/security/1.0/linkedWorkspaces/bulk401 “Unauthorized; scope does not match”

So the same token is fine on /bulk but rejected on every linkedWorkspaces endpoint.

I checked the two things that usually cause “scope does not match”, and both are fine:

  • The scope is there. I decoded the token the app actually sends, and it contains write:security:jira and read:security:jira.
  • The URL is correct. It’s exactly /rest/security/1.0/linkedWorkspaces/bulk, no trailing slash and no encoding.

The API documentation also explicitly states that “these APIs are available to Forge apps with the devops:securityInfoProvider module”, and lists no Forge-specific restriction on the linkedWorkspaces endpoints, so as far as I can tell this should work from Forge.

Because linking fails, Jira never learns about my workspace, so it never calls my callbacks (fetchWorkspaces / searchContainers). The provider just stays on “Set up” in the Security tab and never moves forward.

I put a minimal app that reproduces this here: EnduIf/forge-securityinfoprovider-401-repro

My questions:

  1. Is this a known limitation while the devops:securityInfoProvider module is in preview?
  2. If a Forge app can’t call linkedWorkspaces, how is it supposed to link its workspace so Jira starts calling it back? Is there another way I’m missing?

Thanks!

Does your Forge app declare a Connect app key? This is a current limitation for creating linked workspaces. See https://jira.atlassian.com/browse/ECO-1602 (Note that you don’t need any Connect modules - just the key.)

Edit: I just checked your manifest. Yes this is probably the issue.

See also Tutorial on Building a Jira Security Info Provider app in Forge

Thanks @bkelley,adding the Connect app key (no Connect modules, just the
key) fixed the linking exactly as you and ECO-1602 describe. linkedWorkspaces
now succeeds and Jira calls back to fetchWorkspaces/searchContainers.

That fix has created a follow-on problem, though: I now can’t publish the app.
Because the manifest carries app.connect, the publishing step rejects it as a
Connect-containing app.

So I’m stuck between the two: the securityInfoProvider feature requires the
Connect key per ECO-1602, but the Marketplace path treats any app with a
Connect key as non-Forge and blocks the listing. The ECO-1602 workaround and
the “new apps may not contain Connect modules” listing rule seem to be in
direct conflict for this module.

How should a brand-new (no legacy Connect app) securityInfoProvider app be
published?