diff --git a/src/authentication/IAuthenticator.ts b/src/authentication/IAuthenticator.ts index 0a2eeace2..406d7fc29 100644 --- a/src/authentication/IAuthenticator.ts +++ b/src/authentication/IAuthenticator.ts @@ -1,4 +1,5 @@ import { AccessToken } from "./accessToken"; +import { HttpHeader } from "@paperbits/common/http/httpHeader"; export interface IAuthenticator { /** @@ -12,6 +13,12 @@ export interface IAuthenticator { */ setAccessToken(accessToken: string): Promise; + /** + * Sets new token for the session from response header and return refreshed value + * @param responseHeaders {HttpHeader[]} Response headers. + */ + refreshAccessTokenFromHeader(responseHeaders: HttpHeader[]): Promise; + /** * Parses specified access token. * @param accessToken diff --git a/src/components/defaultAuthenticator.ts b/src/components/defaultAuthenticator.ts index 2cf6b02a6..02c60f9bf 100644 --- a/src/components/defaultAuthenticator.ts +++ b/src/components/defaultAuthenticator.ts @@ -1,6 +1,7 @@ import * as moment from "moment"; import { Utils } from "../utils"; import { IAuthenticator, AccessToken } from "./../authentication"; +import { HttpHeader } from "@paperbits/common/http/httpHeader"; export class DefaultAuthenticator implements IAuthenticator { public async getAccessToken(): Promise { @@ -11,6 +12,26 @@ export class DefaultAuthenticator implements IAuthenticator { sessionStorage.setItem("accessToken", accessToken); } + public async refreshAccessTokenFromHeader(responseHeaders: HttpHeader[] = []): Promise { + const accessTokenHeader = responseHeaders.find(x => x.name.toLowerCase() === "ocp-apim-sas-token"); + if (accessTokenHeader && accessTokenHeader.value) { + const regex = /token=\"(.*)",refresh/gm; + const match = regex.exec(accessTokenHeader.value); + + if (!match || match.length < 2) { + console.error(`Token format is not valid.`); + } + + const accessToken = `SharedAccessSignature ${accessTokenHeader.value}`; + const current = sessionStorage.getItem("accessToken"); + if (current !== accessToken) { + sessionStorage.setItem("accessToken", accessToken); + return accessToken; + } + } + return undefined; + } + public async clearAccessToken(): Promise { sessionStorage.removeItem("accessToken"); } @@ -33,7 +54,16 @@ export class DefaultAuthenticator implements IAuthenticator { return now < parsedToken.expires; } - private parseSharedAccessSignature(accessToken: string): AccessToken { + private parseSharedAccessSignature(fullAccessToken: string): AccessToken { + let accessToken = fullAccessToken; + const refreshRegex = /token=\"(.*)",refresh/gm; + const refreshMatch = refreshRegex.exec(fullAccessToken); + if (!refreshMatch || refreshMatch.length < 2) { + console.error(`Token is not full.`); + } else { + accessToken = refreshMatch[1]; + } + const regex = /^[\w\-]*\&(\d*)\&/gm; const match = regex.exec(accessToken); diff --git a/src/components/staticAuthenticator.ts b/src/components/staticAuthenticator.ts index 74ec40d20..438bcfe7a 100644 --- a/src/components/staticAuthenticator.ts +++ b/src/components/staticAuthenticator.ts @@ -1,4 +1,5 @@ import { IAuthenticator } from "../authentication"; +import { HttpHeader } from "@paperbits/common/http/httpHeader"; export class StaticAuthenticator implements IAuthenticator { private accessToken: string; @@ -11,6 +12,26 @@ export class StaticAuthenticator implements IAuthenticator { this.accessToken = token; } + public async refreshAccessTokenFromHeader(responseHeaders: HttpHeader[] = []): Promise { + const accessTokenHeader = responseHeaders.find(x => x.name.toLowerCase() === "ocp-apim-sas-token"); + if (accessTokenHeader && accessTokenHeader.value) { + const regex = /token=\"(.*)",refresh/gm; + const match = regex.exec(accessTokenHeader.value); + + if (!match || match.length < 2) { + console.error(`Token format is not valid.`); + } + + const accessToken = `SharedAccessSignature ${accessTokenHeader.value}`; + const current = this.accessToken; + if (current !== accessToken) { + this.accessToken = accessToken; + return accessToken; + } + } + return undefined; + } + public async clearAccessToken(): Promise { this.accessToken = undefined; } diff --git a/src/services/mapiClient.ts b/src/services/mapiClient.ts index c7fca46e4..9f2cd858d 100644 --- a/src/services/mapiClient.ts +++ b/src/services/mapiClient.ts @@ -144,6 +144,13 @@ export class MapiClient { throw new Error(`Unable to complete request. Error: ${error.message}`); } + try { + await this.authenticator.refreshAccessTokenFromHeader(response.headers); + } + catch (error) { + console.error("Refresh token error: ", error); + } + return this.handleResponse(response, httpRequest.url); } diff --git a/src/services/usersService.ts b/src/services/usersService.ts index e0dc09652..96cab2f90 100644 --- a/src/services/usersService.ts +++ b/src/services/usersService.ts @@ -52,19 +52,7 @@ export class UsersService { }); const identity = response.toObject(); - const accessTokenHeader = response.headers.find(x => x.name.toLowerCase() === "ocp-apim-sas-token"); - - if (accessTokenHeader && accessTokenHeader.value) { - const regex = /token=\"(.*)",refresh/gm; - const match = regex.exec(accessTokenHeader.value); - - if (!match || match.length < 2) { - throw new Error(`Token format is not valid.`); - } - - const accessToken = match[1]; - await this.authenticator.setAccessToken(`SharedAccessSignature ${accessToken}`); - } + await this.authenticator.refreshAccessTokenFromHeader(response.headers); if (identity && identity.id) { return identity.id;