@urql/exchange-auth
An exchange for managing authentication in urql
@urql/exchange-auth
is an exchange for the urql
GraphQL client which helps handle auth headers and token refresh
Quick Start Guide
First install @urql/exchange-auth
alongside urql
:
yarn add @urql/exchange-auth
npm install --save @urql/exchange-auth
You'll then need to add the authExchange
, that this package exposes to your urql
Client
import { createClient, dedupExchange, cacheExchange, fetchExchange } from 'urql';
import { makeOperation } from '@urql/core';
import { authExchange } from '@urql/exchange-auth';
const client = createClient({
url: 'http://localhost:1234/graphql',
exchanges: [
dedupExchange,
cacheExchange,
authExchange({
addAuthToOperation: ({
authState,
operation,
}) => {
if (!authState || !authState.token) {
return operation;
}
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,
"Authorization": authState.token,
},
},
},
);
},
willAuthError: ({ authState }) => {
if (!authState) return true;
return false;
},
didAuthError: ({ error }) => {
return error.graphQLErrors.some(
e => e.extensions?.code === 'FORBIDDEN',
);
},
getAuth: async ({ authState, mutate }) => {
if (!authState) {
const token = localStorage.getItem('token');
const refreshToken = localStorage.getItem('refreshToken');
if (token && refreshToken) {
return { token, refreshToken };
}
return null;
}
const result = await mutate(refreshMutation, {
token: authState!.refreshToken,
});
if (result.data?.refreshLogin) {
localStorage.setItem('token', result.data.refreshLogin.token);
localStorage.setItem('refreshToken', result.data.refreshLogin.refreshToken);
return {
token: result.data.refreshLogin.token,
refreshToken: result.data.refreshLogin.refreshToken,
};
}
localStorage.clear();
logout();
return null;
},
}),
fetchExchange
],
});
Handling Errors via the errorExchange
Handling the logout logic in getAuth
is the easiest way to get started, but it means the errors will always get swallowed by the authExchange
.
If you want to handle errors globally, this can be done using the errorExchange
:
import { errorExchange } from 'urql';
errorExchange({
onError: (error) => {
const isAuthError = error.graphQLErrors.some(
e => e.extensions?.code === 'FORBIDDEN',
);
if (isAuthError) {
}
}
}),