O'Hara Group

Open API Documentation for Confluence

Service status

Contents

Description

A Confluence macro for generating beautiful documentation from an Open API (a.k.a. Swagger)-compliant JSON or YAML definition.

Based on the open source Swagger UI, this app is a macro wrapper enabling API documentation to be easily embedded into a Confluence page.

Usage 🔗

  1. Start by creating/editing a page in Confluence
  2. Insert the macro either
  3. Specify your Open API-compliant JSON or YAML definition either

How it Works 🔗

The diagram below describes how the Cloud version of the app works.

  1. Confluence page requested
  2. Macro assets loaded
  3. (Optional) JSON/YAML URL fetched
  4. API documentation is generated
Data Center and Server

The Data Center and Server versions operate identically to the Cloud version, except there is no separate app server.

Apps for Data Center/Server run within the same process as the Confluence server itself.

Notes 🔗

URL vs JSON/YAML in the macro body 🔗

If both a URL and JSON/YAML in the macro body are present, the URL will be used and the macro body ignored

Authenticated URLs 🔗

URLs secured by HTTP Basic Authentication (username and password) or personal access tokens are supported. Simply provide a username and password or access token for the URL in the macro configuration dialog.

IMPORTANT SECURITY INFORMATION REGARDING URL CREDENTIALS!

URLs are fetched from the client browser. In other words, it is the user's browser (not the Confluence server) that makes the network request to the server hosting your JSON/YAML definition.

Therefore credentials that required to access the URL need to be made available to the browser.

Values entered in the username/password fields in the macro configuration dialog are stored with the Confluence page content and will be visible in the HTML source of the page.

Our recommendation is to use credentials that grant only the minimum access necessary. In most cases, you should limit the credentials to read-only access to the URL.

The underlying assumption is that if a user is permitted to view the rendered API documentation in Confluence, there is no risk in the same user having read access to the source JSON/YAML definition; so you should bear this in mind when deciding how/where to host your API definition files.

Configuring CORS 🔗

When using a URL for your JSON/YAML definition, it is important to note that the URL will be fetched by the client browser (not the Confluence Server) once the page is rendered.

This means that the URL must be accessible to the end-users browser, and the server hosting the URL must respond with the appropriate CORS headers, e.g.

Access-Control-Allow-Origin: *

(NOTE: For password protected URLs, the "*" wildcard cannot be used for the header value. You must specify an origin, as shown below)

or

Access-Control-Allow-Origin: https://{your Confluence server}
(for Confluence Server/Data Center)

Access-Control-Allow-Origin: https://confluence-open-api.herokuapp.com
(for Confluence Cloud)

Troubleshooting CORS

If you are experiencing CORS related issues, see our comprehensive Guide to troubleshooting CORS.

More information on CORS 🔗

CORS (Cross Origin Resource Sharing) is a browser security mechanism that allows Javascript on a page served from one "origin" (the app) to access a resource hosted at a different origin (the server hosting your JSON/YAML definition).

Without CORS, browsers prevent Javascript from making such cross-origin requests.

With CORS, the origin hosting the resource being accessed (your JSON/YAML definition) must return a special HTTP header indicating that the origin making the request (the app) is permitted access.

To help understand, lets walk through an example of a page served by Confluence Cloud that includes the Open API Documentation for Confluence macro, configured to display API documention for the URL https://petstore.swagger.io/v2/swagger.json

In simple cases (such as when no credentials are needed to access the URL), the way it works is as follows:

When Confluence renders the page, the Open API Documentation for Confluence macro runs inside an IFRAME, e.g.

	<iframe src="https://confluence-open-api.herokuapp.com">
		[macro runs inside here]
	</iframe>
		

Javascript running inside this IFRAME makes the following HTTP request to fetch the URL:

	GET /v2/swagger.json HTTP/1.1
	Host: petstore.swagger.io
	Origin: https://confluence-open-api.herokuapp.com
		

The server hosting the URL responds with:

	HTTP/1.1 200 OK
	Access-Control-Allow-Origin: *
	Content-Type: application/json

	[JSON data here]
		

