atlassian-oauth2
Version:
Atlassian Connect OAuth2 library
113 lines (98 loc) • 5.16 kB
JavaScript
var request = require('request'),
RSVP = require('rsvp'),
jwt = require('atlassian-jwt');
var EXPIRE_IN_SECONDS = 60,
AUTHORIZATION_SERVER_URL = "https://oauth-2-authorization-server.services.atlassian.com",
JWT_CLAIM_PREFIX = "urn:atlassian:connect",
GRANT_TYPE = "urn:ietf:params:oauth:grant-type:jwt-bearer",
SCOPE_SEPARATOR = ' ';
/**
* Creates a JWT claimset for authenticating the add-on to the OAuth2 service.
*
* This is the generic base used to generate payloads for both accountId and userKey.
*
* @param {String} hostBaseUrl - The fully qualified instance name, for example `https://instance.atlassian.net`
* @param {String} oauthClientId - The OAuth client id which corresponds to the `hostBaseUrl` which was provided to the add-on during installation
* @param {String} subClaim - The sub claim to use when making the request to the server.
* @param {String=} audience - The authorization server to use (only intended to be changed for internal Atlassian use).
* @returns {Object} A claimset to be encoded and sent with the token request
*/
function _createGenericAssertionPayload (hostBaseUrl, oauthClientId, subClaim, audience) {
var now = Math.floor(Date.now() / 1000);
var exp = now + EXPIRE_IN_SECONDS;
return {
"iss": JWT_CLAIM_PREFIX + ":clientid:" + oauthClientId,
"tnt": hostBaseUrl,
"sub": subClaim,
"aud": audience || AUTHORIZATION_SERVER_URL,
"iat": now,
"exp": exp
}
}
function _createUserKeyAssertionPayload(hostBaseUrl, oauthClientId, userKey, audience) {
var subClaim = JWT_CLAIM_PREFIX + ":userkey:" + userKey;
return _createGenericAssertionPayload(hostBaseUrl, oauthClientId, subClaim, audience);
}
function _createAAIDAssertingPayload(hostBaseUrl, oauthClientId, aAID, audience) {
var subClaim = JWT_CLAIM_PREFIX + ":useraccountid:" + aAID;
return _createGenericAssertionPayload(hostBaseUrl, oauthClientId, subClaim, audience);
}
/**
* Retrieves an OAuth 2 access token for a given user and instance by creating a JWT token
* signed by the add-on's shared secret.
*
* @param {Object} opts - A hash defining the parameters of the access token request
* @param {String} opts.hostBaseUrl - The fully qualified instance name, for example `https://instance.atlassian.net`
* @param {String} opts.oauthClientId - The OAuth client id which corresponds to the `hostBaseUrl` which was provided to the add-on during installation
* @param {String} opts.sharedSecret - The shared secret which corresponds to the `hostBaseUrl` which was provided to the add-on during installation
* @param {String} opts.userAccountId - The account id of the user to retrieve an access token for
* @param {String} opts.userKey - The user key (not username) of the user to retrieve an access token for (if userAccountId not provided)
* @param {String} opts.scopes - An array of scopes to request for when creating the access token
* @param {String=} opts.authorizationServerBaseUrl - An alternative authorization server to use (intended for internal use by Atlassian only)
* @param {String=} opts.authorizationPath - An alternative authorization path to use (intended for internal use by Atlassian only)
* @returns {Promise.<Object, Error>} A promise that returns the access token if resolved, or an error if rejected
*/
function getAccessToken (opts) {
opts = opts || {};
return new RSVP.Promise(function (resolve, reject) {
var jwtClaims;
if(opts.userAccountId) {
jwtClaims = _createAAIDAssertingPayload(opts.hostBaseUrl, opts.oauthClientId, opts.userAccountId, opts.authorizationServerBaseUrl);
} else if(opts.userKey) {
jwtClaims = _createUserKeyAssertionPayload(opts.hostBaseUrl, opts.oauthClientId, opts.userKey, opts.authorizationServerBaseUrl);
} else {
reject('No user identifier (userKey or userAccountId) provided');
}
var assertion = jwt.encode(jwtClaims, opts.sharedSecret);
var formData = {
grant_type: GRANT_TYPE,
assertion: assertion
};
if (opts.scopes) {
formData.scope = opts.scopes.join(SCOPE_SEPARATOR).toUpperCase()
}
request({
method: 'POST',
url: (opts.authorizationServerBaseUrl || AUTHORIZATION_SERVER_URL) + (opts.authorizationPath || '/oauth2/token'),
form: formData,
json: true,
headers: {
"accept": "application/json"
}
}, function(err, response, body) {
if (err) {
reject(err);
} else if (response.statusCode < 200 || response.statusCode > 299) {
reject(body);
} else {
resolve(body);
}
});
});
}
module.exports = {
_createUserKeyAssertionPayload: _createUserKeyAssertionPayload,
_createAAIDAssertingPayload: _createAAIDAssertingPayload,
_createAssertionPayload: _createUserKeyAssertionPayload, // Don't change the default export in case something else is using it
getAccessToken: getAccessToken
};