diff --git a/deadlock-plugins/deadlock-extension/src/core/keycloakOAuth2DeviceFlowConnection.test.ts b/deadlock-plugins/deadlock-extension/src/core/keycloakOAuth2DeviceFlowConnection.test.ts
index 84a855ed66833348dd6ef805f4c8b0c965117f1b..99b758e2944cba705f1f192735f6936da69f00c7 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 06be288f3b5be1f856e10e04dd7e9cd16432622e..7a34587675991c65d4d3966d816b3a525f3de00f 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}`);
 				}
 			}
 		}