Hey is a decentralized and permissionless social media app built with Lens Protocol 馃尶
at main 77 lines 2.2 kB view raw
1import parseJwt from "@hey/helpers/parseJwt"; 2import { RefreshDocument, type RefreshMutation } from "@hey/indexer"; 3import apolloClient from "@hey/indexer/apollo/client"; 4import type { JwtPayload } from "@hey/types/jwt"; 5import { signIn, signOut } from "@/store/persisted/useAuthStore"; 6 7let refreshPromise: Promise<string> | null = null; 8const MAX_RETRIES = 5; 9 10const executeTokenRefresh = async (refreshToken: string): Promise<string> => { 11 try { 12 for (let attempt = 0; attempt < MAX_RETRIES; attempt++) { 13 const { data } = await apolloClient.mutate<RefreshMutation>({ 14 mutation: RefreshDocument, 15 variables: { request: { refreshToken } } 16 }); 17 18 const refreshResult = data?.refresh; 19 20 if (!refreshResult) { 21 throw new Error("No response from refresh"); 22 } 23 24 if (refreshResult.__typename === "AuthenticationTokens") { 25 const { accessToken: newAccessToken, refreshToken: newRefreshToken } = 26 refreshResult; 27 28 if (!newAccessToken || !newRefreshToken) { 29 throw new Error("Missing tokens in refresh response"); 30 } 31 32 signIn({ 33 accessToken: newAccessToken, 34 refreshToken: newRefreshToken 35 }); 36 37 return newAccessToken; 38 } 39 40 if (refreshResult.__typename === "ForbiddenError") { 41 signOut(); 42 throw new Error("Refresh token is invalid or expired"); 43 } 44 45 if (attempt < MAX_RETRIES - 1) { 46 await new Promise((resolve) => 47 setTimeout(resolve, 2 ** attempt * 1000) 48 ); 49 } 50 } 51 52 throw new Error("Unknown error during token refresh"); 53 } finally { 54 refreshPromise = null; 55 } 56}; 57 58export const refreshTokens = (refreshToken: string): Promise<string> => { 59 if (!refreshPromise) { 60 refreshPromise = executeTokenRefresh(refreshToken); 61 } 62 63 return refreshPromise; 64}; 65 66export const isTokenExpiringSoon = (accessToken: string | null): boolean => { 67 if (!accessToken) { 68 return false; 69 } 70 71 const tokenData: JwtPayload = parseJwt(accessToken); 72 const bufferInMinutes = 5; 73 return ( 74 !!tokenData.exp && 75 Date.now() >= tokenData.exp * 1000 - bufferInMinutes * 60 * 1000 76 ); 77};