diff --git a/src/lib/auth.functions.ts b/src/lib/auth.functions.ts index 4cb1836..7226ad1 100644 --- a/src/lib/auth.functions.ts +++ b/src/lib/auth.functions.ts @@ -1,8 +1,16 @@ -import { createServerFn } from "@tanstack/react-start"; +import { createMiddleware, createServerFn } from "@tanstack/react-start"; import { redirect } from "@tanstack/react-router"; import { oauth } from "./atproto.server"; import { clearAppSession, useAppSession } from "./auth.server"; +export const authMiddleware = createMiddleware({ type: 'function' }).server( + async ({ next }) => { + const session = await useAppSession(); + if (!session.data) throw new Error('Unauthorized') + return next() + }, +) + export const loginFn = createServerFn({ method: "POST" }) .validator((data: { handle: string }) => { if (typeof data.handle !== "string" || !data.handle.trim()) { @@ -17,12 +25,14 @@ export const loginFn = createServerFn({ method: "POST" }) }); export const getCurrentUserFn = createServerFn({ method: "GET" }) + .middleware([authMiddleware]) .handler(async () => { const session = await useAppSession(); return session.data.did; }); export const logoutFn = createServerFn({ method: "POST" }) + .middleware([authMiddleware]) .handler(async () => { await clearAppSession(); throw redirect({ reloadDocument: true }); diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts index 73e066f..f729137 100644 --- a/src/routeTree.gen.ts +++ b/src/routeTree.gen.ts @@ -10,6 +10,8 @@ import { Route as rootRouteImport } from './routes/__root' import { Route as IndexRouteImport } from './routes/index' +import { Route as AuthedRouteRouteImport } from './routes/_authed/route' +import { Route as AuthedSettingsRouteImport } from './routes/_authed/settings' import { Route as OauthClientMetadataJsonRouteImport } from './routes/oauth-client-metadata.json' import { Route as OauthCallbackRouteImport } from './routes/oauth/callback' @@ -18,6 +20,15 @@ const IndexRoute = IndexRouteImport.update({ path: '/', getParentRoute: () => rootRouteImport, } as any) +const AuthedRouteRoute = AuthedRouteRouteImport.update({ + id: '/_authed', + getParentRoute: () => rootRouteImport, +} as any) +const AuthedSettingsRoute = AuthedSettingsRouteImport.update({ + id: '/settings', + path: '/settings', + getParentRoute: () => AuthedRouteRoute, +} as any) const OauthClientMetadataJsonRoute = OauthClientMetadataJsonRouteImport.update({ id: '/oauth-client-metadata/json', path: '/oauth-client-metadata/json', @@ -31,30 +42,42 @@ const OauthCallbackRoute = OauthCallbackRouteImport.update({ export interface FileRoutesByFullPath { '/': typeof IndexRoute + '/settings': typeof AuthedSettingsRoute '/oauth-client-metadata/json': typeof OauthClientMetadataJsonRoute '/oauth/callback': typeof OauthCallbackRoute } export interface FileRoutesByTo { '/': typeof IndexRoute + '/settings': typeof AuthedSettingsRoute '/oauth-client-metadata/json': typeof OauthClientMetadataJsonRoute '/oauth/callback': typeof OauthCallbackRoute } export interface FileRoutesById { __root__: typeof rootRouteImport '/': typeof IndexRoute + '/_authed': typeof AuthedRouteRouteWithChildren + '/_authed/settings': typeof AuthedSettingsRoute '/oauth-client-metadata/json': typeof OauthClientMetadataJsonRoute '/oauth/callback': typeof OauthCallbackRoute } export interface FileRouteTypes { fileRoutesByFullPath: FileRoutesByFullPath - fullPaths: '/' | '/oauth-client-metadata/json' | '/oauth/callback' + fullPaths: + '/' | '/settings' | '/oauth-client-metadata/json' | '/oauth/callback' fileRoutesByTo: FileRoutesByTo - to: '/' | '/oauth-client-metadata/json' | '/oauth/callback' - id: '__root__' | '/' | '/oauth-client-metadata/json' | '/oauth/callback' + to: '/' | '/settings' | '/oauth-client-metadata/json' | '/oauth/callback' + id: + | '__root__' + | '/' + | '/_authed' + | '/_authed/settings' + | '/oauth-client-metadata/json' + | '/oauth/callback' fileRoutesById: FileRoutesById } export interface RootRouteChildren { IndexRoute: typeof IndexRoute + AuthedRouteRoute: typeof AuthedRouteRouteWithChildren OauthClientMetadataJsonRoute: typeof OauthClientMetadataJsonRoute OauthCallbackRoute: typeof OauthCallbackRoute } @@ -68,6 +91,20 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRouteImport } + '/_authed': { + id: '/_authed' + path: '' + fullPath: '/' + preLoaderRoute: typeof AuthedRouteRouteImport + parentRoute: typeof rootRouteImport + } + '/_authed/settings': { + id: '/_authed/settings' + path: '/settings' + fullPath: '/settings' + preLoaderRoute: typeof AuthedSettingsRouteImport + parentRoute: typeof AuthedRouteRoute + } '/oauth-client-metadata/json': { id: '/oauth-client-metadata/json' path: '/oauth-client-metadata/json' @@ -85,8 +122,21 @@ declare module '@tanstack/react-router' { } } +interface AuthedRouteRouteChildren { + AuthedSettingsRoute: typeof AuthedSettingsRoute +} + +const AuthedRouteRouteChildren: AuthedRouteRouteChildren = { + AuthedSettingsRoute: AuthedSettingsRoute, +} + +const AuthedRouteRouteWithChildren = AuthedRouteRoute._addFileChildren( + AuthedRouteRouteChildren, +) + const rootRouteChildren: RootRouteChildren = { IndexRoute: IndexRoute, + AuthedRouteRoute: AuthedRouteRouteWithChildren, OauthClientMetadataJsonRoute: OauthClientMetadataJsonRoute, OauthCallbackRoute: OauthCallbackRoute, } diff --git a/src/routes/__root.tsx b/src/routes/__root.tsx index 843b0b2..ed66b1e 100644 --- a/src/routes/__root.tsx +++ b/src/routes/__root.tsx @@ -42,16 +42,20 @@ function RootDocument({ children }: { children: React.ReactNode }) { - { did - ? ( -
-

Logged in - {did}

- -
- ) : - } + {children} { + const user = await getCurrentUserFn(); + if (!user) { + throw new Error("Unauthorized"); + } + }, + errorComponent: ({ error }) => ( +
+

Error

+ {error.message} +
+ ), + component: RouteComponent, +}) + +function RouteComponent() { + return
Hello "/_authed"!
+} diff --git a/src/routes/_authed/settings.tsx b/src/routes/_authed/settings.tsx new file mode 100644 index 0000000..b5f99ac --- /dev/null +++ b/src/routes/_authed/settings.tsx @@ -0,0 +1,14 @@ +import { createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/_authed/settings')({ + component: RouteComponent, +}) + +function RouteComponent() { + return ( +
+

Settings

+

You are seeing this page because you are logged in!

+
+ ) +}