mirror of
https://github.com/different-ai/openwork
synced 2026-04-25 17:15:34 +02:00
fix(den): accept bearer sessions for desktop auth (#961)
This commit is contained in:
@@ -1,12 +1,11 @@
|
||||
import express from "express"
|
||||
import { fromNodeHeaders } from "better-auth/node"
|
||||
import { asc, desc, eq, isNotNull, sql } from "drizzle-orm"
|
||||
import { ensureAdminAllowlistSeeded } from "../admin-allowlist.js"
|
||||
import { auth } from "../auth.js"
|
||||
import { getCloudWorkerAdminBillingStatus } from "../billing/polar.js"
|
||||
import { db } from "../db/index.js"
|
||||
import { AdminAllowlistTable, AuthAccountTable, AuthSessionTable, AuthUserTable, WorkerTable } from "../db/schema.js"
|
||||
import { asyncRoute } from "./errors.js"
|
||||
import { getRequestSession } from "./session.js"
|
||||
|
||||
function normalizeEmail(value: string | null | undefined) {
|
||||
return value?.trim().toLowerCase() ?? ""
|
||||
@@ -83,9 +82,7 @@ async function mapWithConcurrency<T, R>(items: T[], limit: number, mapper: (item
|
||||
}
|
||||
|
||||
async function requireAdminSession(req: express.Request, res: express.Response) {
|
||||
const session = await auth.api.getSession({
|
||||
headers: fromNodeHeaders(req.headers),
|
||||
})
|
||||
const session = await getRequestSession(req)
|
||||
|
||||
if (!session?.user?.id) {
|
||||
res.status(401).json({ error: "unauthorized" })
|
||||
|
||||
78
services/den/src/http/session.ts
Normal file
78
services/den/src/http/session.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import type express from "express"
|
||||
import { fromNodeHeaders } from "better-auth/node"
|
||||
import { and, eq, gt } from "drizzle-orm"
|
||||
import { auth } from "../auth.js"
|
||||
import { db } from "../db/index.js"
|
||||
import { AuthSessionTable, AuthUserTable } from "../db/schema.js"
|
||||
|
||||
type AuthSessionLike = Awaited<ReturnType<typeof auth.api.getSession>>
|
||||
|
||||
function readBearerToken(req: express.Request): string | null {
|
||||
const header = typeof req.headers.authorization === "string" ? req.headers.authorization.trim() : ""
|
||||
if (!header) {
|
||||
return null
|
||||
}
|
||||
|
||||
const match = header.match(/^Bearer\s+(.+)$/i)
|
||||
if (!match) {
|
||||
return null
|
||||
}
|
||||
|
||||
const token = match[1]?.trim() ?? ""
|
||||
return token || null
|
||||
}
|
||||
|
||||
async function getSessionFromBearerToken(token: string): Promise<AuthSessionLike> {
|
||||
const rows = await db
|
||||
.select({
|
||||
session: {
|
||||
id: AuthSessionTable.id,
|
||||
token: AuthSessionTable.token,
|
||||
userId: AuthSessionTable.userId,
|
||||
expiresAt: AuthSessionTable.expiresAt,
|
||||
createdAt: AuthSessionTable.createdAt,
|
||||
updatedAt: AuthSessionTable.updatedAt,
|
||||
ipAddress: AuthSessionTable.ipAddress,
|
||||
userAgent: AuthSessionTable.userAgent,
|
||||
},
|
||||
user: {
|
||||
id: AuthUserTable.id,
|
||||
name: AuthUserTable.name,
|
||||
email: AuthUserTable.email,
|
||||
emailVerified: AuthUserTable.emailVerified,
|
||||
image: AuthUserTable.image,
|
||||
createdAt: AuthUserTable.createdAt,
|
||||
updatedAt: AuthUserTable.updatedAt,
|
||||
},
|
||||
})
|
||||
.from(AuthSessionTable)
|
||||
.innerJoin(AuthUserTable, eq(AuthSessionTable.userId, AuthUserTable.id))
|
||||
.where(and(eq(AuthSessionTable.token, token), gt(AuthSessionTable.expiresAt, new Date())))
|
||||
.limit(1)
|
||||
|
||||
const row = rows[0]
|
||||
if (!row) {
|
||||
return null
|
||||
}
|
||||
|
||||
return {
|
||||
session: row.session,
|
||||
user: row.user,
|
||||
}
|
||||
}
|
||||
|
||||
export async function getRequestSession(req: express.Request): Promise<AuthSessionLike> {
|
||||
const cookieSession = await auth.api.getSession({
|
||||
headers: fromNodeHeaders(req.headers),
|
||||
})
|
||||
if (cookieSession?.user?.id) {
|
||||
return cookieSession
|
||||
}
|
||||
|
||||
const bearerToken = readBearerToken(req)
|
||||
if (!bearerToken) {
|
||||
return null
|
||||
}
|
||||
|
||||
return getSessionFromBearerToken(bearerToken)
|
||||
}
|
||||
@@ -1,14 +1,13 @@
|
||||
import { randomBytes, randomUUID } from "crypto"
|
||||
import express from "express"
|
||||
import { fromNodeHeaders } from "better-auth/node"
|
||||
import { and, asc, desc, eq, isNull } from "drizzle-orm"
|
||||
import { z } from "zod"
|
||||
import { auth } from "../auth.js"
|
||||
import { getCloudWorkerBillingStatus, requireCloudWorkerAccess, setCloudWorkerSubscriptionCancellation } from "../billing/polar.js"
|
||||
import { db } from "../db/index.js"
|
||||
import { AuditEventTable, WorkerBundleTable, WorkerInstanceTable, WorkerTable, WorkerTokenTable } from "../db/schema.js"
|
||||
import { env } from "../env.js"
|
||||
import { asyncRoute, isTransientDbConnectionError } from "./errors.js"
|
||||
import { getRequestSession } from "./session.js"
|
||||
import { ensureDefaultOrg, listUserOrgs, resolveUserOrg } from "../orgs.js"
|
||||
import { deprovisionWorker, provisionWorker } from "../workers/provisioner.js"
|
||||
import { customDomainForWorker } from "../workers/vanity-domain.js"
|
||||
@@ -243,9 +242,7 @@ async function issueWorkerOwnerToken(workerId: string): Promise<string> {
|
||||
}
|
||||
|
||||
async function requireSession(req: express.Request, res: express.Response) {
|
||||
const session = await auth.api.getSession({
|
||||
headers: fromNodeHeaders(req.headers),
|
||||
})
|
||||
const session = await getRequestSession(req)
|
||||
if (!session?.user?.id) {
|
||||
res.status(401).json({ error: "unauthorized" })
|
||||
return null
|
||||
|
||||
@@ -3,11 +3,12 @@ import cors from "cors"
|
||||
import express from "express"
|
||||
import path from "node:path"
|
||||
import { fileURLToPath } from "node:url"
|
||||
import { fromNodeHeaders, toNodeHandler } from "better-auth/node"
|
||||
import { toNodeHandler } from "better-auth/node"
|
||||
import { auth } from "./auth.js"
|
||||
import { env } from "./env.js"
|
||||
import { adminRouter } from "./http/admin.js"
|
||||
import { asyncRoute, errorMiddleware } from "./http/errors.js"
|
||||
import { getRequestSession } from "./http/session.js"
|
||||
import { workersRouter } from "./http/workers.js"
|
||||
import { listUserOrgs } from "./orgs.js"
|
||||
|
||||
@@ -34,9 +35,7 @@ app.get("/health", (_, res) => {
|
||||
})
|
||||
|
||||
app.get("/v1/me", asyncRoute(async (req, res) => {
|
||||
const session = await auth.api.getSession({
|
||||
headers: fromNodeHeaders(req.headers),
|
||||
})
|
||||
const session = await getRequestSession(req)
|
||||
if (!session?.user?.id) {
|
||||
res.status(401).json({ error: "unauthorized" })
|
||||
return
|
||||
@@ -45,9 +44,7 @@ app.get("/v1/me", asyncRoute(async (req, res) => {
|
||||
}))
|
||||
|
||||
app.get("/v1/me/orgs", asyncRoute(async (req, res) => {
|
||||
const session = await auth.api.getSession({
|
||||
headers: fromNodeHeaders(req.headers),
|
||||
})
|
||||
const session = await getRequestSession(req)
|
||||
if (!session?.user?.id) {
|
||||
res.status(401).json({ error: "unauthorized" })
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user