From f2c3273b68f69fe0271f26836c03c029f294b492 Mon Sep 17 00:00:00 2001 From: Ridanshi Date: Mon, 18 May 2026 12:15:38 +0530 Subject: [PATCH 1/2] fix(auth): encrypt OAuth tokens using encryption utility directly auth.ts silently stored GitHub OAuth access tokens as plaintext because the encryption check relied on a non-existent `app.encryption` Fastify decorator - the condition always evaluated false, falling back to the raw token. connect.ts called `app.encryption.encrypt()` directly, throwing a TypeError at runtime and breaking the GitHub connect flow entirely. Both routes now import `encrypt()` directly from utils/encryption.ts, consistent with how follow.ts already imports `decrypt()` from the same module. --- apps/backend/src/routes/auth.ts | 4 +++- apps/backend/src/routes/connect.ts | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/backend/src/routes/auth.ts b/apps/backend/src/routes/auth.ts index febc41d..1f89ddd 100644 --- a/apps/backend/src/routes/auth.ts +++ b/apps/backend/src/routes/auth.ts @@ -1,5 +1,7 @@ import type { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify'; import { randomBytes } from 'crypto'; +import { encrypt } from '../utils/encryption.js'; + const GITHUB_AUTH_URL = 'https://github.com/login/oauth/authorize'; const GITHUB_TOKEN_URL = 'https://github.com/login/oauth/access_token'; const GITHUB_USER_URL = 'https://api.github.com/user'; @@ -103,7 +105,7 @@ export async function authRoutes(app: FastifyInstance) { }); // Save the authentication token for 'user:email read:user' so we have a basic platform connection - const encryptedToken = (app as any).encryption ? (app as any).encryption.encrypt(tokenData.access_token) : tokenData.access_token; + const encryptedToken = encrypt(tokenData.access_token); await app.prisma.oAuthToken.upsert({ where: { userId_platform: { userId: user.id, platform: 'github' } }, diff --git a/apps/backend/src/routes/connect.ts b/apps/backend/src/routes/connect.ts index 68f8671..e96fea5 100644 --- a/apps/backend/src/routes/connect.ts +++ b/apps/backend/src/routes/connect.ts @@ -1,4 +1,6 @@ import type { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify'; +import { randomBytes } from 'crypto'; +import { encrypt } from '../utils/encryption.js'; const GITHUB_AUTH_URL = 'https://github.com/login/oauth/authorize'; const GITHUB_TOKEN_URL = 'https://github.com/login/oauth/access_token'; @@ -95,7 +97,7 @@ export async function connectRoutes(app: FastifyInstance) { } // Encrypt and store the token - const encryptedToken = app.encryption.encrypt(tokenData.access_token); + const encryptedToken = encrypt(tokenData.access_token); await app.prisma.oAuthToken.upsert({ where: { From b962d5f2c047d463c76e30f7f82f7fb938df8912 Mon Sep 17 00:00:00 2001 From: Ridanshi Date: Thu, 21 May 2026 23:11:16 +0530 Subject: [PATCH 2/2] fix(auth): isolate OAuth token persistence with focused try/catch Wrap the encrypt + oAuthToken.upsert block in its own try/catch so that a transient DB failure during token storage does not abort the login flow. The platform token is supplementary -- authentication (JWT issuance) proceeds even when persistence fails, and the error is logged for observability. Addresses reviewer feedback on PR #144. --- apps/backend/src/routes/auth.ts | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/apps/backend/src/routes/auth.ts b/apps/backend/src/routes/auth.ts index 8fe1dcb..3dc9166 100644 --- a/apps/backend/src/routes/auth.ts +++ b/apps/backend/src/routes/auth.ts @@ -120,14 +120,18 @@ export async function authRoutes(app: FastifyInstance) { }, }); - // Save the authentication token for 'user:email read:user' so we have a basic platform connection - const encryptedToken = encrypt(tokenData.access_token); - - await app.prisma.oAuthToken.upsert({ - where: { userId_platform: { userId: user.id, platform: 'github' } }, - update: { accessToken: encryptedToken, scopes: 'read:user user:email' }, - create: { userId: user.id, platform: 'github', accessToken: encryptedToken, scopes: 'read:user user:email' }, - }); + // Save the authentication token for 'user:email read:user' so we have a basic platform connection. + // Failure here is non-fatal — the user can still authenticate; the token can be reconnected later. + try { + const encryptedToken = encrypt(tokenData.access_token); + await app.prisma.oAuthToken.upsert({ + where: { userId_platform: { userId: user.id, platform: 'github' } }, + update: { accessToken: encryptedToken, scopes: 'read:user user:email' }, + create: { userId: user.id, platform: 'github', accessToken: encryptedToken, scopes: 'read:user user:email' }, + }); + } catch (err) { + app.log.error({ err, userId: user.id }, 'Failed to persist GitHub OAuth token — authentication proceeds'); + } // Generate JWT const token = app.jwt.sign(