How to list a user's organizations

In general: what is the recommended way for a GitHub App to list all of the organizations of a user who has installed the App – or a user who is in an org that has the App installed (via Marketplace)?

Details:

https://developer.github.com/v3/apps/permissions/#metadata-permissions says that all Apps have read-only access to users/:username/orgs, so that’s what I’m trying.

I have two questions:

1- I’m getting a Bad Credentials error

I’m using JWT authentication with my App Id/Key and I’m using the same function as I use for operations such as requesting an installation token or interacting with the /marketplace-listing API. And these other calls do work, so I’m very confident the code is correct.

Is this endpoint not meant to be requested by an App using JWT?

2- If it does work, can I expect to see app-granted, but not public, organizations?

It makes sense for non-App User Agents to only be able to see public organizations on this endpoint, as documented – but for Apps, it would make sense to see all organizations that the App is authorized to see. So I’m wondering (ahead of time, if we fix (1) I can just test), if that’s the case or not.

Here’s a small repro script:

#!/bin/sh
set -e

# Restyled.io-development
app_id=5355
app_key=$HOME/downloads/restyled-io-development.2019-03-21.private-key.pem

jwt=$(
  ruby -r jwt -r openssl <<EOM
    private_pem = File.read("$app_key")
    private_key = OpenSSL::PKey::RSA.new(private_pem)
    payload = {
      iat: Time.now.to_i,
      exp: Time.now.to_i + (10 * 60),
      iss: $app_id,
    }
    puts JWT.encode(payload, private_key, "RS256")
EOM
)

###
### Getting an installation id for the restyled-io org works:
###
curl --silent -X POST \
  -H "Authorization: Bearer $jwt" \
  -H "Accept: application/vnd.github.machine-man-preview+json" \
  "https://api.github.com/installations/58920/access_tokens"

###
### Getting marketplace_listings (stubbed) works:
###
curl --silent \
  -H "Authorization: Bearer $jwt" \
  -H "Accept: application/vnd.github.machine-man-preview+json" \
  "https://api.github.com/marketplace_listing/stubbed/plans"

###
### Getting my own orgs doesn't work -> Bad Credentials
###
curl --silent \
  -H "Authorization: Bearer $jwt" \
  -H "Accept: application/vnd.github.machine-man-preview+json" \
  "https://api.github.com/users/pbrisbin/orgs"

# No auth at all works, but returns only public orgs (as expected)
curl --silent \
  -H "Accept: application/vnd.github.machine-man-preview+json" \
  "https://api.github.com/users/pbrisbin/orgs"

So my next approach was to ask for orgs/:org/members for each Org as they synchronize from the Marketplace, store it on my side, then I can look up user->orgs later with my own data.

Again, the #metadata-permissions documentation says Apps have access to this. I believe it’s reasonable that --if an App is installed in the Org-- listing its members (including non-public) should be totally fine. But again, I get Bad Credentials:

curl --silent \
  -H "Authorization: Bearer $jwt" \
  -H "Accept: application/vnd.github.machine-man-preview+json" \
  "https://api.github.com/orgs/restyled-io/members"

What is going on here? Is it really just impossible to find non-public members of orgs for which an App is installed?