UNPKG

box-node-sdk

Version:

Official SDK for Box Platform APIs

254 lines (253 loc) 10.6 kB
import { PostOAuth2TokenGrantTypeField } from '../schemas/postOAuth2Token'; import { PostOAuth2TokenSubjectTokenTypeField } from '../schemas/postOAuth2Token'; import { AccessToken } from '../schemas/accessToken'; import { PostOAuth2TokenBoxSubjectTypeField } from '../schemas/postOAuth2Token'; import { Authentication } from '../networking/auth'; import { NetworkSession } from '../networking/network'; import { TokenStorage } from './tokenStorage'; import { InMemoryTokenStorage } from './tokenStorage'; import { AuthorizationManager } from '../managers/authorization'; import { BoxSdkError } from './errors'; import { PostOAuth2Token } from '../schemas/postOAuth2Token'; import { PostOAuth2Revoke } from '../schemas/postOAuth2Revoke'; export class CcgConfig { /** * Box API key used for identifying the application the user is authenticating with */ readonly clientId!: string; /** * Box API secret used for making auth requests. */ readonly clientSecret!: string; /** * The ID of the Box Developer Edition enterprise. */ readonly enterpriseId?: string; /** * The user id to authenticate. This value is not required. But if it is provided, then the user will be auto-authenticated at the time of the first API call. */ readonly userId?: string; /** * Object responsible for storing token. If no custom implementation provided,the token will be stored in memory. */ readonly tokenStorage: TokenStorage = new InMemoryTokenStorage({}); constructor( fields: Omit<CcgConfig, 'tokenStorage'> & Partial<Pick<CcgConfig, 'tokenStorage'>>, ) { if (fields.clientId !== undefined) { this.clientId = fields.clientId; } if (fields.clientSecret !== undefined) { this.clientSecret = fields.clientSecret; } if (fields.enterpriseId !== undefined) { this.enterpriseId = fields.enterpriseId; } if (fields.userId !== undefined) { this.userId = fields.userId; } if (fields.tokenStorage !== undefined) { this.tokenStorage = fields.tokenStorage; } } } export interface CcgConfigInput { /** * Box API key used for identifying the application the user is authenticating with */ readonly clientId: string; /** * Box API secret used for making auth requests. */ readonly clientSecret: string; /** * The ID of the Box Developer Edition enterprise. */ readonly enterpriseId?: string; /** * The user id to authenticate. This value is not required. But if it is provided, then the user will be auto-authenticated at the time of the first API call. */ readonly userId?: string; /** * Object responsible for storing token. If no custom implementation provided,the token will be stored in memory. */ readonly tokenStorage?: TokenStorage; } export class BoxCcgAuth implements Authentication { /** * Configuration object of Client Credentials Grant auth. */ readonly config!: CcgConfig; /** * An object responsible for storing token. If no custom implementation provided, the token will be stored in memory. */ readonly tokenStorage: TokenStorage; /** * The ID of the user or enterprise to authenticate as. If not provided, defaults to the enterprise ID if set, otherwise defaults to the user ID. */ readonly subjectId?: string; /** * The type of the subject ID provided. Must be either 'user' or 'enterprise'. */ readonly subjectType?: PostOAuth2TokenBoxSubjectTypeField; constructor( fields: Omit< BoxCcgAuth, | 'tokenStorage' | 'subjectId' | 'subjectType' | 'refreshToken' | 'retrieveToken' | 'retrieveAuthorizationHeader' | 'withUserSubject' | 'withEnterpriseSubject' | 'downscopeToken' | 'revokeToken' >, ) { if (fields.config !== undefined) { this.config = fields.config; } this.tokenStorage = this.config.tokenStorage; this.subjectId = !(this.config.userId == void 0) ? this.config.userId : this.config.enterpriseId; this.subjectType = !(this.config.userId == void 0) ? ('user' as PostOAuth2TokenBoxSubjectTypeField) : ('enterprise' as PostOAuth2TokenBoxSubjectTypeField); } /** * Get a new access token using CCG auth * @param {NetworkSession} networkSession An object to keep network session state * @returns {Promise<AccessToken>} */ async refreshToken(networkSession?: NetworkSession): Promise<AccessToken> { const authManager: AuthorizationManager = new AuthorizationManager({ networkSession: !(networkSession == void 0) ? networkSession! : new NetworkSession({}), }); const token: AccessToken = await authManager.requestAccessToken({ grantType: 'client_credentials' as PostOAuth2TokenGrantTypeField, clientId: this.config.clientId, clientSecret: this.config.clientSecret, boxSubjectType: this.subjectType, boxSubjectId: this.subjectId, } satisfies PostOAuth2Token); await this.tokenStorage.store(token); return token; } /** * Return a current token or get a new one when not available. * @param {NetworkSession} networkSession An object to keep network session state * @returns {Promise<AccessToken>} */ async retrieveToken(networkSession?: NetworkSession): Promise<AccessToken> { const oldToken: undefined | AccessToken = await this.tokenStorage.get(); if (oldToken == void 0) { const newToken: AccessToken = await this.refreshToken(networkSession); return newToken; } return oldToken!; } /** * @param {NetworkSession} networkSession * @returns {Promise<string>} */ async retrieveAuthorizationHeader( networkSession?: NetworkSession, ): Promise<string> { const token: AccessToken = await this.retrieveToken(networkSession); return ''.concat('Bearer ', token.accessToken!) as string; } /** * Create a new BoxCCGAuth instance that uses the provided user ID as the subject ID. * May be one of this application's created App User. Depending on the configured User Access Level, may also be any other App User or Managed User in the enterprise. * <https://developer.box.com/en/guides/applications/> * <https://developer.box.com/en/guides/authentication/select/> * @param {string} userId The id of the user to authenticate * @param {TokenStorage} tokenStorage Object responsible for storing token in newly created BoxCCGAuth. If no custom implementation provided, the token will be stored in memory. * @returns {BoxCcgAuth} */ withUserSubject( userId: string, tokenStorage: TokenStorage = new InMemoryTokenStorage({}), ): BoxCcgAuth { const newConfig: CcgConfig = new CcgConfig({ clientId: this.config.clientId, clientSecret: this.config.clientSecret, enterpriseId: this.config.enterpriseId, userId: userId, tokenStorage: tokenStorage, }); return new BoxCcgAuth({ config: newConfig }); } /** * Create a new BoxCCGAuth instance that uses the provided enterprise ID as the subject ID. * @param {string} enterpriseId The id of the enterprise to authenticate * @param {TokenStorage} tokenStorage Object responsible for storing token in newly created BoxCCGAuth. If no custom implementation provided, the token will be stored in memory. * @returns {BoxCcgAuth} */ withEnterpriseSubject( enterpriseId: string, tokenStorage: TokenStorage = new InMemoryTokenStorage({}), ): BoxCcgAuth { const newConfig: CcgConfig = new CcgConfig({ clientId: this.config.clientId, clientSecret: this.config.clientSecret, enterpriseId: enterpriseId, userId: void 0, tokenStorage: tokenStorage, }); return new BoxCcgAuth({ config: newConfig }); } /** * Downscope access token to the provided scopes. Returning a new access token with the provided scopes, with the original access token unchanged. * @param {readonly string[]} scopes The scope(s) to apply to the resulting token. * @param {string} resource The file or folder to get a downscoped token for. If None and shared_link None, the resulting token will not be scoped down to just a single item. The resource should be a full URL to an item, e.g. https://api.box.com/2.0/files/123456. * @param {string} sharedLink The shared link to get a downscoped token for. If None and item None, the resulting token will not be scoped down to just a single item. * @param {NetworkSession} networkSession An object to keep network session state * @returns {Promise<AccessToken>} */ async downscopeToken( scopes: readonly string[], resource?: string, sharedLink?: string, networkSession?: NetworkSession, ): Promise<AccessToken> { const token: undefined | AccessToken = await this.retrieveToken(networkSession); if (token == void 0) { throw new BoxSdkError({ message: 'No access token is available. Make an API call to retrieve a token before calling this method.', }); } const authManager: AuthorizationManager = new AuthorizationManager({ networkSession: !(networkSession == void 0) ? networkSession! : new NetworkSession({}), }); const downscopedToken: AccessToken = await authManager.requestAccessToken({ grantType: 'urn:ietf:params:oauth:grant-type:token-exchange' as PostOAuth2TokenGrantTypeField, subjectToken: token!.accessToken, subjectTokenType: 'urn:ietf:params:oauth:token-type:access_token' as PostOAuth2TokenSubjectTokenTypeField, scope: scopes.join(' ') as string, resource: resource, boxSharedLink: sharedLink, } satisfies PostOAuth2Token); return downscopedToken; } /** * Revoke the current access token and remove it from token storage. * @param {NetworkSession} networkSession An object to keep network session state * @returns {Promise<undefined>} */ async revokeToken(networkSession?: NetworkSession): Promise<undefined> { const oldToken: undefined | AccessToken = await this.tokenStorage.get(); if (oldToken == void 0) { return void 0; } const authManager: AuthorizationManager = new AuthorizationManager({ networkSession: !(networkSession == void 0) ? networkSession! : new NetworkSession({}), }); await authManager.revokeAccessToken({ clientId: this.config.clientId, clientSecret: this.config.clientSecret, token: oldToken!.accessToken, } satisfies PostOAuth2Revoke); await this.tokenStorage.clear(); return void 0; } }