From 3ef729e000351d207907c48ff2cb8f577918d7b7 Mon Sep 17 00:00:00 2001 From: Christian Zheng <czheng@takima.fr> Date: Mon, 11 Apr 2022 16:03:25 +0200 Subject: [PATCH] feat(login): add token verifier --- ...keycloakOAuth2DeviceFlowConnection.test.ts | 16 +++++++ .../keycloakOAuth2DeviceFlowConnection.ts | 45 ++++++++++++++++++- 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/deadlock-plugins/deadlock-extension/src/core/keycloakOAuth2DeviceFlowConnection.test.ts b/deadlock-plugins/deadlock-extension/src/core/keycloakOAuth2DeviceFlowConnection.test.ts index 84a855ed..99b758e2 100644 --- a/deadlock-plugins/deadlock-extension/src/core/keycloakOAuth2DeviceFlowConnection.test.ts +++ b/deadlock-plugins/deadlock-extension/src/core/keycloakOAuth2DeviceFlowConnection.test.ts @@ -15,6 +15,7 @@ export default class KeycloakOAuth2DeviceFlowConnectionTest { this.connection = new KeycloakOAuth2DeviceFlowConnection( 'https://auth.dev.deadlock.io/auth/realms/Deadlock/protocol/openid-connect/auth/device', 'https://auth.dev.deadlock.io/auth/realms/Deadlock/protocol/openid-connect/token', + 'https://auth.dev.deadlock.io/auth/realms/Deadlock/protocol/openid-connect/userinfo', ); } @@ -38,5 +39,20 @@ export default class KeycloakOAuth2DeviceFlowConnectionTest { openLink: openLinkPlaceholder, }); console.log('refreshed tokens', refreshedTokens); + + try { + console.log(`'12345' is a valid token ? ${await this.connection.tokenIsValid('12345')};`); + console.log(`'' is a valid token ? ${await this.connection.tokenIsValid('')};`); + console.log( + `${tokens.accessToken} is a valid token ? ${await this.connection.tokenIsValid(tokens.accessToken)};`, + ); + console.log( + `${refreshedTokens.accessToken} is a valid token ? ${await this.connection.tokenIsValid( + refreshedTokens.accessToken, + )};`, + ); + } catch (error: unknown) { + console.error(error); + } } } diff --git a/deadlock-plugins/deadlock-extension/src/core/keycloakOAuth2DeviceFlowConnection.ts b/deadlock-plugins/deadlock-extension/src/core/keycloakOAuth2DeviceFlowConnection.ts index 06be288f..7a345876 100644 --- a/deadlock-plugins/deadlock-extension/src/core/keycloakOAuth2DeviceFlowConnection.ts +++ b/deadlock-plugins/deadlock-extension/src/core/keycloakOAuth2DeviceFlowConnection.ts @@ -12,13 +12,54 @@ export default class KeycloakOAuth2DeviceFlowConnection { private _refreshToken: string; private _deviceAuthorizationRequestResponseData: DeviceAuthorizationRequestResponseData; - constructor(private _deviceUrl: string, private _tokenUrl: string) { + constructor(private _deviceUrl: string, private _tokenUrl: string, private _userInfoUrl?: string) { this._waitDuration = new WaitDuration([5_000, 5_000, 5_000, 10_000, 10_000, 10_000, 30_000, 30_000, 100_000]); this._accessToken = ''; this._refreshToken = ''; this._deviceAuthorizationRequestResponseData = {}; } + /** + * _userInfoUrl must be passed in constructor in order to use this + * @param accessToken + * @returns Promise + */ + public async tokenIsValid(accessToken: string) { + const url = this._userInfoUrl; + if (!url) { + return Promise.reject('tokenIsValid: missing user_info API endpoint'); + } + if (!accessToken) { + return Promise.resolve(false); + } + const tokenValidationRequestResponse: Response = await fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + Authorization: `Bearer ${accessToken}`, + }, + body: '', + agent: new https.Agent({ rejectUnauthorized: false }), // TODO: remove when SSL will work + }); + const tokenValidationRequestResponseCode = tokenValidationRequestResponse.status; + switch (tokenValidationRequestResponseCode) { + case HttpStatusCode.OK: { + return Promise.resolve(true); + } + case HttpStatusCode.BAD_REQUEST: { + const badRequestResponse: FailedAuthenticationReponseData = + (await tokenValidationRequestResponse.json()) as FailedAuthenticationReponseData; + throw new Error('tokenIsValid: ' + badRequestResponse.error); + } + case HttpStatusCode.UNAUTHORIZED: { + return Promise.resolve(false); + } + default: { + throw new Error(`tokenIsValid: Unhandled HTTP status: ${tokenValidationRequestResponseCode}`); + } + } + } + public async getToken(args: { refreshToken?: string; openLink: (link: string) => void }) { const { refreshToken, openLink } = args; if (!!refreshToken) { @@ -145,7 +186,7 @@ export default class KeycloakOAuth2DeviceFlowConnection { break; } default: { - break; + throw new Error(`tokenIsValid: Unhandled HTTP status: ${userAuthenticationRequestResponseCode}`); } } } -- GitLab