Documentation

OAuth 2.0 - JWT Bearer token authorization grant type

Connect supports the JWT Bearer token authorization grant type for OAuth 2.0, allowing add-ons with the appropriate scope (ACT_AS_USER) to access resources and perform actions in JIRA and Confluence on behalf of users.

Connect OAuth 2.0 JWT Bearer token authorization grant flow

The flow for accessing a user's resources works as follows:

  1. Install hook fires with the oauthClientId and the shared secret.
  2. Add-on creates a JWT assertion with the shared secret and the oauthClientId, and then POSTs it to the authorization server.
  3. Authorization server returns an OAuth 2.0 access token.
  4. Add-on uses the access token to perform actions as a user.

Requesting an OAuth 2.0 access token

For an add-on to make requests on a user's behalf, you need an OAuth 2.0 access token.

The OAuth 2.0 JWT Bearer token flow involves the following general steps to retrieve a token:

  1. Admin installs the add-on, which initiates the installation handshake with the oauthClientId and the shared secret in the request body:
  {
      "key": "addon-key",
      "oauthClientId": "your-oauth2-client-id",
  }
  1. The add-on creates an assertion, a JWT that is HMAC-SHA256 signed with the shared secret the add-on received during the installation handshake, and adds the following claims in the payload:
Attribute Type Description
iss String the issuer of the claim. For example: urn:atlassian:connect:clientid:{oauthClientId}
sub String The subject of the token. For example: urn:atlassian:connect:userkey:{userkey of the user to run services on behalf of} NOTE: The userkey is different from the username. For example, to get the userkey for username alex use the REST endpoint /rest/api/2/user?username=alex in JIRA or /rest/api/user?username=alex in Confluence.
tnt String The instance the add-on is installed on. For example: https://{your-instance}.atlassian.net
aud String The Atlassian authentication server: https://auth.atlassian.io
iat Long Issue time in seconds since the epoch UTC.
exp Long Expiry time in seconds since the epoch UTC. Must be no later that 60 seconds in the future.
  1. The assertion and the payload are POSTed to the authorization server: https://auth.atlassian.io/oauth2/token

    Example request:

    POST /oauth2/token HTTP/1.1
    Host: auth.atlassian.io
    Accept: application/json
    Content-Length: {length of the request body}
    Content-Type: application/x-www-form-urlencoded
    grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&scope=READ+WRITE&assertion={your-signed-jwt}
    
    • grant_type is the literal url-encoded urn:ietf:params:oauth:grant-type:jwt-bearer.
    • assertion is set to the assertion created in the previous step.
    • scope is space-delimited and capitalized. Tokens are only granted for scopes your add-on is authorized for. If you omit the scope, the request is interpreted as a request for an access token with all the scopes your add-on has been granted.
  2. The token endpoint validates the signatures and issues an access token. Example response:

    HTTP/1.1 200 OK
    Status: 200 OK
    Content-Type: application/json; charset=utf-8
    ...
    {
       "access_token": "{your access token}",
       "expires_in": {15 minutes expressed as seconds},
       "token_type": "Bearer"
    }
    

Using an access token in a request

Set the Authorization header to Bearer {your access token} and make your request:

Example request:

GET /rest/api/latest/myself HTTP/1.1
Host: {your-registered-instance}.atlassian.net
Accept: application/json
Authorization: Bearer {your-access-token}

Example response:

HTTP/1.1 200 OK
Status: 200 OK
Content-Type: application/json; charset=utf-8
...
{
  "key": "{key-of-user-to-run-services-on-behalf-of}",
  "displayName": "{impersonated user's display name}",
  ...
}

The example is from a JIRA REST resource—not every resource has these properties.

Rate limiting

Add-ons are allowed 500 access token requests every 5 minutes for each host product the add-on is installed on. If you exceed the limit, the server returns a 409 status response and a JSON formatted error message.

Current usage limits are returned in the following headers for every server response:

  • X-RateLimit-Limit - The number of requests allowed for 5 minutes (set to 500).
  • X-RateLimit-Remaining - The number of requests remaining before you hit the limit.
  • X-RateLimit-Reset - Unix timestamp indicating when the limit will update. When this occurs, the X-RateLimit-Remaining count will reset to 500 and the X-RateLimit-Reset time will reset to 5 minutes in the future.

Example response:

HTTP/1.1 200 OK
X-RateLimit-Limit: 500
X-RateLimit-Remaining: 499
X-RateLimit-Reset: 1366037820
...

Token expiration

The OAuth 2.0 access token expiry time is included in the access token response (it is currently 15 minutes but this may change in future). Write your code to anticipate the possibility that a granted token might no longer work. We suggest tracking expiration time and requesting a new token before it expires, rather than handling a token expiration error. Refresh tokens at the 30-60 second mark.

Code Examples

Runnable Java and node.js sample code demonstrating the flow is available from this repository.

Atlassian Connect for Express.js support

Atlassian Conenct for Express.js provides the .asUser method to make requests on users' behalf.

var httpClient = addon.httpClient(req);
httpClient.asUser('userkey-of-user-to-act-as').get('/rest/api/latest/myself', function (err, res, body) {
  ...
})

Atlassian Connect for Spring Boot support

Atlassian Connect for Spring Boot supports making requests as a user on behalf via the 'AtlassianHostRestClients' component. See the readme for more information.

@Autowired
private AtlassianHostRestClients atlassianHostRestClients;

public void doSomething() {
    atlassianHostRestClients.authenticatedAsHostActor().getForObject("/rest/api/example", Void.class);