#Handling High Level Auth With Hooks

64 messages · Page 1 of 1 (latest)

merry trout
#

👋 @frail carbon so like i was getting at on twitter, I've been trying to figure out the right way to go about setting up auth with the router when doing something like the below. The example in the docs was fairly static, so was trying to figure out a larger solution. I've tried various things with beforeLoad and with context, but haven't been able to nail it down.

I've reeled back the below to a simple base that works, but needs to be cleaned up to a proper setup. Any thoughts on a best approach here? I'm fine redirecting to that login path when a route is unauthorized or a login page i can pretty up -- either works for me.

Happy to provide more code, it's just hard to get something fully running on code sandbox since i'm using an IDP in docker for the auth.

https://gist.github.com/pdevito3/190bff13bdf237fd285ec02735c03b6b

Gist

Tanstack Router Base WIP. GitHub Gist: instantly share code, notes, and snippets.

frail carbon
#

I’ll look at this tonight

frail carbon
#

What are you building with it?

merry trout
#

It’s just a vanilla vite app

#

Using .NET for the BFF side of things

frail carbon
#

Woo!

merry trout
#

just realized my brain switched with it to it with lol. Trying to get a SPA template down for my OSS and want to dogfood a complete LIMS app for it (lab management software) since i have a long background there.

steep fulcrum
#

You don't need to create components for layouts create a route with id instead of path and use that as layout less imports and just make auth check there for all the child routes

frail carbon
#

@merry trout did you see that example?

merry trout
#

yeah, but how can i get isAuthenticated? i can't use my hook there

steep fulcrum
merry trout
#

i'll give it another whirl, might just need fresh eyes

steep fulcrum
merry trout
steep fulcrum
# merry trout hadn't seen this portion before. nice to see, but how does something like the be...

Route paths are used to match parts of a URL's pathname to a route. At their core, route paths are just strings and can be defined using a variety of syntaxes, each with different behaviors. Before we get into those behaviors, lets look at a few important cross-cutting path concerns.

Leading and Trailing Slashes

frail carbon
#

You pass a component with it

steep fulcrum
#

component: () => <Outlet />

#

or whatever you want like a navy bar something

merry trout
#

ah i had errors when i tried it but i hadn't changed children to outlet

#

duh

#

makes sense

#

cool i'll give the auth piece another whirl and ping yall

steep fulcrum
#

one with loaders and one with hooks

merry trout
#

would love to take a peek if you're able

steep fulcrum
merry trout
#

🍻

steep fulcrum
#

forgot about this one

#

that is based on nextjs app router pattern

merry trout
#

FYI (and i very well could have missed it in the docs), but for the layout stuff, it wasn't clear to me that i needed to nest this add children. your layout repo helped 🙂

const authLayout = new Route({
  getParentRoute: () => appRoute,
  id: "auth-layout",
  component: AuthLayout,
});

const indexRoute = new Route({
  getParentRoute: () => authLayout,
  path: "/",
  component: IndexPage,
});

const orderRoute = new Route({
  getParentRoute: () => authLayout,
  path: "/orders",
  component: OrdersPage,
});

// Create the route tree using your routes
const routeTree = appRoute.addChildren([
  authLayout.addChildren([indexRoute, orderRoute]),
]);
#

about to dig through the auth stuff now

frail carbon
#

This is where a file based router would help a lot

steep fulcrum
merry trout
#

