Skip to content

Commit

Permalink
fix: AutoRenewService should perform renew if token has expired befor…
Browse files Browse the repository at this point in the history
…e service start (#1354)

OKTA-549676 fix: AutoRenewService should perform renew if token has expired before service start
  • Loading branch information
denysoblohin-okta authored Dec 7, 2022
1 parent 682a278 commit 2d1486f
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 82 deletions.
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
# Changelog

## 7.2.0

### Fixes

- [#1354](https://github.com/okta/okta-auth-js/pull/1354) Fixes token auto renew if token has expired before `AutoRenewService` start

## 7.1.1

### Fixes

- [#1355](https://github.com/okta/okta-auth-js/pull/1355) Adds missing type `currentAuthenticatorEnrollment` to `IdxContext`


## 7.1.0

### Features
Expand Down
7 changes: 7 additions & 0 deletions lib/oidc/TokenManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ const DEFAULT_OPTIONS = {
interface TokenManagerState {
expireTimeouts: Record<string, unknown>;
renewPromise: Promise<Token | undefined> | null;
started?: boolean;
}
function defaultState(): TokenManagerState {
return {
Expand Down Expand Up @@ -138,10 +139,16 @@ export class TokenManager implements TokenManagerInterface {
this.clearPendingRemoveTokens();
}
this.setExpireEventTimeoutAll();
this.state.started = true;
}

stop() {
this.clearExpireEventTimeoutAll();
this.state.started = false;
}

isStarted() {
return !!this.state.started;
}

getOptions(): TokenManagerOptions {
Expand Down
1 change: 1 addition & 0 deletions lib/oidc/types/TokenManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,5 @@ export interface TokenManagerInterface {

start();
stop();
isStarted(): boolean;
}
18 changes: 17 additions & 1 deletion lib/services/AutoRenewService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

import { AuthSdkError } from '../errors';
import { ServiceInterface, ServiceManagerOptions } from '../core/types';
import { EVENT_EXPIRED, TokenManagerInterface } from '../oidc/types';
import { EVENT_EXPIRED, TokenManagerInterface, isRefreshToken } from '../oidc/types';
import { isBrowser } from '../features';

export class AutoRenewService implements ServiceInterface {
Expand Down Expand Up @@ -46,6 +46,17 @@ export class AutoRenewService implements ServiceInterface {
return !!this.options.syncStorage && isBrowser();
}

private processExpiredTokens() {
const tokenStorage = this.tokenManager.getStorage();
const tokens = tokenStorage.getStorage();
Object.keys(tokens).forEach(key => {
const token = tokens[key];
if (!isRefreshToken(token) && this.tokenManager.hasExpired(token)) {
this.onTokenExpiredHandler(key);
}
});
}

private onTokenExpiredHandler(key: string) {
if (this.options.autoRenew) {
if (this.shouldThrottleRenew()) {
Expand All @@ -67,6 +78,11 @@ export class AutoRenewService implements ServiceInterface {
if (this.canStart()) {
await this.stop();
this.tokenManager.on(EVENT_EXPIRED, this.onTokenExpiredHandler);
if (this.tokenManager.isStarted()) {
// If token manager has been already started, we could miss token expire events,
// so need to process expired tokens manually.
this.processExpiredTokens();
}
this.started = true;
}
}
Expand Down
7 changes: 6 additions & 1 deletion test/spec/OktaAuth/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,16 @@ describe('OktaAuth (api)', function() {
});

describe('start', () => {
it('starts the token service', async () => {
it('starts the token manager', async () => {
jest.spyOn(auth.tokenManager, 'start');
await auth.start();
expect(auth.tokenManager.start).toHaveBeenCalled();
});
it('starts the service manager', async () => {
jest.spyOn(auth.serviceManager, 'start');
await auth.start();
expect(auth.serviceManager.start).toHaveBeenCalled();
});
it('updates auth state', async () => {
jest.spyOn(auth.authStateManager, 'updateAuthState');
await auth.start();
Expand Down
1 change: 1 addition & 0 deletions test/spec/ServiceManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ describe('ServiceManager', () => {
it('starts autoRenew service after becoming leader (for syncStorage == true)', async () => {
const options = { tokenManager: { syncStorage: true, autoRenew: true } };
const client = createAuth(options);
expect(client.serviceManager.isLeaderRequired()).toBeTruthy();
await client.serviceManager.start();
expect(client.serviceManager.isLeader()).toBeFalsy();
expect(client.serviceManager.getService('autoRenew')?.isStarted()).toBeFalsy();
Expand Down
Loading

0 comments on commit 2d1486f

Please sign in to comment.