Source: sessions/ccg-session.ts

  1. /**
  2. * @fileoverview An Anonymous Box API Session.
  3. */
  4. // ------------------------------------------------------------------------------
  5. // Requirements
  6. // ------------------------------------------------------------------------------
  7. import { Promise } from 'bluebird';
  8. // ------------------------------------------------------------------------------
  9. // Typedefs
  10. // ------------------------------------------------------------------------------
  11. type Config = any /* FIXME */;
  12. type TokenManager = any /* FIXME */;
  13. type TokenInfo = any /* FIXME */;
  14. type TokenRequestOptions = any /* FIXME */;
  15. // ------------------------------------------------------------------------------
  16. // Private
  17. // ------------------------------------------------------------------------------
  18. // ------------------------------------------------------------------------------
  19. // Public
  20. // ------------------------------------------------------------------------------
  21. /**
  22. * The Client Credentials Grant Box API Session.
  23. *
  24. * The Client Credentials Grant API Session holds a Client Credentials accessToken, which it
  25. * returns to the client so that it may make calls on behalf of service account or specified users.
  26. *
  27. * Tokens will be refreshed in the background if a request is made within the
  28. * "stale buffer" (defaults to 10 minutes before the token is set to expire).
  29. * If the token is also expired, all incoming requests will be held until a fresh token
  30. * is retrieved.
  31. *
  32. * @param {Config} config The SDK configuration options
  33. * @param {TokenManager} tokenManager The TokenManager
  34. * @constructor
  35. */
  36. class CCGSession {
  37. _config: Config;
  38. _tokenManager: TokenManager;
  39. _tokenInfo: TokenInfo;
  40. _refreshPromise: Promise<any> | null;
  41. constructor(config: Config, tokenManager: TokenManager) {
  42. this._config = config;
  43. this._tokenManager = tokenManager;
  44. // The TokenInfo object for this anonymous session
  45. this._tokenInfo = null;
  46. this._refreshPromise = null;
  47. }
  48. /**
  49. * Initiate a refresh of the access tokens. New tokens should be passed to the
  50. * caller, and then cached for later use.
  51. *
  52. * @param {?TokenRequestOptions} [options] - Sets optional behavior for the token grant
  53. * @returns {Promise<string>} Promise resolving to the access token
  54. * @private
  55. */
  56. _refreshAccessToken(options?: TokenRequestOptions) {
  57. // If tokens aren't already being refreshed, start the refresh
  58. if (!this._refreshPromise) {
  59. // Initiate a refresh
  60. this._refreshPromise = this._tokenManager
  61. .getTokensClientCredentialsGrant(options)
  62. .then((tokenInfo: TokenInfo) => {
  63. // Set new token info and propagate the new access token
  64. this._tokenInfo = tokenInfo;
  65. return tokenInfo.accessToken;
  66. })
  67. .finally(() => {
  68. // Refresh complete, clear promise
  69. this._refreshPromise = null;
  70. });
  71. }
  72. return this._refreshPromise as Promise<any>;
  73. }
  74. /**
  75. * Produces a valid, anonymous access token.
  76. * Performs a refresh before returning if the current token is expired. If the current
  77. * token is considered stale but still valid, return the current token but initiate a
  78. * new refresh in the background.
  79. *
  80. * @param {TokenRequestOptions} [options] - Sets optional behavior for the token grant
  81. * @returns {Promise<string>} Promise resolving to the access token
  82. */
  83. getAccessToken(options?: TokenRequestOptions) {
  84. // If the current token is no longer fresh, get a new token. All incoming
  85. // requests will be held until a fresh token is retrieved.
  86. var expirationBuffer = this._config.expiredBufferMS;
  87. if (
  88. !this._tokenInfo ||
  89. !this._tokenManager.isAccessTokenValid(this._tokenInfo, expirationBuffer)
  90. ) {
  91. return this._refreshAccessToken(options);
  92. }
  93. // Your token is not currently stale! Return the current access token.
  94. return Promise.resolve(this._tokenInfo.accessToken);
  95. }
  96. /**
  97. * Revokes the anonymous token used by this anonymous session, and clears the saved tokenInfo.
  98. *
  99. * @param {TokenRequestOptions} [options] - Sets optional behavior for the token grant
  100. * @returns {Promise} Promise resolving if the revoke succeeds
  101. */
  102. revokeTokens(options?: TokenRequestOptions) {
  103. // The current anonymous token is revoked (but a new one will be created automatically as needed).
  104. var tokenInfo = this._tokenInfo || {},
  105. accessToken = tokenInfo.accessToken;
  106. this._tokenInfo = null;
  107. return this._tokenManager.revokeTokens(accessToken, options);
  108. }
  109. /**
  110. * Exchange the client access token for one with lower scope
  111. *
  112. * @param {string|string[]} scopes The scope(s) requested for the new token
  113. * @param {string} [resource] The absolute URL of an API resource to scope the new token to
  114. * @param {Object} [options] - Optional parameters
  115. * @param {TokenRequestOptions} [options.tokenRequestOptions] - Sets optional behavior for the token grant
  116. * @returns {void}
  117. */
  118. exchangeToken(
  119. scopes: string | string[],
  120. resource?: string,
  121. options?: {
  122. tokenRequestOptions?: TokenRequestOptions;
  123. }
  124. ) {
  125. // We need to get the access token, in case it hasn't been generated yet
  126. return this.getAccessToken(options).then((accessToken) =>
  127. this._tokenManager.exchangeToken(accessToken, scopes, resource, options)
  128. );
  129. }
  130. }
  131. /**
  132. * @module box-node-sdk/lib/sessions/ccg-session
  133. * @see {@Link CCGSession}
  134. */
  135. export = CCGSession;