import fetch, { RequestInit, Response } from 'node-fetch'; import { URL } from 'url'; import * as querystring from 'querystring'; import { AuthorisationTokenRequest } from '../types/request'; import { ErrorData } from '../types/errors'; import { InvalidResponseError } from '../errors'; /** * When using some methods in the Subscription service an authorisation token is required. * This function gets an authorisation token from the Membership API * @param url Should be passed in on initialisation of the service * @param sessionToken The 'FT_session_s' value from the user's cookie * @param clientId Should be passed in on initialisation of the service * @param additionalHeaders any headers to add to the request * @returns authorisation token * */ export async function authorisationTokenRequest({ url, sessionToken, clientId, additionalHeaders = {} }: AuthorisationTokenRequest, fetch: Function): Promise { const options: RequestInit = { method: 'GET', headers: { 'Cookie': `FTSession_s=${sessionToken}`, ...additionalHeaders }, redirect: 'manual' // API doesn't follow the redirect and returns an opaque-redirect filtered response which wraps the redirect response. }; const response: Response = await fetch(`${url}?client_id=${clientId}&response_type=token`, options); const data: ErrorData = { url, status: response.status, method: options.method }; // Only a redirect is expected from this call if (response.status !== 302) { throw new InvalidResponseError('Redirect expected', data); } const location = response.headers.get && response.headers.get('location'); if (!location) { throw new InvalidResponseError('Location header expected', data); } const { hash } = new URL(location); const splitQueryString = querystring.parse(hash.replace(/^#/, '')); const accessToken = splitQueryString.access_token; if (accessToken && typeof accessToken === 'string') { return accessToken; } // url returns error params: error=invalid_grant&error_description=Invalid%20FT%20user%20session if (splitQueryString.error) { throw new InvalidResponseError('' + splitQueryString.error_description, data); } data.location = location; throw new InvalidResponseError('Token not found', data); }