UNPKG

ltijs

Version:

Easily turn your web application into a LTI 1.3 Learning Tool.

84 lines • 3.94 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.AccessTokenManager = void 0; const validation_1 = require("#utils/validation/validation"); const random_1 = require("#utils/random/random"); const jwt_1 = require("#utils/crypto/jwt"); const jwt_constants_1 = require("#utils/crypto/jwt.constants"); const access_token_manager_schemas_1 = require("#services/access-token-manager/access-token-manager.schemas"); const platform_keys_1 = require("#services/platform-manager/platform-keys"); class AccessTokenManager { LOG_COMPONENT = 'accessTokenManager'; CLIENT_ASSERTION_TYPE = 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer'; GRANT_TYPE = 'client_credentials'; ACCEPT = 'application/json'; EXPIRY_SAFETY_MARGIN_SECONDS = 60; databaseManager; requestHandler; logger; constructor(databaseManager, requestHandler, logger) { this.databaseManager = databaseManager; this.requestHandler = requestHandler; this.logger = logger; } async getAccessToken(platform, scopes) { this.logger.debug(this.LOG_COMPONENT, `Attempting to retrieve access token for ${platform.url} with scopes: ${scopes}`); const cached = await this.getCachedToken(platform, scopes); const token = cached ?? (await this.requestAndCacheNewToken(platform, scopes)); return this.normalizeTokenType(token); } async getCachedToken(platform, scopes) { const record = await this.databaseManager.getAccessToken(platform.url, platform.clientId, scopes); const isExpired = record !== undefined && (Date.now() - record.createdAt) / 1000 > record.expires_in - this.EXPIRY_SAFETY_MARGIN_SECONDS; if (record === undefined || isExpired) return undefined; this.logger.debug(this.LOG_COMPONENT, `Cached access token found for ${platform.url}`); const { createdAt: _createdAt, ...token } = record; return token; } async requestAndCacheNewToken(platform, scopes) { const token = await this.requestNewToken(platform, scopes); await this.cacheToken(platform, scopes, token); this.logger.debug(this.LOG_COMPONENT, `Successfully generated new access token for ${platform.url} with scopes: ${scopes}`); return token; } async requestNewToken(platform, scopes) { const clientAssertion = await this.signClientAssertion(platform); const body = new URLSearchParams({ grant_type: this.GRANT_TYPE, client_assertion_type: this.CLIENT_ASSERTION_TYPE, client_assertion: clientAssertion, scope: scopes, }); const response = await this.requestHandler.post(platform.accessTokenEndpoint, body, { headers: { accept: this.ACCEPT }, }); return (0, validation_1.validate)(access_token_manager_schemas_1.AccessTokenSchema, response.data); } async signClientAssertion(platform) { const assertion = { sub: platform.clientId, iss: platform.clientId, aud: platform.authorizationServer, jti: (0, random_1.randomJti)(), }; return (0, jwt_1.signJwt)(assertion, (0, platform_keys_1.resolvePlatformPrivateKey)(platform), { algorithm: jwt_constants_1.RS256_ALGORITHM, expiresIn: 60, keyid: platform.id, }); } async cacheToken(platform, scopes, token) { await this.databaseManager.saveAccessToken(platform.url, platform.clientId, scopes, { ...token, createdAt: Date.now(), }); } normalizeTokenType(token) { return { ...token, token_type: token.token_type.charAt(0).toUpperCase() + token.token_type.slice(1) }; } } exports.AccessTokenManager = AccessTokenManager; exports.default = AccessTokenManager; //# sourceMappingURL=access-token-manager.service.js.map