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;