Showing results for 
Search instead for 
Did you mean: 
Sign up Log in

How to resolve 403 Forbidden error in my Atlassian Connect add-on for Bitbucket cloud

Mahesh Chandran Korapattu Rama Chandran
I'm New Here
I'm New Here
Those new to the Atlassian Community have posted less than three times. Give them a warm welcome!
May 8, 2023

created an Atlassian connect add-on using the Atlassian Spring Boot Starter. I created the following descriptor (atlassian-connect.json):

  "key": "${addon.key}",
  "baseUrl": "${addon.base-url}",
  "name": "Mahesh Hello World",
  "description": "Mahesh Hello World",
  "authentication": {
    "type": "jwt"
  "lifecycle": {
    "installed": "/installed",
    "uninstalled": "/uninstalled"
  "modules": {
  "webhooks": [
      "event": "pullrequest:created",
      "url": "/bitbucket-hook"
  "webPanel": [
      "url": "/connect-example?repoPath={repo_path}",
      "name": {
        "value": "Example Web Panel"
      "location": "org.bitbucket.repository.overview.informationPanel",
      "key": "example-web-panel"
  "scopes": ["account", "repository:admin", "pullrequest"]

As seen, there is one webhook registered for the pullrequest:created event. The Spring Rest Controller webhook listener is based on this link

As per the above link, docs for atlassian-connect-spring-boot states the following :

 "Provides a Spring Boot starter for building Atlassian Connect add-ons for JIRA (Software, Service Desk and Core) and Confluence."

Apparently this means Bitbucket Cloud is not supported out of the box. So the link provides a solution to create your own JWT tokens based on another link

In addition to classes mentioned in this link, I created my Rest Controller (webhook listener) as follows:

    public void webhook(@AuthenticationPrincipal AtlassianHostUser hostUser, @RequestBody String repository, HttpServletResponse httpServletResponse)
            throws ClientProtocolException, IOException, URISyntaxException, InterruptedException {;
        AccessTokenResponse accessToken = new AccessToken(hostUser.getHost().getSharedSecret(), hostUser.getHost().getClientKey(), "mahesh-hello-world-9").getAccessToken();

        RestTemplate restTemplate = new RestTemplate();
        HttpHeaders headers = new HttpHeaders();
        headers.add("Authorization", "Bearer " + accessToken.getAccess_token());
        HttpEntity<String> branchRequest = new HttpEntity<String>(headers);
        ResponseEntity<String> response ="", HttpMethod.GET, branchRequest, String.class);

        String branchObject = response.getBody();
        JsonObject targetJsonObject = JsonParser.parseString(branchObject).getAsJsonObject().get("target").getAsJsonObject();
        String hash = targetJsonObject.get("hash").getAsString();

        headers = new HttpHeaders();
        accessToken = new AccessToken(hostUser.getHost().getSharedSecret(), hostUser.getHost().getClientKey(), "mahesh-hello-world-9").getAccessToken();
        headers.add("Authorization", "Bearer " + accessToken.getAccess_token());
        headers.add("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36");

        MultiValueMap<String, Object> map= new LinkedMultiValueMap<>();
        map.add("message", "This is a test commit");
        map.add("author", "Mahesh Chandran <>");
        map.add("parents", hash);
        map.add("branch", "master");
        map.add("test.yml", new FileSystemResource("/home/sacumen/Code/atlassian/bitbucket-test-code/test.yml"));

        HttpEntity<MultiValueMap<String, Object>> pushRequest
                = new HttpEntity<>(map, headers);

        response ="", HttpMethod.POST, pushRequest, String.class);;

But I get the following error:

org.springframework.web.client.HttpClientErrorException: 403 Forbidden

I have given repo read/write/admin rights for the OAuth consumer which I created in Bitbucket.

The same endpoints work well and pushes the files successfully from Postman. The only difference I can make out is that in Postman, I use client_credentials with the Client ID and Client Secret corresponding to the OAuth consumer. I don't see this used as far as I can think.

Can someone look into the code and let me know if there is a solution, given this approach.

0 answers

Suggest an answer

Log in or Sign up to answer
Site Admin
AUG Leaders

Atlassian Community Events