The browser checks the 'Access-Control-Allow-Origin' header in the response to see if the origin is permitted.

In this case, a value of "*" indicates that any origin is permitted, so the browser makes the JSON response available to the Javascript that initiated the request.

(If the origin was not permitted, the browser would instead throw an error and the Javascript would be prevented from accessing the JSON response.)

In cases where credentials are required to access the resource, a process known as "preflight" must first occur. This involves the browser first sending an 'OPTIONS' request to the resource server:

	OPTIONS /v2/swagger.json HTTP/1.1
	Host: petstore.swagger.io
	Origin: https://confluence-open-api.herokuapp.com
	Access-Control-Request-Method: GET
	Access-Control-Request-Headers: Authorization
		

The server hosting the URL responds with:

	HTTP/1.1 200 OK
	Access-Control-Allow-Origin: https://confluence-open-api.herokuapp.com
	Access-Control-Allow-Methods: GET, POST, OPTIONS
	Access-Control-Allow-Headers: Authorization
		

The browser checks the 'Access-Control-Allow-*' headers to make sure it is permitted to make the request, and if so the browser then proceeds with the actual 'GET' request to fetch the resource.

For Confluence Server/Data Center, the app does not run in an IFRAME, so substitute 'https://confluence-open-api.herokuapp.com' in the above examples with the URL of your Confluence server.

Mixed Content Errors 🔗

When using the 'Try It Out!' feature to test your API, watch for mixed content issues if your Confluence page is served over https:// and the API host in your JSON or YAML definition is http:// (or vice versa).

Some browsers (e.g. Chrome) will allow Open API to attempt the API request, but block it from reaching the network. 'Try It Out!' will display the request URL and request headers as if the request was sent, but the response headers will show

{"error": "no response from server"}

Other browsers (e.g. Firefox) block Open API from attempting the request at all. 'Try It Out!' will not show anything (so it appears like nothing happens when you click the button).

In either case, check the browser console for errors such as

Mixed Content: The page at 'https://{your cloud instance}.atlassian.net' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://your.api.endpoint'. This request has been blocked; the content must be served over HTTPS.

or

Blocked loading mixed active content "http://your.api.endpoint"

Try it Out! 🔗

The Try it Out! feature can be restricted to specific HTTP methods, or disabled entirely by specifying a value of "none".

Supported Java vendors (Server/Data Center version) 🔗

The app has been verified to support the following Java vendors:

Migrating between Server, Data Center and Cloud versions 🔗

Versions of Open API Documentation for Confluence are available for all Atlassian Confluence platforms (Server, Data Center and Cloud).

The features available in the app are the same, regardless of which platform you use.

Additionally, because data used by the macro is stored within the page content itself, migrating between platforms (e.g. moving from Server to Cloud, from Server to Data Center, or from Cloud back to self-hosted/on-premise) in most cases requires no additional steps.

For example, pages moved to the Cloud using the Confluence Cloud Migration Assistant should display the same as they did in your Server or Data Center instance, or vice-versa.

Confluence page attachments

