# frozen_string_literal: true require_relative '../helpers/jwt_helper' module Alula # Helper class to generate OAuth access tokens (core API) and JWT tokens (VSP API) class TokenExchange class << self def token_for_user(user_id, opts = {}, scope: nil) url = '/rest/v1/oauth/accesstokens' payload = { data: { attributes: { userId: user_id } } } payload[:data][:attributes][:scope] = scope if scope response = Alula::Client.request(:post, url, payload, opts) if response.ok? ImpersonatedToken.new(response.data['data']['attributes']) else error_class = AlulaError.for_response(response) raise error_class end end def fetch_video_token(payload) cache_key = generate_cache_key(payload) cached_token, expiry = retrieve_cached_token(cache_key) if cached_token && Time.now.to_i < expiry jwt_token = cached_token else jwt_token = build_jwt_token(payload) expiry = Time.now.to_i + JwtHelper::ONE_HOUR # 1 hour expiry store_token_in_cache(cache_key, jwt_token, expiry) end jwt_token end private def build_jwt_token(payload) JwtHelper.build_jwt_token(payload) end def store_token_in_cache(cache_key, jwt_token, expiry) @token_cache ||= {} @token_cache[cache_key] = [jwt_token, expiry] end def retrieve_cached_token(cache_key) @token_cache ||= {} @token_cache[cache_key] end def generate_cache_key(payload) if payload[:internal] 'jwt_token_internal' elsif payload[:customerId] "jwt_token_customer_#{payload[:customerId]}" else raise ArgumentError, 'Invalid payload' end end end class ImpersonatedToken # Simple Oauth::Response reader object attr_reader :date_created, :access_token, :expires_in, :expires_at, :refresh_token, :scope, :impersonated_by def initialize(attributes) @raw_response = attributes @date_created = Time.parse(attributes['dateCreated']) @access_token = attributes['accessToken'] @expires_at = Time.parse(attributes['expires']) @expires_in = (@expires_at - Time.now.utc).to_i @refresh_token = attributes['refresh_token'] @scope = attributes['scope'] @impersonated_by = attributes['impersonatedBy'] end end end end