Authentication
Build your own authentication system from scratch with complete control over implementation
Build your own authentication system from scratch with complete control over implementation. This collection provides authentication components and utilities that you can customize to fit your exact requirements, supporting multiple database adapters and OAuth providers.
Installation
CLI
Install core utilities
This will install the main authentication package along with required dependencies.
npx shadcn add https://yuki-ui.vercel.app/r/auth-session.jsonnpx shadcn add https://yuki-ui.vercel.app/r/auth-session.jsonpnpm dlx shadcn add https://yuki-ui.vercel.app/r/auth-session.jsonbunx --bun shadcn add https://yuki-ui.vercel.app/r/auth-session.jsonnpx shadcn add https://yuki-ui.vercel.app/r/auth-jwt.jsonnpx shadcn add https://yuki-ui.vercel.app/r/auth-jwt.jsonpnpm dlx shadcn add https://yuki-ui.vercel.app/r/auth-jwt.jsonbunx --bun shadcn add https://yuki-ui.vercel.app/r/auth-jwt.jsonInstall database adapter
Choose and install a database adapter that matches your database technology.
npx shadcn add https://yuki-ui.vercel.app/r/auth-adapter-drizzle.jsonnpx shadcn add https://yuki-ui.vercel.app/r/auth-adapter-drizzle.jsonpnpm dlx shadcn add https://yuki-ui.vercel.app/r/auth-adapter-drizzle.jsonbunx --bun shadcn add https://yuki-ui.vercel.app/r/auth-adapter-drizzle.jsonnpx shadcn add https://yuki-ui.vercel.app/r/auth-adapter-prisma.jsonnpx shadcn add https://yuki-ui.vercel.app/r/auth-adapter-prisma.jsonpnpm dlx shadcn add https://yuki-ui.vercel.app/r/auth-adapter-prisma.jsonbunx --bun shadcn add https://yuki-ui.vercel.app/r/auth-adapter-prisma.jsonnpx shadcn add https://yuki-ui.vercel.app/r/auth-adapter-mongoose.jsonnpx shadcn add https://yuki-ui.vercel.app/r/auth-adapter-mongoose.jsonpnpm dlx shadcn add https://yuki-ui.vercel.app/r/auth-adapter-mongoose.jsonbunx --bun shadcn add https://yuki-ui.vercel.app/r/auth-adapter-mongoose.jsonManual
Download and customize the source code directly from the registry: Source
Quick Start
-
Configure Authentication
Edit a configuration file to define your authentication settings, including secret keys, OAuth providers, and database adapters.
server/auth/config.ts import type { AuthConfig } from '@/server/auth/types' export const authConfig = { secret: process.env.AUTH_SECRET, providers: [ // Add OAuth providers here ], // This will be implemented after installing a database adapter adapter: { user: {}, account: {}, session: {}, // Only for session-based auth }, } as const satisfies AuthConfigSet environment variables for your secret key and OAuth provider credentials.
.env # You can generate a secure random key using `openssl rand -base64 32` AUTH_SECRET=your-secret-key # OAuth provider credentials AUTH_{PROVIDER}_ID=your-client-id AUTH_{PROVIDER}_SECRET=your-client-secretSupported OAuth Providers:
- Discord
- Figma
- Github
- Vercel
You can add custom providers by implementing the
BaseProviderabstract class. -
Create API Route
To handle authentication requests, create an API route in your server framework of choice and export the
handlerfunction from the authentication package.app/api/auth/[...auth]/route.ts export { handler as GET, handler as POST, handler as OPTIONS, } from '@/server/auth'- Export api route handlers
app/routes/api/auth.ts import type { Route } from './+types/auth' import { handler } from '@/server/auth' export const loader = ({ request }: Route.LoaderArgs) => handler(request) export const action = ({ request }: Route.ActionArgs) => handler(request)- Register route
app/routes.ts import type { RouteConfig } from '@react-router/dev/routes' import { route } from '@react-router/dev/routes' export default [ route('/api/auth/*', './routes/api/auth'), // ...other routes ] satisfies RouteConfigsrc/routes/api/auth.$.ts import { createFileRoute } from '@tanstack/react-router' import { handler } from '@/server/auth' export const Route = createFileRoute('/api/auth/$')({ server: { handlers: { GET: async ({ request }) => handler(request), POST: async ({ request }) => handler(request), OPTIONS: async ({ request }) => handler(request), }, }, })src/routes/api/auth.ts import { Router } from 'express' import { handler } from '@/server/auth' const authRouter = Router() router.use('/api/auth/*', async (req, res) => { const response = handler(req) res.status(response.status) response.headers.forEach((value, key) => { res.setHeader(key, value) }) if (response.status === 204) return res.send() if (response.status === 302 && response.headers.get('Location')) return res.redirect(response.headers.get('Location')) const contentType = response.headers.get('content-type') ?? '' if (contentType.includes('application/json')) { const body = await response.json() return res.json(body) } else { const body = await response.text() return res.send(body) } res.send(body) }) export { authRouter }src/routes/auth.ts import { Elysia } from 'elysia' import { handler } from '@/server/auth' export const authRouter = new Elysia({ name: 'Auth Router' }).all( '/api/auth/*', ({ request }) => handler(request), )server/api/auth/[...auth].ts import { handler } from '@/server/auth' export default defineEventHandler(event => handler(event.node.req)) -
Set Up Query Client and Providers
Configure React Query and session providers for your application. This ensures efficient data fetching, caching, and session management across your app.
lib/query-client.ts import { defaultShouldDehydrateQuery, QueryClient, } from '@tanstack/react-query' export const createQueryClient = () => new QueryClient({ defaultOptions: { queries: { // With SSR, we usually want to set some default staleTime // above 0 to avoid refetching immediately on the client staleTime: 60 * 1000, }, dehydrate: { shouldDehydrateQuery: (query) => defaultShouldDehydrateQuery(query) || query.state.status === 'pending', }, hydrate: {}, }, })components/providers.tsx 'use client' import type { QueryClient } from '@tanstack/react-query' import { QueryClientProvider } from '@tanstack/react-query' import { SessionProvider } from '@/hooks/use-session' import { createQueryClient } from '@/lib/query-client' let clientQueryClientSingleton: QueryClient | undefined = undefined const getQueryClient = () => { if (typeof window === 'undefined') return createQueryClient() else return (clientQueryClientSingleton ??= createQueryClient()) } export function Providers({ children, }: Readonly<{ children: React.ReactNode }>) { const queryClient = getQueryClient() return ( <QueryClientProvider client={queryClient}> <SessionProvider>{children}</SessionProvider> </QueryClientProvider> ) }
Conclusion
With these steps, you have set up a customizable authentication system in your application. You can now extend and modify the components and utilities to fit your specific needs, ensuring a secure and efficient authentication process for your users.