70 lines
2.8 KiB
JavaScript
70 lines
2.8 KiB
JavaScript
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
/*
|
|
Copyright 2023 The Matrix.org Foundation C.I.C.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
import { HTTPError, TokenRefreshLogoutError } from "../http-api/index.js";
|
|
import { OAuth2HTTPError } from "./error.js";
|
|
/**
|
|
* Class responsible for refreshing OAuth2 access tokens
|
|
*/
|
|
export class TokenRefresher {
|
|
constructor(auth, onRefresh) {
|
|
_defineProperty(this, "inflightRefreshRequest", void 0);
|
|
/**
|
|
* Attempt token refresh using given refresh token
|
|
* @param refreshToken - refresh token to use in request with token issuer
|
|
* @returns tokens - Promise that resolves with new access and refresh tokens
|
|
* @throws when token refresh fails
|
|
*/
|
|
_defineProperty(this, "tokenRefreshFunction", async refreshToken => {
|
|
if (!this.inflightRefreshRequest) {
|
|
this.inflightRefreshRequest = this.getNewTokens(refreshToken);
|
|
}
|
|
try {
|
|
const tokens = await this.inflightRefreshRequest;
|
|
return tokens;
|
|
} catch (e) {
|
|
// If we encounter a 40x error then signal that it should cause a logout by upgrading it to a TokenRefreshLogoutError
|
|
if (e instanceof HTTPError && this.shouldLogoutOnError(e)) {
|
|
throw new TokenRefreshLogoutError(e);
|
|
}
|
|
throw e;
|
|
} finally {
|
|
this.inflightRefreshRequest = undefined;
|
|
}
|
|
});
|
|
this.auth = auth;
|
|
this.onRefresh = onRefresh;
|
|
}
|
|
shouldLogoutOnError(error) {
|
|
// Treat as logout as per https://spec.matrix.org/v1.18/client-server-api/#refresh-token-grant
|
|
// after making sure it is an RFC 6749 section 5.2 error response
|
|
return error instanceof OAuth2HTTPError && typeof error.httpStatus === "number" && error.httpStatus < 500 && error.httpStatus >= 400;
|
|
}
|
|
async getNewTokens(refreshToken) {
|
|
const requestStart = Date.now();
|
|
const response = await this.auth.performRefreshTokenGrant(refreshToken);
|
|
const tokens = {
|
|
accessToken: response.access_token,
|
|
refreshToken: response.refresh_token,
|
|
// We use the request start time to calculate the expiry time as we don't know when the server received our request
|
|
expiry: response.expires_in ? new Date(requestStart + response.expires_in * 1000) : undefined
|
|
};
|
|
await this.onRefresh(tokens);
|
|
return tokens;
|
|
}
|
|
}
|
|
//# sourceMappingURL=tokenRefresher.js.map
|