-
Notifications
You must be signed in to change notification settings - Fork 3
/
auth-exchange.ts
90 lines (82 loc) · 2.89 KB
/
auth-exchange.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import { gql, makeOperation } from "https://npm.tfl.dev/@urql/core@^3.0.0";
import { authExchange } from "https://npm.tfl.dev/@urql/exchange-auth@^1.0.0";
import globalContext from "https://tfl.dev/@truffle/global-context@^1.0.0/index.ts";
import {
getAccessToken,
setAccessTokenCookie,
setAccessTokenJumper,
} from "./auth.ts";
export const TRUFFLE_ACCESS_TOKEN_KEY = "mogul-menu:accessToken";
const LOGIN_ANON_MUTATION = gql
`mutation LoginAnon { userLoginAnon { accessToken } }`;
export function getAuthExchange() {
return authExchange({
addAuthToOperation: ({
authState,
operation,
}) => {
const context = globalContext.getStore();
// the token isn't in the auth state, return the operation without changes
// HACK: variables._skipAuth for domain query. ideally there's some way to bypass
// auth via context instead of var
if (
(!authState || !authState.accessToken) &&
!operation?.variables?._skipAuth
) {
return operation;
}
// fetchOptions can be a function (See Client API) but you can simplify this based on usage
const fetchOptions = typeof operation.context.fetchOptions === "function"
? operation.context.fetchOptions()
: operation.context.fetchOptions || {};
return makeOperation(
operation.kind,
operation,
{
...operation.context,
fetchOptions: {
...fetchOptions,
headers: {
...fetchOptions.headers,
"x-access-token": authState.accessToken || "",
"x-org-id": context.orgId || "",
},
},
},
);
},
willAuthError: ({ authState }) => {
if (!authState) return true;
// e.g. check for expiration, existence of auth etc
return false;
},
didAuthError: ({ error }) => {
// check if the error was an auth error
const hasAuthError = error.graphQLErrors.some(
(e) => e.extensions?.code === 401,
);
if (hasAuthError) {
console.log("Auth error, retrying", error);
setAccessTokenCookie("");
}
return hasAuthError;
},
getAuth: async ({ authState, mutate }) => {
let accessToken = await getAccessToken();
// TODO: ideally we don't want to create an anon user during ssr because
// the user may actually exist, but has 3rd party cookies disabled.
// BUT we have to for now since sporocarp will break if we don't have
// an accessToken
if (!accessToken || accessToken === "undefined") {
console.log("no user found, creating one");
const response = await mutate(LOGIN_ANON_MUTATION);
accessToken = response?.data?.userLoginAnon?.accessToken;
if (accessToken) {
setAccessTokenJumper(accessToken);
setAccessTokenCookie(accessToken);
}
}
return { accessToken };
},
});
}