Skip to content

Instantly share code, notes, and snippets.

@caesaneer
Last active December 28, 2022 03:19
Show Gist options
  • Save caesaneer/29a5200f0521feb215364b4f144912f5 to your computer and use it in GitHub Desktop.
Save caesaneer/29a5200f0521feb215364b4f144912f5 to your computer and use it in GitHub Desktop.
urql client using Mitt to receive authState changes from Firebase onAuthStateChanged
// URQL
import { makeOperation, fetchExchange } from '@urql/core';
import { createClient } from '@urql/svelte';
import { authExchange } from '@urql/exchange-auth';
import type { ClientOptions, Operation } from '@urql/svelte';
// MITT
import mitt from 'mitt';
type AuthState = {
accessToken?: string;
refreshToken?: string;
tokenExpiry?: string;
};
// export emitter so it can be used by Firebase onAuthStateChanged
export const authEmitter = mitt();
function newUrqlClient() {
let initialized = false;
// getAuth option is used to fetch the initial auth state.
const getAuth = async ({
authState
}: {
authState?: AuthState | null;
}): Promise<AuthState | null> => {
if (!authState) {
const authState: AuthState = {};
if (!initialized) {
initialized = true;
// set authEmitter to update authState when token changes
authEmitter.on('token', (token) => {
console.log('UPDATED URQL AUTH TOKEN');
authState.accessToken = token as string;
});
}
return authState;
}
return null;
};
// the purpose of addAuthToOperation is to apply an auth state to each request.
// the shape of authState is based on the returned value of getAuth.
const addAuthToOperation = ({
authState,
operation
}: {
authState: AuthState;
operation: Operation;
}) => {
// return if authState is not set
if (!authState || !authState.accessToken) {
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.accessToken
}
}
});
};
const urqlClientBaseConfig: ClientOptions = {
url: 'http://localhost:8080/graphql',
exchanges: [
authExchange({
addAuthToOperation,
getAuth,
fetchExchange
})
]
};
return createClient({
...urqlClientBaseConfig
});
}
export const urqlClient = newUrqlClient();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment