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

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

Password protected URLs 🔗

URLs secured by HTTP Basic Authentication (username and password) are supported. Simply provide a username and password 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)

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".

Validator 🔗

When using a URL, the app will automatically attempt to validate your API definition JSON/YAML against https://online.swagger.io/validator.

If your URL is not publicly accessible to the validator, an "Error" badge will appear at the bottom right. You can disable auto-validation by setting the Online Validator URL to "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.

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)

Service Repository Type Example URL
GitHub ✅ Public repo
https://raw.githubusercontent.com/{owner}/{repo}/{branch}/{file path}
GitLab ✅ Public repo
https://gitlab.com/{project}/{repo}/raw/{branch}/{file path}
Bitbucket (Cloud) ✅ Public repo
https://bitbucket.org/{project}/{repo}/raw/{commit ref}/{file path}
GitHub ⚠️ Private repo
https://api.github.com/repos/{owner}/{repo}/contents/{file path}
GitLab ⚠️ Private repo
https://gitlab.com/api/v4/projects/{project id}/repository/files/{file path}/raw?ref={branch}&private_token={private token}
Bitbucket (Cloud) ⚠️ Private repo
https://api.bitbucket.org/2.0/repositories/{project}/{repo}/src/master/{file path}
Bitbucket (Server) ❌ Public repo
https://{server name}/mvc/projects/{project}/repos/{repo}/raw/{file path}
Bitbucket (Server) ❌ Private repo
https://{server name}/rest/api/1.0/projects/{project}/repos/{repo}/raw/{file path}
Public repositories 🔗

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

Static site hosting 🔗

Another option may be to use GitHub Pages or Bitbucket static site hosting.

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/.

(Note: By default, 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:

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.

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.

Possible workaround 🔗

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.heroku.app
	
  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? 🔗

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.

Effective as of May 18, 2016.