diff --git a/packages/auth-foundation/src/oauth2/client.ts b/packages/auth-foundation/src/oauth2/client.ts index 2c2e05f..22d979d 100644 --- a/packages/auth-foundation/src/oauth2/client.ts +++ b/packages/auth-foundation/src/oauth2/client.ts @@ -29,6 +29,7 @@ import { UserInfo } from './requests/UserInfo.ts'; import { PromiseQueue } from '../utils/PromiseQueue.ts'; import { EventEmitter } from '../utils/EventEmitter.ts'; import { hasSameValues } from '../utils/index.ts'; +import TimeCoordinator, { Timestamp } from '../utils/TimeCoordinator.ts'; // ref: https://developer.okta.com/docs/reference/api/oidc/ @@ -106,6 +107,18 @@ export class OAuth2Client extends APIClient { await this.dpopSigningAuthority.sign(request, { keyPairId: dpopPairId, nonce }); } + protected async processResponse(response: Response, request: APIRequest): Promise { + await super.processResponse(response, request); + + // NOTE: this logic will not work on CORS requests, the Date header needs to be allowlisted via access-control-expose-headers + const dateHeader = response.headers.get('date'); + if (dateHeader) { + const serverTime = Timestamp.from(new Date(dateHeader)); + const skew = Math.round(serverTime.timeSince(Date.now() / 1000)); + TimeCoordinator.clockSkew = skew; + } + } + /** @internal */ protected async getJson (url: URL, options: OAuth2Client.GetJsonOptions = {}): Promise { const { skipCache } = { ...OAuth2Client.DefaultGetJsonOptions, ...options }; diff --git a/packages/auth-foundation/src/utils/TimeCoordinator.ts b/packages/auth-foundation/src/utils/TimeCoordinator.ts index c0b9ccd..3fd8878 100644 --- a/packages/auth-foundation/src/utils/TimeCoordinator.ts +++ b/packages/auth-foundation/src/utils/TimeCoordinator.ts @@ -83,16 +83,26 @@ export class Timestamp { */ // TODO: implement (post beta) class TimeCoordinator { + #skew = 0; + static #tolerance = 0; // TODO: adjust from http time headers // (backend change needed to allow Date header in CORS requests) - get clockSkew () { - return 0; + get clockSkew (): number { + return this.#skew; + } + + set clockSkew (skew: number) { + this.#skew = skew; } // TODO: accept via config option - static get clockTolerance () { - return 0; + static get clockTolerance (): number { + return TimeCoordinator.#tolerance; + } + + static set clockTolerance (tolerance: number) { + TimeCoordinator.#tolerance = tolerance; } now (): Timestamp {