diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/RevokeDeveloperTokenDialog.tsx b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/RevokeDeveloperTokenDialog.tsx index 7e9d045704..f47af0d232 100644 --- a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/RevokeDeveloperTokenDialog.tsx +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/RevokeDeveloperTokenDialog.tsx @@ -21,9 +21,11 @@ import { import { UserStore } from "@docspace/shared/store/UserStore"; import { OAuthStoreProps } from "SRC_DIR/store/OAuthStore"; +import { introspectDeveloperToken } from "@docspace/shared/api/oauth"; +import { FieldContainer } from "@docspace/shared/components/field-container"; const StyledContainer = styled.div` - p { + .warning-text { margin-bottom: 16px; } `; @@ -42,11 +44,15 @@ const GenerateDeveloperTokenDialog = ({ // const {} = useTranslation(["OAuth", "Common"]); const [token, setToken] = React.useState(""); + const [isValidToken, setIsValidToken] = React.useState(false); + const [tokenError, setTokenError] = React.useState(""); const [requestRunning, setRequestRunning] = React.useState(false); + const timerRef = React.useRef(null); + const onRevoke = async () => { - if (!token || !client || requestRunning) return; + if (!token || !isValidToken || !client || requestRunning) return; try { const { clientId, clientSecret } = client; @@ -66,9 +72,42 @@ const GenerateDeveloperTokenDialog = ({ } }; - const onChange = (e: React.ChangeEvent) => { + const onChange = async (e: React.ChangeEvent) => { const value = e.target.value; + if (timerRef.current) { + clearTimeout(timerRef.current); + } + + if (!value) { + setIsValidToken(false); + setTokenError(""); + setToken(""); + return; + } + + timerRef.current = setTimeout(async () => { + try { + const data = await introspectDeveloperToken(value); + + if (!data) return; + + const { active, client_id: clientId } = data; + + if (active && clientId === client?.clientId) { + setIsValidToken(true); + setTokenError(""); + return; + } + + setIsValidToken(false); + setTokenError("Invalid token"); + } catch (err) { + setIsValidToken(false); + setTokenError("Invalid token"); + } + }, 200); + setToken(value); }; @@ -89,16 +128,23 @@ const GenerateDeveloperTokenDialog = ({ Revoke developer token - Warning text - + Warning text + + + @@ -107,7 +153,7 @@ const GenerateDeveloperTokenDialog = ({ primary scale onClick={onRevoke} - isDisabled={!token} + isDisabled={!token || !isValidToken} isLoading={requestRunning} size={ButtonSize.small} /> diff --git a/packages/shared/api/oauth/index.ts b/packages/shared/api/oauth/index.ts index 2568addaef..e232dfe72b 100644 --- a/packages/shared/api/oauth/index.ts +++ b/packages/shared/api/oauth/index.ts @@ -12,6 +12,7 @@ import { TConsentData, TConsentList, TGenerateDeveloperToken, + TIntrospectDeveloperToken, } from "../../utils/oauth/types"; export const getClient = async (clientId: string): Promise => { @@ -278,8 +279,8 @@ export const introspectDeveloperToken = (token: string) => { const params = new URLSearchParams(); params.append("token", token); - return request( - { method: "post", url: "/oauth2/revoke", data: params }, + return request( + { method: "post", url: "/oauth2/introspect", data: params }, false, true, ); diff --git a/packages/shared/utils/oauth/types.ts b/packages/shared/utils/oauth/types.ts index d269b28910..6f6c88f6bb 100644 --- a/packages/shared/utils/oauth/types.ts +++ b/packages/shared/utils/oauth/types.ts @@ -157,3 +157,19 @@ export type TGenerateDeveloperToken = { scope: string; token_type: string; }; + +export type TIntrospectDeveloperToken = { + active: boolean; + sub: string; + aud: string[]; + nbf: string; + scope: string; + iss: string; + exp: number; + iat: number; + jti: string; + tid: number; + cid: string; + client_id: string; + token_type: string; +};