T
TanStack•3mo ago
flat-fuchsia

How to protect server functions?

Hi! I'm using the start-clerk-basic example (https://github.com/TanStack/router/tree/main/examples/react/start-clerk-basic) to start a project and I can see how we can require authentication on the front-end, but if I try to call the endpoint generated by the server function on Postman, it works even without login. What would be the best practice to do this with a global middleware? Any examples?
GitHub
router/examples/react/start-clerk-basic at main · TanStack/router
🤖 Fully typesafe Router for React (and friends) w/ built-in caching, 1st class search-param APIs, client-side cache integration and isomorphic rendering. - TanStack/router
12 Replies
useful-bronze
useful-bronze•3mo ago
I might be misinterpretting, but I just add a throw redirect for each server function:
export const fetchClerkAuth = createServerFn({
method: "GET",
}).handler(async () => {
const { userId } = await getAuth(getWebRequest());

if (!userId) {
throw redirect({
to: "/sign-in/$",
});
}
});
export const fetchClerkAuth = createServerFn({
method: "GET",
}).handler(async () => {
const { userId } = await getAuth(getWebRequest());

if (!userId) {
throw redirect({
to: "/sign-in/$",
});
}
});
eastern-cyan
eastern-cyan•3mo ago
or make a middleware that does exactly that
flat-fuchsia
flat-fuchsiaOP•3mo ago
Well that's the thing. I don't want to do that manually for every function and global middleware doing that seems to not be working. Any examples of working code?
eastern-cyan
eastern-cyan•3mo ago
No description
eastern-cyan
eastern-cyan•3mo ago
No description
eastern-cyan
eastern-cyan•3mo ago
no need for a global middleware here just use the middleware when necessary and if you really want it do work globally create a src/global-middleware.ts
import { registerGlobalMiddleware } from '@tanstack/react-start'
import { $$auth } from '...'

registerGlobalMiddleware({
middleware: [$$auth],
})
import { registerGlobalMiddleware } from '@tanstack/react-start'
import { $$auth } from '...'

registerGlobalMiddleware({
middleware: [$$auth],
})
flat-fuchsia
flat-fuchsiaOP•3mo ago
Thanks for the example! Seems that there is an issue with the file global-middleware.ts on Windows systems. I have that exact same file and for some weird reason it doesn't work =/ Can you also share your "badRequest" helper, please? I liked the idea 🙂
eastern-cyan
eastern-cyan•3mo ago
try importing it somewhere in your app at least once as in import '@/global-middleware'
import { json } from '@tanstack/react-start'
import type { Range } from '@/lib/utils/types'

export function badRequest(
message: any,
status: Range<400, 499>,
data?: any,
): never {
throw json({ error: message, data }, { status })
}

export function serverError(
message: any,
status: Range<500, 599>,
data?: any,
): never {
throw json({ error: message, data }, { status })
}
import { json } from '@tanstack/react-start'
import type { Range } from '@/lib/utils/types'

export function badRequest(
message: any,
status: Range<400, 499>,
data?: any,
): never {
throw json({ error: message, data }, { status })
}

export function serverError(
message: any,
status: Range<500, 599>,
data?: any,
): never {
throw json({ error: message, data }, { status })
}
here's the Range helper type if you want
export type Enumerate<
N extends number,
Acc extends number[] = [],
> = Acc['length'] extends N
? Acc[number]
: Enumerate<N, [...Acc, Acc['length']]>

export type Range<Min extends number, Max extends number> = Exclude<
Enumerate<Max>,
Enumerate<Min>
>
export type Enumerate<
N extends number,
Acc extends number[] = [],
> = Acc['length'] extends N
? Acc[number]
: Enumerate<N, [...Acc, Acc['length']]>

export type Range<Min extends number, Max extends number> = Exclude<
Enumerate<Max>,
Enumerate<Min>
>
flat-fuchsia
flat-fuchsiaOP•3mo ago
Importing manually with import '@/global-middleware' worked! Thanks for the helper funcions, very nice. I appreciate the help, thank you very much!
foreign-sapphire
foreign-sapphire•3mo ago
Wow, this is some TS wizardry! Very interesting!
eastern-cyan
eastern-cyan•3mo ago
haha yes, there's definitely some mental gymnastics
genetic-orange
genetic-orange•2mo ago
BTW, importing global middleware does work but if you need both .client and .server I had to do it server side and client side to get both working. So I did in ssr.tsx and router.tsx. I believe they are working on a proper registration for it.

Did you find this page helpful?