Skip to content

Commit

Permalink
feat(api/auth): create initial auth library
Browse files Browse the repository at this point in the history
  • Loading branch information
JowiAoun committed Sep 17, 2024
1 parent f11601c commit 8d12715
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 1 deletion.
49 changes: 49 additions & 0 deletions libs/api/src/trpc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { TRPCError, initTRPC } from '@trpc/server'
import superjson from 'superjson'
import { ZodError } from 'zod'

import { auth } from '@cuhacking/auth'
import { db } from '@cuhacking/db'

export async function createTRPCContext(opts: { headers: Headers }) {
const { session, user } = await auth()

return {
db,
session,
user,
...opts,
}
}

const t = initTRPC.context<typeof createTRPCContext>().create({
transformer: superjson,
errorFormatter({ shape, error }) {
return {
...shape,
data: {
...shape.data,
zodError:
error.cause instanceof ZodError ? error.cause.flatten() : null,
},
}
},
})
export const createCallerFactory = t.createCallerFactory

export const createRouter = t.router

export const publicProcedure = t.procedure

export const protectedProcedure = t.procedure.use(({ ctx, next }) => {
if (!ctx.session || !ctx.user) {
throw new TRPCError({ code: 'UNAUTHORIZED' })
}

return next({
ctx: {
session: { ...ctx.session },
user: { ...ctx.user },
},
})
})
32 changes: 32 additions & 0 deletions libs/auth/src/actions/logout.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
'use server'

import { cookies } from 'next/headers'
import { redirect } from 'next/navigation'

import { auth } from '../auth'
import { lucia } from '../lucia'

/**
* This function logs out the user.
* @returns The response.
*/
export async function logout() {
const { session } = await auth()
if (!session) {
return {
error: 'Unauthorized',
}
}

await lucia.invalidateSession(session.id)

const sessionCookie = lucia.createBlankSessionCookie()

cookies().set(
sessionCookie.name,
sessionCookie.value,
sessionCookie.attributes,
)

return redirect('/login')
}
40 changes: 40 additions & 0 deletions libs/auth/src/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { cache } from 'react'
import { cookies } from 'next/headers'

import type { Session, User } from 'lucia'

import { lucia } from './lucia'

export async function uncachedAuth(): Promise<
{ user: User, session: Session } | { user: null, session: null }
> {
const sessionId = cookies().get(lucia.sessionCookieName)?.value ?? null
if (!sessionId) {
return { user: null, session: null }
}
const result = await lucia.validateSession(sessionId)
try {
if (result.session?.fresh) {
const sessionCookie = lucia.createSessionCookie(result.session.id)
cookies().set(
sessionCookie.name,
sessionCookie.value,
sessionCookie.attributes,
)
}
if (!result.session) {
const sessionCookie = lucia.createBlankSessionCookie()
cookies().set(
sessionCookie.name,
sessionCookie.value,
sessionCookie.attributes,
)
}
}
catch {
console.error('Failed to set session cookie')
}
return result
}

export const auth = cache(uncachedAuth)
3 changes: 2 additions & 1 deletion libs/auth/src/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './lib/auth'
export * from './lucia'
export * from './auth'
33 changes: 33 additions & 0 deletions libs/auth/src/lucia.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { DrizzlePostgreSQLAdapter } from '@lucia-auth/adapter-drizzle'
import { Lucia } from 'lucia'

import { db, session, user } from '@cuhacking/db'
import { envWebsiteServer } from '@cuhacking/env'

const adapter = new DrizzlePostgreSQLAdapter(db, session, user)

export const lucia = new Lucia(adapter, {
sessionCookie: {
attributes: {
secure: envWebsiteServer.NODE_ENV === 'production',
},
},
getUserAttributes: (attributes: any) => {
return {
name: attributes.name,
email: attributes.email,
avatarUrl: attributes.avatarUrl,
}
},
})

declare module 'lucia' {
interface Register {
Lucia: typeof lucia
DatabaseUserAttributes: {
name?: string
email: string
avatarUrl?: string
}
}
}

0 comments on commit 8d12715

Please sign in to comment.