One exception to the above is when a URL specified in the macro points to a Confluence page attachment (e.g. you have uploaded your JSON/YAML spec as a page attachment, and pointed the macro to the attachment's URL).

During migration between platforms, attachment URLs will likely change, and currently the migration process does not automatically remap the macro to point to the new attachment URL.

After the migration completes, the macro will still be pointing at the attachment in your original (source) Confluence instance.

Our team is investigating options to detect instances of the macro that specify page attachment URLs, and automatically remap these URLs during the migration process.

Until such time, any instances of the macro that uses a page attachment URL will need to be manually updated to the new attachment URL once the migration has completed.

The only changes that may be required are as follows:

Limitations 🔗

OAuth2 flows 🔗

If your API uses OAuth 2.0, the Open API specification defines the following flows that can be specified in your API definition:

However, Swagger UI (and therefore the The Try it Out! feature in Open API Documentation for Confluence) currently only supports implicit.

Export to PDF/Word 🔗

The API documentation is generated dynamically in the browser using Javascript.

For this reason, it is not possible to include API documentation when exporting with Export to PDF or Export to Word, as these static export formats are generated on the Confluence server.

Previews (limitation applies to Cloud version only) 🔗

API documentation cannot be displayed when the page is in preview mode, and will only display once the page has been saved

JSON/YAML definitions in git repositories 🔗

A question we are frequently asked is: Can I host my JSON/YAML definitions in a git repository? (e.g. GitHub, Bitbucket, GitLab)

📢 Public repositories 🔗

If your git repository is public, in either GitHub, Bitbucket Cloud or GitLab you can simply browse to the defintion file in your repository and click the "Raw" button for the URL to use.

Service Example URL
GitHub
https://raw.githubusercontent.com/{owner}/{repo}/{branch}/{file path}
GitLab
https://gitlab.com/{project}/{repo}/raw/{branch}/{file path}
Bitbucket (Cloud)
https://bitbucket.org/{project}/{repo}/raw/{commit ref}/{file path}
Bitbucket (Server) 🛑
https://{server name}/mvc/projects/{project}/repos/{repo}/raw/{file path}
Azure DevOps ⚠️
https://dev.azure.com/{org}/{project}/_apis/git/repositories/{repo}/items?$format=octetStream&api-version=6.0&path={file path}

🛑 Bitbucket Server is known to have issues. Some customers have had success using a URL format as shown above (note the "/mvc" in the URL); however this may only work for certain older versions of Bitbucket Server.

⚠️ For public Azure DevOps repositories, you need to construct an API URL with the path to the file as shown above.

🌟 Static site hosting 🔗

Another option is to use the static site hosting offered by your Git provider.

For example, in Bitbucket you can create a repository (either public or private) named {your account}.bitbucket.io, and any files in that repository will be publicly accessible at https://{your account}.bitbucket.io/.

Service Example URL
GitHub Pages
https://{owner}.github.io/{repo}/
GitLab Pages
https://{your account or group}.gitlab.io/{project}/
Bitbucket static site hosting ⚠️
https://{your account}.bitbucket.io/{repo}/

⚠️ Files served from a Bitbucket static site have 15 minute cache expiry; so pushing new updates to your files may not be immediately visible.

🔐 Private repositories 🔗

If your repository is private, some additional steps are required to provide the necessary credentials.

Service Credentials Example URL
GitHub
  1. Create a personal access token
  2. Enter the token in the GitHub Access Token field in the macro configuration dialog
https://api.github.com/repos/{owner}/{repo}/contents/{file path}
GitLab
  1. Create a personal access token that has API scope
  2. Enter the token in the GitLab Access Token field in the macro config dialog
https://gitlab.com/api/v4/projects/{project id}/repository/files/{file path}
Bitbucket (Cloud) ⚠️
  1. Create a username/password that has read access to the repository
  2. Enter these values into the Username and Password fields in the macro configuration dialog
https://api.bitbucket.org/2.0/repositories/{project}/{repo}/src/master/{file path}
Bitbucket (Server) 🛑 Not supported, see note below
https://{server name}/rest/api/1.0/projects/{project}/repos/{repo}/raw/{file path}
Azure DevOps
  1. Create a personal access token
  2. Enter the token in the Password field in the macro configuration dialog, and leave the Username field empty
https://dev.azure.com/{org}/{project}/_apis/git/repositories/{repo}/items?$format=octetStream&api-version=6.0&path={file path}

⚠️ If you use Bitbucket two-factor verification, you will need to create an app password with read access, and enter this into the Password field in the macro configuration dialog instead of the user password..

🛑 BitBucket Server does support password protected URLs, and files hosted in private Bitbucket repositories can be accessed with a username/password, however Bitbucket currently doesn't return the correct CORS headers for a pre-flight OPTIONS request.


IMPORTANT SECURITY INFORMATION REGARDING GIT ACCESS TOKENS!

URLs are fetched from the client browser. In other words, it is the user's browser (not the Confluence server) that makes the network request to the server hosting your JSON/YAML definition.

Therefore credentials that required to access the URL need to be made available to the browser.

Access tokens supplied either as part of the URL, or in the GitHub Access Token field in the macro configuration dialog are stored with the Confluence page content and will be visible in the HTML source of the page.

Our recommendations for using access tokens are:

The underlying assumption is that if a user is permitted to view the rendered API documentation in Confluence, there is no risk in the same user having read access to the source JSON/YAML definition; so you should bear this in mind when deciding how/where to host your API definition files.

Possible workaround for Bitbucket Server 🔗

If you are experiencing issue relating to CORS, one possible workaround is to set up a "proxy" in front of Bitbucket that injects the correct CORS headers. This can be any standard web server or reverse proxy such as nginx or Apache, or a small node.js/express application as shown in the example below.

Example: Nginx reverse proxy 🔗
location / {
  # If your JSON/YAML URL does not require any authentication, you can use a wildcard:
  #   Access-Control-Allow-Origin: *
  #
  # Otherwise, for Confluence Server/Data Centre:
  #   Access-Control-Allow-Origin: https://{your Confluence server}
  #
  # For Confluence Cloud:
  #   Access-Control-Allow-Origin: https://confluence-open-api.herokuapp.com
	
  add_header 'Access-Control-Allow-Origin' '*';
  add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
	
  # If your JSON/YAML URL requires authentication, be sure to include the Authorization header
  #   Access-Contol-Allow-Headers: Authorization,DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type
	
  add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
	
  if ($request_method = 'OPTIONS') {
    # Tell client that this pre-flight info is valid for 20 days
		
    add_header 'Access-Control-Max-Age' 1728000;
    add_header 'Content-Type' 'text/plain; charset=utf-8';
    add_header 'Content-Length' 0;

    return 204;
  }
}	
		
Example: node.js/express proxy 🔗

The proxy responds to OPTIONS requests from the browser with the correct CORS headers; and to GET requests by passing them through to your Git server.

const fs = require("fs");
const request = require("request");
const https = require("https");
const express = require("express");
const app = express();
			
/*
 * If your JSON/YAML URL does not require any authentication, you can use a wildcard:
 *   allowOrigin = "*";
 *
 * Otherwise, for Confluence Server/Data Centre:
 *   allowOrigin = "https://{your Confluence server}"
 *
 * For Confluence Cloud:
 *   allowOrigin = "https://confluence-open-api.herokuapp.com"
 */
const allowOrigin = "https://confluence-open-api.herokuapp.com";
const allowMethods = "GET, POST, OPTIONS";
const allowHeaders = "Authorization, DNT, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type"

/*
 * Enter the name of your Bitbucket (or other Git) host here 
 * e.g. targetHost = "https://bitbucket.example.com"
 */
const targetHost = "http://{your Bitbucket server}"
	
/* Handles OPTIONS requests by returning the correct CORS headers */
app.options("/*", (_, res) => {
  try {
    res.setHeader("Access-Control-Allow-Origin", allowOrigin);
    res.setHeader("Access-Control-Allow-Methods", allowMethods);
    res.setHeader("Access-Control-Allow-Headers", allowHeaders);
    res.setHeader("Access-Control-Max-Age", 1728000);
    res.setHeader("Content-Type", "text/plain; charset=utf-8");
    res.setHeader("Content-Length", 0);
    res.status(204).send();
  } catch (e) {
    res.status(500).send(JSON.stringify(e));
  }
};
			
/*
 * Handles GET requests by passing them through to the target host
 * e.g. GET https://proxy.example.com/rest/api/1.0/projects/{project}/repos/{repo}/raw/{file path}
 * would be forwarded to GET https://bitbucket.example.com/rest/api/1.0/projects/{project}/repos/{repo}/raw/{file path}
 */
app.get("/*", (req, res) => {
  "use strict";

  try {
    const opts = {
      method: req.method,
      baseUrl: targetHost,
      url: req.originalUrl,
      headers: {
        authorization: req.headers.authorization
      }
    };

    console.log(`Proxying ${opts.method} request through to ${opts.baseUrl}${opts.url}`);

    request(opts).on("response", res => {
      res.headers["Access-Control-Allow-Origin"] = allowOrigin;
      res.headers["Access-Control-Allow-Methods"] = allowMethods;
      res.headers["Access-Control-Allow-Headers"] = allowHeaders;
    }).pipe(res);
  } catch (e) {
    console.log(e);
    res.status(500).send(JSON.stringify(e));
  }
}; 

/*
 * Place the key.pem & cert.pem files for your SSL/TLS certificate into the same directory as this file.
 * NOTE: Do not use a self-signed certificate, as it will not be trusted by your users browser
 * Use a certificate issued by a certificate authority that matches the domain of your proxy server 
 */
https.createServer({
  key: fs.readFileSync("key.pem"),
  cert: fs.readFileSync("cert.pem")
}, app).listen(process.env.PORT || 5000);			
		

Still having trouble? 🔗

Troubleshooting CORS

If you are experiencing CORS related issues, see our comprehensive Guide to troubleshooting CORS.

If your API documentation isn't displaying correctly, below is a list of known issues that may be the cause.

Update to the latest app version 🔗

We regularly publish updates to the app that include the latest Swagger UI version, new features and bug fixes.

If you are experiencing issues, one of the first things you should check is whether there is a newer version of the app available for your Confluence version.

Your Confluence administrator can check for updates via the Manage Apps page.

Check for errors in the browser console 🔗

A good tip to help diagnose the problem is to look in your browser's console for any errors. Some errors are caused by the browser itself or a conflict with other apps, and the only place these errors show is in the console.

To access the browser console, use the appropriate shortcut for your OS / browser:

On Windows 🔗
On Mac 🔗

HTTP vs HTTPS issues 🔗

If your Confluence page is served over https:// but you are using a http:// URL in the macro to load your Open API definition, some browsers (e.g. Chrome) will refuse to load the URL and you will simply see Failed to load spec.. In the console, you will see a message such as:

Mixed Content: The page at 'https://your.confluence.instance' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://your.apidefinition.url'. This request has been blocked; the content must be served over HTTPS.

or

Blocked loading mixed active content "http://your.apidefinition.url"

In this case, you will need to have your Open API JSON/YAML definition hosted on a https:// URL.

Security & Privacy Statement 🔗

Open API Documentation for Confluence is a paid app for Atlassian Confluence Server & Data Center (on premise installation) and Atlassian Confluence Cloud (cloud hosted).

Server & Data Center Version 🔗

The server version is implemented as a Java JAR, using the Atlassian SDK.

When installed, the app runs entirely within the Confluence server process.

Neither the app provider or any other party is able to view the content of your Confluence pages.

Cloud Version 🔗

The cloud version runs on the Heroku cloud platform. Heroku's physical infrastructure is hosted and managed within Amazon's secure data centers and utilizes the Amazon Web Service (AWS) technology. The Amazon servers are located in Northern Virginia in the United States.

Status information about the Heroku cloud platform can be found here.

Both Heroku and Amazon have published a security statement you can find here:

Encryption 🔗

The app runs on Heroku's Common Runtime, under the URL https://confluence-open-api.herokuapp.com.

All communication between the Confluence Cloud servers and the Open API Documentation for Confluence servers is encrypted using TLS.

Heroku's Common Runtime supports TLS version 1.0, 1.1 and 1.2.

Transported content 🔗

No page content or personally identifiable end-user information is transported between the Confluence Cloud servers and the Open API Documentation for Confluence servers.

When a page containing the Open API Documentation for Confluence macro is rendered, Confluence sends a HTTPS request to the app servers. This request contains only a JSON Web Token (JWT) that identifies 'context' information including:

This context information is not stored, logged or used for any other purpose than what this app requires.

Neither the app provider or any other party is able to view any content of your Confluence pages or users.

If an instance of the macro is configured to source an API definition from an authenticated URL, the password or Git access token is passed to the app servers to be encrypted, and the encrypted value is returned to the Confluence Cloud servers for storage with the page content. The credentials passed to the app servers for encryption are not stored, logged or used for any other purpose.

Confluence administrators can optionally configure the app to restrict where JSON/YAML API definitions used by the macro are allowed to be sourced from.

The app configuration settings are stored in a secure database managed by the app provider. The settings, which do not include any personally identifiable information, only contain:

Effective as of May 25, 2023.