diff --git a/packages/react/src/auth/index.ts b/packages/react/src/auth/index.ts index 632083b7..7ae03693 100644 --- a/packages/react/src/auth/index.ts +++ b/packages/react/src/auth/index.ts @@ -15,7 +15,7 @@ // useCreateUserWithEmailAndPasswordMutation // useFetchSignInMethodsForEmailQuery // useGetRedirectResultQuery -// useRevokeAccessTokenMutation +export { useRevokeAccessTokenMutation } from "./useRevokeAccessTokenMutation"; // useSendPasswordResetEmailMutation // useSendSignInLinkToEmailMutation export { useSignInAnonymouslyMutation } from "./useSignInAnonymouslyMutation"; @@ -46,4 +46,3 @@ export { useSignInAnonymouslyMutation } from "./useSignInAnonymouslyMutation"; // useUpdatePasswordMutation // useUpdateProfileMutation // useVerifyBeforeUpdateEmailMutation - diff --git a/packages/react/src/auth/useRevokeAccessTokenMutation.test.tsx b/packages/react/src/auth/useRevokeAccessTokenMutation.test.tsx new file mode 100644 index 00000000..aac3d1ea --- /dev/null +++ b/packages/react/src/auth/useRevokeAccessTokenMutation.test.tsx @@ -0,0 +1,51 @@ +import React from "react"; +import { describe, expect, test, beforeEach, afterEach } from "vitest"; +import { renderHook, act, waitFor } from "@testing-library/react"; +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import { useRevokeAccessTokenMutation } from "./useRevokeAccessTokenMutation"; +import { + OAuthProvider, + signInWithPopup, + type UserCredential, +} from "firebase/auth"; +import { auth, wipeAuth } from "~/testing-utils"; + +const queryClient = new QueryClient({ + defaultOptions: { + queries: { retry: false }, + mutations: { retry: false }, + }, +}); + +const wrapper = ({ children }: { children: React.ReactNode }) => ( + {children} +); + +describe("useRevokeAccessTokenMutation", () => { + let userCredential: UserCredential; + + beforeEach(async () => { + const provider = new OAuthProvider("apple.com"); + userCredential = await signInWithPopup(auth, provider); + }); + + afterEach(async () => { + queryClient.clear(); + await auth.signOut(); + await wipeAuth(); + }); + + test("successfully revokes access token", async () => { + const { result } = renderHook(() => useRevokeAccessTokenMutation(auth), { + wrapper, + }); + + const oauthAccessToken = await userCredential.user.getIdToken(); + + act(() => { + result.current.mutate({ token: oauthAccessToken }); + }); + + await waitFor(() => expect(result.current.isSuccess).toBe(true)); + }); +}); diff --git a/packages/react/src/auth/useRevokeAccessTokenMutation.ts b/packages/react/src/auth/useRevokeAccessTokenMutation.ts new file mode 100644 index 00000000..bb466561 --- /dev/null +++ b/packages/react/src/auth/useRevokeAccessTokenMutation.ts @@ -0,0 +1,22 @@ +import { useMutation, type UseMutationOptions } from "@tanstack/react-query"; +import { type Auth, AuthError, revokeAccessToken } from "firebase/auth"; + +type RevokeAccessTokenParams = { + token: string; +}; + +type AuthUseMutationOptions< + TData = unknown, + TError = Error, + TVariables = void +> = Omit, "mutationFn">; + +export function useRevokeAccessTokenMutation( + auth: Auth, + options?: AuthUseMutationOptions +) { + return useMutation({ + ...options, + mutationFn: ({ token }) => revokeAccessToken(auth, token), + }); +}