UNPKG

atlassian-oauth2

Version:

Atlassian Connect OAuth2 library

113 lines (98 loc) 5.16 kB
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 };