chore: refactor sessions

This commit is contained in:
David Nguyen
2025-02-16 00:44:01 +11:00
parent 8d5fafec27
commit 1ed1cb0773
21 changed files with 261 additions and 307 deletions

View File

@ -21,7 +21,6 @@ export const auth = new Hono<HonoAuthContext>()
.use(async (c, next) => {
c.set('requestMetadata', extractRequestMetadata(c.req.raw));
// Todo: Maybe use auth URL.
const validOrigin = new URL(NEXT_PUBLIC_WEBAPP_URL()).origin;
const headerOrigin = c.req.header('Origin');
@ -54,9 +53,6 @@ export const auth = new Hono<HonoAuthContext>()
* Handle errors.
*/
auth.onError((err, c) => {
// Todo Remove
console.error(`${err}`);
if (err instanceof HTTPException) {
return c.json(
{

View File

@ -1,13 +1,18 @@
import type { Context } from 'hono';
import { deleteCookie, getSignedCookie, setSignedCookie } from 'hono/cookie';
import { getCookieDomain, useSecureCookies } from '@documenso/lib/constants/auth';
import {
formatSecureCookieName,
getCookieDomain,
useSecureCookies,
} from '@documenso/lib/constants/auth';
import { appLog } from '@documenso/lib/utils/debugger';
import { env } from '@documenso/lib/utils/env';
import { generateSessionToken } from './session';
export const sessionCookieName = 'sessionId';
export const sessionCookieName = formatSecureCookieName('sessionId');
export const csrfCookieName = formatSecureCookieName('csrfToken');
const getAuthSecret = () => {
const authSecret = env('NEXTAUTH_SECRET');
@ -86,7 +91,7 @@ export const deleteSessionCookie = (c: Context) => {
};
export const getCsrfCookie = async (c: Context) => {
const csrfToken = await getSignedCookie(c, getAuthSecret(), 'csrfToken');
const csrfToken = await getSignedCookie(c, getAuthSecret(), csrfCookieName);
return csrfToken || null;
};
@ -94,7 +99,7 @@ export const getCsrfCookie = async (c: Context) => {
export const setCsrfCookie = async (c: Context) => {
const csrfToken = generateSessionToken();
await setSignedCookie(c, 'csrfToken', csrfToken, getAuthSecret(), {
await setSignedCookie(c, csrfCookieName, csrfToken, getAuthSecret(), {
...sessionCookieOptions,
// Explicity set to undefined for session lived cookie.

View File

@ -7,7 +7,23 @@ import type { SessionValidationResult } from '../session/session';
import { validateSessionToken } from '../session/session';
import { getSessionCookie } from '../session/session-cookies';
export const getSession = async (c: Context | Request): Promise<SessionValidationResult> => {
export const getSession = async (c: Context | Request) => {
const { session, user } = await getOptionalSession(mapRequestToContextForCookie(c));
if (session && user) {
return { session, user };
}
if (c instanceof Request) {
throw new Error('Unauthorized');
}
throw new AppError(AuthenticationErrorCode.Unauthorized);
};
export const getOptionalSession = async (
c: Context | Request,
): Promise<SessionValidationResult> => {
const sessionId = await getSessionCookie(mapRequestToContextForCookie(c));
if (!sessionId) {
@ -21,20 +37,6 @@ export const getSession = async (c: Context | Request): Promise<SessionValidatio
return await validateSessionToken(sessionId);
};
export const getRequiredSession = async (c: Context | Request) => {
const { session, user } = await getSession(mapRequestToContextForCookie(c));
if (session && user) {
return { session, user };
}
if (c instanceof Request) {
throw new Error('Unauthorized');
}
throw new AppError(AuthenticationErrorCode.Unauthorized);
};
/**
* Todo: Rethink, this is pretty sketchy.
*/

View File

@ -4,10 +4,6 @@ import { GoogleAuthOptions, OidcAuthOptions } from '../config';
import { handleOAuthCallbackUrl } from '../lib/utils/handle-oauth-callback-url';
import type { HonoAuthContext } from '../types/context';
// Todo: Test
// api/auth/callback/google?
// api/auth/callback/oidc
/**
* Have to create this route instead of bundling callback with oauth routes to provide
* backwards compatibility for self-hosters (since we used to use NextAuth).
@ -20,7 +16,5 @@ export const callbackRoute = new Hono<HonoAuthContext>()
/**
* Google callback verification.
*
* Todo: Double check this is the correct callback.
*/
.get('/google', async (c) => handleOAuthCallbackUrl({ c, clientOptions: GoogleAuthOptions }));

View File

@ -27,7 +27,7 @@ import { UserSecurityAuditLogType } from '@documenso/prisma/client';
import { AuthenticationErrorCode } from '../lib/errors/error-codes';
import { getCsrfCookie } from '../lib/session/session-cookies';
import { onAuthorize } from '../lib/utils/authorizer';
import { getRequiredSession, getSession } from '../lib/utils/get-session';
import { getSession } from '../lib/utils/get-session';
import type { HonoAuthContext } from '../types/context';
import {
ZForgotPasswordSchema,
@ -176,10 +176,6 @@ export const emailPasswordRoute = new Hono<HonoAuthContext>()
const session = await getSession(c);
if (!session.isAuthenticated) {
throw new AppError(AuthenticationErrorCode.Unauthorized);
}
await updatePassword({
userId: session.user.id,
password,
@ -251,7 +247,7 @@ export const emailPasswordRoute = new Hono<HonoAuthContext>()
* Setup two factor authentication.
*/
.post('/2fa/setup', async (c) => {
const { user } = await getRequiredSession(c);
const { user } = await getSession(c);
const result = await setupTwoFactorAuthentication({
user,
@ -277,7 +273,7 @@ export const emailPasswordRoute = new Hono<HonoAuthContext>()
async (c) => {
const requestMetadata = c.get('requestMetadata');
const { user: sessionUser } = await getRequiredSession(c);
const { user: sessionUser } = await getSession(c);
const user = await prisma.user.findFirst({
where: {
@ -324,7 +320,7 @@ export const emailPasswordRoute = new Hono<HonoAuthContext>()
async (c) => {
const requestMetadata = c.get('requestMetadata');
const { user: sessionUser } = await getRequiredSession(c);
const { user: sessionUser } = await getSession(c);
const user = await prisma.user.findFirst({
where: {
@ -367,7 +363,7 @@ export const emailPasswordRoute = new Hono<HonoAuthContext>()
}),
),
async (c) => {
const { user: sessionUser } = await getRequiredSession(c);
const { user: sessionUser } = await getSession(c);
const user = await prisma.user.findFirst({
where: {

View File

@ -119,28 +119,3 @@ export const passkeyRoute = new Hono<HonoAuthContext>()
200,
);
});
// Todo
// .post('/register', async (c) => {
// const { user } = await getRequiredSession(c);
// //
// })
// .post(
// '/pre-authenticate',
// sValidator(
// 'json',
// z.object({
// code: z.string(),
// }),
// ),
// async (c) => {
// //
// return c.json({
// success: true,
// recoveryCodes: result.recoveryCodes,
// });
// },
// );

View File

@ -1,10 +1,10 @@
import { Hono } from 'hono';
import type { SessionValidationResult } from '../lib/session/session';
import { getSession } from '../lib/utils/get-session';
import { getOptionalSession } from '../lib/utils/get-session';
export const sessionRoute = new Hono().get('/session', async (c) => {
const session: SessionValidationResult = await getSession(c);
const session: SessionValidationResult = await getOptionalSession(c);
return c.json(session);
});

View File

@ -9,7 +9,7 @@ import { viewBackupCodes } from '@documenso/lib/server-only/2fa/view-backup-code
import { prisma } from '@documenso/prisma';
import { AuthenticationErrorCode } from '../lib/errors/error-codes';
import { getRequiredSession } from '../lib/utils/get-session';
import { getSession } from '../lib/utils/get-session';
import type { HonoAuthContext } from '../types/context';
import {
ZDisableTwoFactorRequestSchema,
@ -22,7 +22,7 @@ export const twoFactorRoute = new Hono<HonoAuthContext>()
* Setup two factor authentication.
*/
.post('/setup', async (c) => {
const { user } = await getRequiredSession(c);
const { user } = await getSession(c);
const result = await setupTwoFactorAuthentication({
user,
@ -41,7 +41,7 @@ export const twoFactorRoute = new Hono<HonoAuthContext>()
.post('/enable', sValidator('json', ZEnableTwoFactorRequestSchema), async (c) => {
const requestMetadata = c.get('requestMetadata');
const { user: sessionUser } = await getRequiredSession(c);
const { user: sessionUser } = await getSession(c);
const user = await prisma.user.findFirst({
where: {
@ -79,7 +79,7 @@ export const twoFactorRoute = new Hono<HonoAuthContext>()
.post('/disable', sValidator('json', ZDisableTwoFactorRequestSchema), async (c) => {
const requestMetadata = c.get('requestMetadata');
const { user: sessionUser } = await getRequiredSession(c);
const { user: sessionUser } = await getSession(c);
const user = await prisma.user.findFirst({
where: {
@ -117,7 +117,7 @@ export const twoFactorRoute = new Hono<HonoAuthContext>()
'/view-recovery-codes',
sValidator('json', ZViewTwoFactorRecoveryCodesRequestSchema),
async (c) => {
const { user: sessionUser } = await getRequiredSession(c);
const { user: sessionUser } = await getSession(c);
const user = await prisma.user.findFirst({
where: {