Skip to content

Commit

Permalink
resolves #340 - Auto-refresh tokens
Browse files Browse the repository at this point in the history
  • Loading branch information
vscheuber committed Oct 26, 2023
1 parent 19dd8e9 commit 16a704d
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 13 deletions.
73 changes: 60 additions & 13 deletions src/ops/AuthenticateOps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,31 +27,25 @@ export type Authenticate = {
/**
* Get tokens
* @param {boolean} forceLoginAsUser true to force login as user even if a service account is available (default: false)
* @param {boolean} autoRefresh true to automatically refresh tokens before they expire (default: true)
* @returns {Promise<boolean>} true if tokens were successfully obtained, false otherwise
*/
getTokens(forceLoginAsUser?: boolean): Promise<boolean>;
getTokens(
forceLoginAsUser?: boolean,
autoRefresh?: boolean
): Promise<boolean>;
};

export default (state: State): Authenticate => {
return {
/**
* Get access token for service account
* @returns {string | null} Access token or null
*/
async getAccessTokenForServiceAccount(
saId: string = undefined,
saJwk: JwkRsa = undefined
): Promise<string | null> {
return getAccessTokenForServiceAccount({ saId, saJwk, state });
},

/**
* Get tokens
* @param {boolean} forceLoginAsUser true to force login as user even if a service account is available (default: false)
* @returns {Promise<boolean>} true if tokens were successfully obtained, false otherwise
*/
getTokens(forceLoginAsUser = false) {
return getTokens({ forceLoginAsUser, state });
getTokens(forceLoginAsUser = false, autoRefresh = true) {
return getTokens({ forceLoginAsUser, autoRefresh, state });
},
};
};
Expand Down Expand Up @@ -571,6 +565,10 @@ export async function getAccessTokenForServiceAccount({
state,
});
debugMessage({ message: response.data.access_token, state });
debugMessage({
message: `AuthenticateOps.getAccessTokenForServiceAccount: expires: ${response.data.expires_in}`,
state,
});
debugMessage({
message: `AuthenticateOps.getAccessTokenForServiceAccount: end`,
state,
Expand Down Expand Up @@ -644,17 +642,65 @@ async function getLoggedInSubject(state: State): Promise<string> {
return subjectString;
}

/**
* Helper method to set, reset, or cancel timer to auto refresh tokens
* @param {boolean} forceLoginAsUser true to force login as user even if a service account is available (default: false)
* @param {boolean} autoRefresh true to automatically refresh tokens before they expire (default: true)
* @param {State} state library state
*/
function scheduleAutoRefresh(
forceLoginAsUser: boolean,
autoRefresh: boolean,
state: State
) {
let timer = state.getAutoRefreshTimer();
// reset existing timer
if (timer) {
if (autoRefresh) {
debugMessage({
message: `AuthenticateOps.scheduleAutoRefresh: reset existing timer`,
state,
});
timer.refresh();
} else {
debugMessage({
message: `AuthenticateOps.scheduleAutoRefresh: cancel existing timer`,
state,
});
clearInterval(timer);
}
}
// new timer
else if (autoRefresh) {
debugMessage({
message: `AuthenticateOps.scheduleAutoRefresh: set new timer`,
state,
});
timer = setInterval(getTokens, 1000 * 10, {
forceLoginAsUser,
autoRefresh,
state,
// Volker's Visual Studio Code doesn't want to have it any other way.
}) as unknown as NodeJS.Timeout;
timer.unref();
state.setAutoRefreshTimer(timer);
}
}

/**
* Get tokens
* @param {boolean} forceLoginAsUser true to force login as user even if a service account is available (default: false)
* @param {boolean} autoRefresh true to automatically refresh tokens before they expire (default: true)
* @param {State} state library state
* @returns {Promise<boolean>} true if tokens were successfully obtained, false otherwise
*/
export async function getTokens({
forceLoginAsUser = false,
autoRefresh = true,
state,
}: {
forceLoginAsUser?: boolean;
autoRefresh?: boolean;
state: State;
}): Promise<boolean> {
debugMessage({ message: `AuthenticateOps.getTokens: start`, state });
Expand Down Expand Up @@ -770,6 +816,7 @@ export async function getTokens({
type: 'info',
state,
});
scheduleAutoRefresh(forceLoginAsUser, autoRefresh, state);
debugMessage({
message: `AuthenticateOps.getTokens: end with tokens`,
state,
Expand Down
11 changes: 11 additions & 0 deletions src/shared/State.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ export type State = {
getOutputFile(): string;
setDirectory(directory: string): void;
getDirectory(): string;
setAutoRefreshTimer(timer: NodeJS.Timeout): void;
getAutoRefreshTimer(): NodeJS.Timeout;
setCurlirizeHandler(handler: (message: string) => void): void;
getCurlirizeHandler(): (message: string) => void;
setCurlirize(curlirize: boolean): void;
Expand Down Expand Up @@ -275,6 +277,13 @@ export default (initialState: StateInterface): State => {
return state.directory;
},

setAutoRefreshTimer(timer: NodeJS.Timeout): void {
state.autoRefreshTimer = timer;
},
getAutoRefreshTimer(): NodeJS.Timeout {
return state.autoRefreshTimer;
},

setCurlirizeHandler(handler: (message: string) => void) {
state.curlirizeHandler = handler;
},
Expand Down Expand Up @@ -396,6 +405,7 @@ export interface StateInterface {
masterKeyPath?: string;
outputFile?: string;
directory?: string;
autoRefreshTimer?: NodeJS.Timeout;
// output handler settings
printHandler?: (
message: string | object,
Expand Down Expand Up @@ -858,6 +868,7 @@ export const getDebug = (): boolean =>
* @deprecated since version v0.17.0. Import state:
*
* ```import { state } from '@rockcarver/frodo-lib';```
import { setInterval } from '@types/node';
*
* then call functions:
*
Expand Down

0 comments on commit 16a704d

Please sign in to comment.