Merge pull request #1802 from umbraco/feature/validate-token-on-first-load

Feature: Validate the token on first load
This commit is contained in:
Jacob Overgaard
2024-05-13 16:26:35 +02:00
committed by GitHub
3 changed files with 49 additions and 23 deletions

View File

@@ -7,6 +7,7 @@ import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal';
export class UmbAppAuthController extends UmbControllerBase {
#authContext?: typeof UMB_AUTH_CONTEXT.TYPE;
#isFirstCheck = true;
constructor(host: UmbControllerHost) {
super(host);
@@ -37,7 +38,18 @@ export class UmbAppAuthController extends UmbControllerBase {
const isAuthorized = this.#authContext.getIsAuthorized();
if (isAuthorized) {
return true;
// If this is the first time we are checking the authorization state (i.e. on first load), we need to make sure
// that the token is still valid. If it is not, we need to start the authorization flow.
// If the token is still valid, we can return true.
if (this.#isFirstCheck) {
this.#isFirstCheck = false;
const isValid = await this.#authContext.validateToken();
if (isValid) {
return true;
}
} else {
return true;
}
}
// Make a request to the auth server to start the auth flow

View File

@@ -307,29 +307,17 @@ export class UmbAuthFlow {
return Promise.resolve(this.#tokenResponse.accessToken);
}
// if the refresh token is not set (maybe the provider doesn't support them)
if (!this.#tokenResponse?.refreshToken) {
this.#timeoutSignal.next();
return Promise.reject('Missing refreshToken.');
}
const success = await this.makeRefreshTokenRequest();
const request = new TokenRequest({
client_id: this.#clientId,
redirect_uri: this.#redirectUri,
grant_type: GRANT_TYPE_REFRESH_TOKEN,
code: undefined,
refresh_token: this.#tokenResponse.refreshToken,
extras: undefined,
});
await this.#performTokenRequest(request);
if (!this.#tokenResponse) {
if (!success) {
this.clearTokenStorage();
this.#timeoutSignal.next();
return Promise.reject('Missing tokenResponse.');
}
return Promise.resolve(this.#tokenResponse.accessToken);
return this.#tokenResponse
? Promise.resolve(this.#tokenResponse.accessToken)
: Promise.reject('Missing tokenResponse.');
}
/**
@@ -364,18 +352,36 @@ export class UmbAuthFlow {
await this.#performTokenRequest(request);
}
async makeRefreshTokenRequest(): Promise<boolean> {
if (!this.#tokenResponse?.refreshToken) {
return false;
}
const request = new TokenRequest({
client_id: this.#clientId,
redirect_uri: this.#redirectUri,
grant_type: GRANT_TYPE_REFRESH_TOKEN,
code: undefined,
refresh_token: this.#tokenResponse.refreshToken,
extras: undefined,
});
return this.#performTokenRequest(request);
}
/**
* This method will make a token request to the server using the refresh token.
* If the request fails, it will sign the user out (clear the token state).
*/
async #performTokenRequest(request: TokenRequest): Promise<void> {
async #performTokenRequest(request: TokenRequest): Promise<boolean> {
try {
this.#tokenResponse = await this.#tokenHandler.performTokenRequest(this.#configuration, request);
this.#saveTokenState();
return true;
} catch (error) {
// If the token request fails, it means the code or refresh token is invalid
this.clearTokenStorage();
console.error('Token request error', error);
this.clearTokenStorage();
return false;
}
}
}

View File

@@ -174,6 +174,15 @@ export class UmbAuthContext extends UmbContextBase<UmbAuthContext> {
return this.#authFlow.performWithFreshTokens();
}
/**
* Validates the token against the server and returns true if the token is valid.
* @memberof UmbAuthContext
* @returns True if the token is valid, otherwise false
*/
async validateToken(): Promise<boolean> {
return this.#authFlow.makeRefreshTokenRequest();
}
/**
* Clears the token storage.
* @memberof UmbAuthContext
@@ -188,7 +197,6 @@ export class UmbAuthContext extends UmbContextBase<UmbAuthContext> {
* @memberof UmbAuthContext
*/
timeOut() {
this.clearTokenStorage();
this.#isAuthorized.setValue(false);
this.#isTimeout.next();
}