Sica / Ben
Sica / Ben3d ago

Auth Headers in Singleton Pattern

The recommended approach for setting up a SPA with tRPC is to use the Singleton Pattern (source). However, many authentication libraries rely on providers and hooks to supply the authenticated user, meaning the access_token is only accessible within React land. Given this, what is the recommended method to include the access_token in the tRPC headers? Can this be achieved using the Singleton Pattern, or is it necessary to use TRPCProvider instead?
Solution:
GitHub
Introducing the new TanStack React Query integration · trpc trpc · ...
We are excited to announce the new TanStack React Query integration for tRPC is now available on tRPC's next-release. Compared to our classic React Query Integration it's simpler and more T...
Jump to solution
4 Replies
bill92
bill923d ago
I agree with this one, I rely on a hook from clerk to get the token
const { getToken } = useAuth();
const { getToken } = useAuth();
now I can't use it and pass it on to my headers what would be the recommended approach?
Solution
bill92
bill922d ago
GitHub
Introducing the new TanStack React Query integration · trpc trpc · ...
We are excited to announce the new TanStack React Query integration for tRPC is now available on tRPC's next-release. Compared to our classic React Query Integration it's simpler and more T...
bill92
bill922d ago
👍 I was able to implement it
skylerdj
skylerdj2d ago
Since you're using a SPA with something like vite, you can use something like jotai so you can access the token from both inside and outside of react doing something like this: 1. first create the token atom
import { getDefaultStore } from "jotai";

// if you're using a JotaiProvider in your app, you need to pass the store to the provider using createStore instead, otherwise this is fine
const jotaiStore = getDefaultStore();

const authTokenAtom = atom<string|undefined>(undefined);

/** Used to get and set the auth token outside of the react tree */
export const getAuthToken = () => jotaiStore.get(authTokenAtom);
export const setAuthToken = (token:string) => jotaiStore.set(authTokenAtom, token);

// optional since you already have a hook to use from your own auth provider, but it helps having a single source of truth in your app
/** Used to get the auth token inside of the react tree to listen to changes and trigger re-renders */
export const useAuthToken = () => useAtom(authTokenAtom);
export const useSetAuthToken = () => useSetAtom(authTokenAtom);
import { getDefaultStore } from "jotai";

// if you're using a JotaiProvider in your app, you need to pass the store to the provider using createStore instead, otherwise this is fine
const jotaiStore = getDefaultStore();

const authTokenAtom = atom<string|undefined>(undefined);

/** Used to get and set the auth token outside of the react tree */
export const getAuthToken = () => jotaiStore.get(authTokenAtom);
export const setAuthToken = (token:string) => jotaiStore.set(authTokenAtom, token);

// optional since you already have a hook to use from your own auth provider, but it helps having a single source of truth in your app
/** Used to get the auth token inside of the react tree to listen to changes and trigger re-renders */
export const useAuthToken = () => useAtom(authTokenAtom);
export const useSetAuthToken = () => useSetAtom(authTokenAtom);
2. then sync the token atom with your hook
// CALL THIS ONCE IN YOUR APP SOMEWHERE
export const useSyncAuthTokenAtom = () => {
// get the user from your auth provider
const user = useAuth();
const setAuthToken = useSetAuthToken();

useEffect(() => {
setAuthToken(user.access_token)
},[setAuthTokem, user.access_to])
}
// CALL THIS ONCE IN YOUR APP SOMEWHERE
export const useSyncAuthTokenAtom = () => {
// get the user from your auth provider
const user = useAuth();
const setAuthToken = useSetAuthToken();

useEffect(() => {
setAuthToken(user.access_token)
},[setAuthTokem, user.access_to])
}
3. Then in your react app you can use either the useAuthToken to use the atom as a single source of truth or just keep using your provider hook 4. For outside of react like trpc or api calls, you can just call the getAuthToken function which will retreive the value from the atom
import {getAuthToken} from "@src/utils/token"

headers: () => {
return {
"Authorization": `Bearer ${getAuthToken}`
}
}
import {getAuthToken} from "@src/utils/token"

headers: () => {
return {
"Authorization": `Bearer ${getAuthToken}`
}
}
There's also a simplified version of this if you don't care about using a single source of truth and don't already have jotai in your app and don't want to add it, using regular js, but i recommend the first approach
// use this to access the auth token outside of your react app
let authToken = undefined;
const getAuthToken = () => authToken;

// CALL THIS ONCE IN YOUR APP SOMEWHERE
export const useSyncAuthTokenAtom = () => {
// get the user from your auth provider
const user = useAuth();

useEffect(() => {
authToken = user.access_token
},[user.access_to])
}
// use this to access the auth token outside of your react app
let authToken = undefined;
const getAuthToken = () => authToken;

// CALL THIS ONCE IN YOUR APP SOMEWHERE
export const useSyncAuthTokenAtom = () => {
// get the user from your auth provider
const user = useAuth();

useEffect(() => {
authToken = user.access_token
},[user.access_to])
}
then in the trpc singleton you can just the authToken directly
import { getAuthToken } from "@src/utils/token"

headers: () => {
return {
"Authorization": `Bearer ${getAuthToken}`
}
}
import { getAuthToken } from "@src/utils/token"

headers: () => {
return {
"Authorization": `Bearer ${getAuthToken}`
}
}

Did you find this page helpful?