Private Space content search via OAuth 2.0 (3LO)

I created an OAuth 2.0 (3LO) app to do a search with the /wiki/rest/api/content/search API for all the spaces I have.

I searched with the AcceesToken I got, but it only worked on public spaces, not private spaces.

So I tried searching for spaces via the /api/v2/spaces API, which also only searched for public spaces.

Then I checked ACT_AS_USER, but realized that this only works in the Atlassian Connect app.

Finally, I included the API token that can be issued per user as the header of the /wiki/rest/api/content/search call, and the search worked for all spaces.

Is there any way to search for private spaces with an AccessToken from an OAuth 2.0 (3LO) app?

Welcome to the Atlassian developer community @BrantHwang,

Yes. OAuth 2.0 access tokens do work with this endpoint. Perhaps something went wrong in your token exchange or in making the request using the token. Can you post more about the request that you made with the access token?

1 Like

OAuth Request Code

    @GetMapping("/oauth/atlassian")
    public RedirectView authorize(HttpSession session) {
        String state = UUID.randomUUID().toString();

        StringBuilder scope = new StringBuilder();

        scope.append("read:me");
        scope.append(" read:confluence-content.all");
        scope.append(" read:confluence-content.summary");
        scope.append(" read:confluence-space.summary");
        scope.append(" read:confluence-props");
        scope.append(" search:confluence");
        scope.append(" read:jira-work");

        String authorizationUrl = UriComponentsBuilder.fromHttpUrl("https://auth.atlassian.com/authorize")
                        .queryParam("audience", "api.atlassian.com")
                        .queryParam("client_id", clientId)
                        .queryParam("scope",scope.toString())
                        .queryParam("response_type", "code")
                        .queryParam("prompt", "consent")
                        .queryParam("redirect_uri", redirectUri)
                        .queryParam("state", state)
                        .build().toString();

        session.setAttribute("oauth_state", state);

        return new RedirectView(authorizationUrl);
    }

OAuth Callback Code

   @GetMapping("/oauth/atlassian/callback")
    public String callback(
            @RequestParam("code") String code,
            @RequestParam String state,
            HttpSession session,
            RedirectAttributes redirectAttributes,
            HttpServletResponse response) {

        String savedState = (String) session.getAttribute("oauth_state");

        if (!state.equals(savedState)) {
            redirectAttributes.addFlashAttribute("message", "Invalid Atlassian OAuth state parameter");
        }

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

        String requestBody = "grant_type=authorization_code" +
                "&client_id=" + clientId +
                "&client_secret=" + clientSecret +
                "&code=" + code +
                "&redirect_uri=" + redirectUri;

        HttpEntity<String> request = new HttpEntity<>(requestBody, headers);
        ResponseEntity<TokenResponse> responseEntity = restTemplate.postForEntity(tokenUrl, request, TokenResponse.class);

        String accessToken = Objects.requireNonNull(responseEntity.getBody()).getAccessToken();
        return accessToken;
}

In this way, I successfully obtained the AccessToken after OAuth authentication.

However, when I call the Search API like below with that AccessToken, I can’t retrieve data from Private Space.

    @Override
    public List<SearchResult> search(SearchRequest request) {
        if (!StringUtils.hasText(request.getAtlassianToken())) {
            return Collections.emptyList();
        }

        List<SearchResult> results = new ArrayList<>();

        try {
            String cql = UrlEscapers.urlFragmentEscaper().escape("text~\"" + request.getQuery() + "\"");
            String url = confluenceUrl + "/rest/api/content/search?type=page&limit=500&cql=" + cql;

            HttpHeaders headers = new HttpHeaders();
            //headers.setBearerAuth(request.getAtlassianToken());
            headers.setBasicAuth(request.getEmail(), request.getAtlassianToken());

            HttpEntity<?> entity = new HttpEntity<>(headers);

            return searchRecursively(new URI(url), entity, results);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

        return results;
    }

I’ve tried BearerAuth, I’ve tried Basic Auth, and it doesn’t work.

However, as I already mentioned in the original question, I can search with the API token issued by the user (User → Settings → Security → API Token), everything is searched normally, even Private Space.

Thank you so much.

@BrantHwang,

When you use OAuth 2.0, the URL construction is different. The base URL looks like: https://api.atlassian.com/ex/confluence/{cloudid}

For more details see:
https://developer.atlassian.com/cloud/oauth/getting-started/making-calls-to-api/#using-the-cloud-id

Thank you so much!!! It works!!