You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-11-28 05:03:59 +03:00
Abstract logout-causing error type from tokenRefreshFunction calls (#4765)
* Abstract logout-causing error type from tokenRefreshFunction calls Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Add test Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --------- Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
committed by
GitHub
parent
f4de8837fd
commit
2090319bdd
@@ -20,7 +20,7 @@ limitations under the License.
|
|||||||
|
|
||||||
import fetchMock from "fetch-mock-jest";
|
import fetchMock from "fetch-mock-jest";
|
||||||
|
|
||||||
import { OidcTokenRefresher } from "../../../src";
|
import { OidcTokenRefresher, TokenRefreshLogoutError } from "../../../src";
|
||||||
import { logger } from "../../../src/logger";
|
import { logger } from "../../../src/logger";
|
||||||
import { makeDelegatedAuthConfig } from "../../test-utils/oidc";
|
import { makeDelegatedAuthConfig } from "../../test-utils/oidc";
|
||||||
|
|
||||||
@@ -266,5 +266,27 @@ describe("OidcTokenRefresher", () => {
|
|||||||
refreshToken: "second-new-refresh-token",
|
refreshToken: "second-new-refresh-token",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should throw TokenRefreshLogoutError when expired", async () => {
|
||||||
|
fetchMock.post(
|
||||||
|
config.token_endpoint,
|
||||||
|
{
|
||||||
|
status: 400,
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
error: "invalid_grant",
|
||||||
|
error_description: "The provided access grant is invalid, expired, or revoked.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ overwriteRoutes: true },
|
||||||
|
);
|
||||||
|
|
||||||
|
const refresher = new OidcTokenRefresher(authConfig.issuer, clientId, redirectUri, deviceId, idTokenClaims);
|
||||||
|
await refresher.oidcClientReady;
|
||||||
|
|
||||||
|
await expect(refresher.doRefreshAccessToken("refresh-token")).rejects.toThrow(TokenRefreshLogoutError);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -212,3 +212,17 @@ export class TokenRefreshError extends Error {
|
|||||||
return "TokenRefreshError";
|
return "TokenRefreshError";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a TokenRefreshError. This indicates that a request failed due to the token being expired,
|
||||||
|
* and attempting to refresh said token failed in a way indicative of token invalidation.
|
||||||
|
*/
|
||||||
|
export class TokenRefreshLogoutError extends Error {
|
||||||
|
public constructor(cause?: Error) {
|
||||||
|
super(cause?.message ?? "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public get name(): string {
|
||||||
|
return "TokenRefreshLogoutError";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -18,12 +18,10 @@ limitations under the License.
|
|||||||
* This is an internal module. See {@link MatrixHttpApi} for the public class.
|
* This is an internal module. See {@link MatrixHttpApi} for the public class.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ErrorResponse as OidcAuthError } from "oidc-client-ts";
|
|
||||||
|
|
||||||
import { checkObjectHasKeys, encodeParams } from "../utils.ts";
|
import { checkObjectHasKeys, encodeParams } from "../utils.ts";
|
||||||
import { type TypedEventEmitter } from "../models/typed-event-emitter.ts";
|
import { type TypedEventEmitter } from "../models/typed-event-emitter.ts";
|
||||||
import { Method } from "./method.ts";
|
import { Method } from "./method.ts";
|
||||||
import { ConnectionError, MatrixError, TokenRefreshError } from "./errors.ts";
|
import { ConnectionError, MatrixError, TokenRefreshError, TokenRefreshLogoutError } from "./errors.ts";
|
||||||
import {
|
import {
|
||||||
HttpApiEvent,
|
HttpApiEvent,
|
||||||
type HttpApiEventHandlerMap,
|
type HttpApiEventHandlerMap,
|
||||||
@@ -234,7 +232,8 @@ export class FetchHttpApi<O extends IHttpOpts> {
|
|||||||
return TokenRefreshOutcome.Success;
|
return TokenRefreshOutcome.Success;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.opts.logger?.warn("Failed to refresh token", error);
|
this.opts.logger?.warn("Failed to refresh token", error);
|
||||||
if (error instanceof OidcAuthError || error instanceof MatrixError) {
|
// If we get a TokenError or MatrixError, we should log out, otherwise assume transient
|
||||||
|
if (error instanceof TokenRefreshLogoutError || error instanceof MatrixError) {
|
||||||
return TokenRefreshOutcome.Logout;
|
return TokenRefreshOutcome.Logout;
|
||||||
}
|
}
|
||||||
return TokenRefreshOutcome.Failure;
|
return TokenRefreshOutcome.Failure;
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { type IdTokenClaims, OidcClient, WebStorageStateStore } from "oidc-client-ts";
|
import { type IdTokenClaims, OidcClient, WebStorageStateStore, ErrorResponse } from "oidc-client-ts";
|
||||||
|
|
||||||
import { type AccessTokens } from "../http-api/index.ts";
|
import { type AccessTokens, TokenRefreshLogoutError } from "../http-api/index.ts";
|
||||||
import { generateScope } from "./authorize.ts";
|
import { generateScope } from "./authorize.ts";
|
||||||
import { discoverAndValidateOIDCIssuerWellKnown } from "./discovery.ts";
|
import { discoverAndValidateOIDCIssuerWellKnown } from "./discovery.ts";
|
||||||
import { logger } from "../logger.ts";
|
import { logger } from "../logger.ts";
|
||||||
@@ -104,6 +104,12 @@ export class OidcTokenRefresher {
|
|||||||
try {
|
try {
|
||||||
const tokens = await this.inflightRefreshRequest;
|
const tokens = await this.inflightRefreshRequest;
|
||||||
return tokens;
|
return tokens;
|
||||||
|
} catch (e) {
|
||||||
|
// If we encounter an OIDC error then signal that it should cause a logout by upgrading it to a TokenRefreshLogoutError
|
||||||
|
if (e instanceof ErrorResponse) {
|
||||||
|
throw new TokenRefreshLogoutError(e);
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
} finally {
|
} finally {
|
||||||
this.inflightRefreshRequest = undefined;
|
this.inflightRefreshRequest = undefined;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user