so i have my layout and auth hook like below (route tree above), but i'm having a couple problem:

  1. every page navigation is triggering the loading. shouldn't it just be replacing the nested outlet and not causing a refetch?
  2. trying to handle the unauthenticated path, but if i reroute it just gets in an infinite loop of not logged out even when i am (i think from the initial render where it hasn't got the data yet) i was able to do this in the api on error

any thoughts?

export default function AuthLayout() {
  const { isLoggedIn, user, logoutUrl, isLoading } = useAuthUser();
  if (isLoading) return <Loading />;

  return (
    <>
      <div>
        <DesktopMenu user={user} logoutUrl={logoutUrl} />

        <div className="sticky top-0 z-40 flex items-center px-4 py-4 bg-white shadow-sm gap-x-6 sm:px-6 lg:hidden">
          <div className="flex-1 text-sm font-semibold leading-6 text-primary">
            Peak LIMS
          </div>

          <ProfileManagement user={user} logoutUrl={logoutUrl} />
        </div>

        <main className="py-10 lg:pl-72">
          <div className="px-4 sm:px-6 lg:px-8">
            <Outlet />
          </div>
        </main>

        <MobileMenu />
      </div>
    </>
  );
}
const fetchClaims = async () =>
  axios.get("/bff/user", config).then((res) => res.data);

function useClaims() {
  return useQuery(
    claimsKeys.claim,
    async () => {
      const delay = new Promise((resolve) => setTimeout(resolve, 550));
      return Promise.all([fetchClaims(), delay]).then(([claims]) => claims);
    },
    {
      retry: false,
    }
  );
}

function useAuthUser() {
  const { data: claims, isLoading, isError } = useClaims();
  if (isError) window.location.href = "/bff/login";

  // does claims things

  return {
    user,
    logoutUrl: logoutUrl?.value ?? undefined,
    isLoading,
    isLoggedIn,
  };
}

export { useAuthUser };
merry trout
#

ooo wait, i still have anchor tags in my nav. i bet that's it

#

was updating my mobile nav for a hot minute, but once i updated desktop that did it 🚀 lol

#

i am seeing this typescript unhappiness on Link though

Property 'search' is missing in type '{ children: (string | Element)[]; to: string; className: string; }' but required in type '{ search: SearchReducer<Partial<{}>, Partial<{}> & Partial<{}> & Omit<never, never>>; }'.ts(2741)
#
                    <Link
                      to={item.href}
                      className={cn(
                        item.current
                          ? "bg-gray-50 text-foreground"
                          : "text-gray-700 hover:text-foreground hover:bg-gray-50",
                        "group flex gap-x-3 rounded-md p-2 text-sm leading-6 font-semibold"
                      )}
                    >
                      <item.icon
                        className={cn(
                          item.current
                            ? "text-foreground"
                            : "text-gray-400 group-hover:text-foreground",
                          "h-6 w-6 shrink-0"
                        )}
                        aria-hidden="true"
                      />
                      {item.name}
                    </Link>
frail carbon
#

Do one of the links in your navigation require search parameters?

merry trout
#

not as of yet but they very well could.

i tweaked the desktop ones to look more like this atm. mobile ones need a little extra love with useNavigate to close the mobile menu on nav

                    <Link
                      to={item.href}
                      className={cn(
                        "text-gray-700 hover:text-foreground hover:bg-gray-50",
                        "group flex gap-x-3 rounded-md p-2 text-sm leading-6 font-semibold"
                      )}
                      activeProps={{
                        className: "bg-card text-emerald-500",
                      }}
                    >
                      <item.icon
                        className={cn("h-6 w-6 shrink-0")}
                        aria-hidden="true"
                      />
                      {item.name}
                    </Link>
#

disregard my mixed colors. still need to figure out this shadcn setup lol

steep fulcrum
#

can you share snippet for type of item.href

steep fulcrum
steep fulcrum
steep fulcrum
#

fix and you get intellisesnse ⬇️

#
import type { ReactNode } from "react";
import { Link } from "@tanstack/react-router";
import type { RegisteredRoutesInfo } from "@tanstack/react-router";

export function NavLink(item: {
  href: RegisteredRoutesInfo["routePaths"];
  name: ReactNode | string;
}) {
  return <Link to={item.href}>{item.name}</Link>;
}
merry trout
#

Yeah makes sense. Was going to try something along those lines but need to refactor a bit given my nav setup

#

The error didn’t hint at that at all 😂

merry trout
#

confirmed fixed

#

thanks again

brazen imp
# steep fulcrum or this ⬇️ https://tanstack.com/router/v1/docs/guide/authenticated-routes

hi Bachitter, hope you dont mind me reviving an old thread but I have the exact same question as OP. I wanted to ask,is the alternative You don't need to create components for layouts create a route with id instead of path and use that as layout less imports and just make auth check there for all the child routes comparable to checking auth in route.beforeLoad? Are there any tradeoffs?

steep fulcrum
brazen imp
steep fulcrum
brazen imp
steep fulcrum
#

as the repos were using early beta version

thin cobalt
#

Hey, looking for examples on auth also. Trying to implement oAuth flow and my api call in the auth callback page's loader is being called twice 🤷‍♂️ Was hoping to see some more examples of auth in TSRouter. Do you happen to have any time to upload those example?