Mirror: The highly customizable and versatile GraphQL client with which you add on features like normalized caching as you grow.
at main 2.4 kB view raw
1import { Client, fetchExchange, cacheExchange, gql } from 'urql'; 2import { authExchange } from '@urql/exchange-auth'; 3 4import { 5 getRefreshToken, 6 getToken, 7 saveAuthData, 8 clearStorage, 9} from './authStore'; 10 11const REFRESH_TOKEN_MUTATION = gql` 12 mutation RefreshCredentials($refreshToken: String!) { 13 refreshCredentials(refreshToken: $refreshToken) { 14 refreshToken 15 token 16 } 17 } 18`; 19 20const auth = authExchange(async utilities => { 21 let token = getToken(); 22 let refreshToken = getRefreshToken(); 23 24 return { 25 addAuthToOperation(operation) { 26 return token 27 ? utilities.appendHeaders(operation, { 28 Authorization: `Bearer ${token}`, 29 }) 30 : operation; 31 }, 32 didAuthError(error) { 33 return error.graphQLErrors.some( 34 e => e.extensions?.code === 'UNAUTHORIZED' 35 ); 36 }, 37 willAuthError(operation) { 38 // Sync tokens on every operation 39 token = getToken(); 40 refreshToken = getRefreshToken(); 41 42 if (!token) { 43 // Detect our login mutation and let this operation through: 44 return ( 45 operation.kind !== 'mutation' || 46 // Here we find any mutation definition with the "signin" field 47 !operation.query.definitions.some(definition => { 48 return ( 49 definition.kind === 'OperationDefinition' && 50 definition.selectionSet.selections.some(node => { 51 // The field name is just an example, since register may also be an exception 52 return node.kind === 'Field' && node.name.value === 'signin'; 53 }) 54 ); 55 }) 56 ); 57 } 58 return false; 59 }, 60 async refreshAuth() { 61 if (refreshToken) { 62 const result = await utilities.mutate(REFRESH_TOKEN_MUTATION, { 63 refreshToken, 64 }); 65 66 if (result.data?.refreshCredentials) { 67 token = result.data.refreshCredentials.token; 68 refreshToken = result.data.refreshCredentials.refreshToken; 69 saveAuthData({ token, refreshToken }); 70 return; 71 } 72 } 73 74 // This is where auth has gone wrong and we need to clean up and redirect to a login page 75 clearStorage(); 76 window.location.reload(); 77 }, 78 }; 79}); 80 81const client = new Client({ 82 url: 'https://trygql.formidable.dev/graphql/web-collections', 83 exchanges: [cacheExchange, auth, fetchExchange], 84}); 85 86export default client;