feat(client): refactor auth/login
Signed-off-by: Noa Virellia <noa@requiem.garden>
This commit is contained in:
@@ -7,7 +7,7 @@ export const Route = createFileRoute('/_sidebarLayout/')({
|
||||
loader: async () => {
|
||||
if (!hasToken()) {
|
||||
throw redirect({
|
||||
to: '/login',
|
||||
to: '/authorize',
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
42
client/src/routes/authorize.tsx
Normal file
42
client/src/routes/authorize.tsx
Normal file
@@ -0,0 +1,42 @@
|
||||
import { createFileRoute } from '@tanstack/react-router';
|
||||
import { zodValidator } from '@tanstack/zod-adapter';
|
||||
import z from 'zod';
|
||||
import { LoginForm } from '@/components/login-form';
|
||||
import { generateOAuthState } from '@/lib/random';
|
||||
import { getToken } from '@/lib/token';
|
||||
|
||||
const authorizeSchema = z.object({
|
||||
response_type: z.literal('code').default('code'),
|
||||
client_id: z.literal('org_client').default('org_client'),
|
||||
redirect_uri: z.string().default(`${new URL(import.meta.env.VITE_APP_BASE_URL as string).toString()}token`),
|
||||
state: z.string().default(generateOAuthState()),
|
||||
});
|
||||
|
||||
export type AuthorizeSearchParams = z.infer<typeof authorizeSchema>;
|
||||
|
||||
export const Route = createFileRoute('/authorize')({
|
||||
component: RouteComponent,
|
||||
validateSearch: zodValidator(authorizeSchema),
|
||||
});
|
||||
|
||||
function RouteComponent() {
|
||||
const token = getToken();
|
||||
const oauthParams = Route.useSearch();
|
||||
if (token !== null) {
|
||||
const base = new URL(window.location.origin);
|
||||
const url = new URL('/api/v1/auth/redirect', base);
|
||||
url.searchParams.set('client_id', oauthParams.client_id);
|
||||
url.searchParams.set('response_type', oauthParams.response_type);
|
||||
url.searchParams.set('redirect_uri', oauthParams.redirect_uri);
|
||||
url.searchParams.set('state', oauthParams.state);
|
||||
window.location.href = url.toString();
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<div className="bg-background flex min-h-svh flex-col items-center justify-center gap-6 p-6 md:p-10">
|
||||
<div className="w-full max-w-sm">
|
||||
<LoginForm oauthParams={oauthParams} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
import { createFileRoute, Navigate } from '@tanstack/react-router';
|
||||
import { zodValidator } from '@tanstack/zod-adapter';
|
||||
import z from 'zod';
|
||||
import { LoginForm } from '@/components/login-form';
|
||||
import { useValidateMagicLink } from '@/hooks/data/useValidateMagicLink';
|
||||
import { setRefreshToken, setToken } from '@/lib/token';
|
||||
|
||||
const loginMagicLinkReceiverSchema = z.object({
|
||||
ticket: z.string().optional(),
|
||||
});
|
||||
|
||||
export const Route = createFileRoute('/login')({
|
||||
component: RouteComponent,
|
||||
validateSearch: zodValidator(loginMagicLinkReceiverSchema),
|
||||
});
|
||||
|
||||
function ReceiveMagicLinkComponent() {
|
||||
const { ticket } = Route.useSearch();
|
||||
const { data } = useValidateMagicLink(ticket!);
|
||||
|
||||
setToken(data.data.access_token);
|
||||
setRefreshToken(data.data.refresh_token);
|
||||
|
||||
return <Navigate to="/" />;
|
||||
}
|
||||
|
||||
function RouteComponent() {
|
||||
const { ticket } = Route.useSearch();
|
||||
return (
|
||||
<div className="bg-background flex min-h-svh flex-col items-center justify-center gap-6 p-6 md:p-10">
|
||||
<div className="w-full max-w-sm">
|
||||
{ticket === undefined ? <LoginForm /> : <ReceiveMagicLinkComponent />}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
25
client/src/routes/token.tsx
Normal file
25
client/src/routes/token.tsx
Normal file
@@ -0,0 +1,25 @@
|
||||
import { createFileRoute, useNavigate } from '@tanstack/react-router';
|
||||
import { useState } from 'react';
|
||||
import z from 'zod';
|
||||
import { doSetTokenByCode } from '@/lib/token';
|
||||
|
||||
const tokenCodeSchema = z.object({
|
||||
code: z.string().nonempty(),
|
||||
});
|
||||
|
||||
export const Route = createFileRoute('/token')({
|
||||
component: RouteComponent,
|
||||
validateSearch: tokenCodeSchema,
|
||||
});
|
||||
|
||||
function RouteComponent() {
|
||||
const { code } = Route.useSearch();
|
||||
const [status, setStatus] = useState('Loading...');
|
||||
const navigate = useNavigate();
|
||||
doSetTokenByCode(code).then(() => {
|
||||
void navigate({ to: '/' });
|
||||
}).catch((_) => {
|
||||
setStatus('Error getting token');
|
||||
});
|
||||
return <div>{status}</div>;
|
||||
}
|
||||
Reference in New Issue
Block a user