Skip to content

Commit 48deca9

Browse files
refactor: scope by organizations (#166)
* Add organization to dashboard page * feat(api): implement organization management functions including creation, deletion, and membership updates * feat(api): add organization routes and query for listing organization memberships * feat(api): add organization membership query endpoint for improved data retrieval * refactor(api, web): add organizations settings page and format code * refactor(api, web): remove organization handle from creation process and update UI accordingly * refactor(api, web): remove membership-related functionality and simplify organization data structure * feat(web): update sidebar to include organizations section and add navigation for administration * refactor(web): streamline organization switcher component and clean up sidebar structure * refactor(web): update routing and sidebar structure for organization management * refactor(web): update dashboard routing to organization-specific paths and remove unused organization switcher component * refactor(web): remove UsagePage and integrate usage credits into the dashboard, enhancing credit tracking and display * refactor(web): update routing structure for organization dashboard, workflows, and datasets, enhancing navigation and page organization * refactor(web): reorganize sidebar items and clean up component imports for improved navigation and code clarity * refactor(web): consolidate dataset and deployment page imports, streamline routing structure for improved organization and clarity * refactor(web): update routing paths for datasets and workflows to organization-specific structure, enhancing clarity and consistency * refactor(web): reorganize sidebar items and enhance breadcrumb functionality for improved navigation and user experience * refactor(web): move the collapse button at the bottom of the sidebar * feat(web): add org handle to url * feat(web): update organization switcher --------- Co-authored-by: leonardcser <73912641+leonardcser@users.noreply.github.com>
1 parent 43f7aa1 commit 48deca9

43 files changed

Lines changed: 1705 additions & 810 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

apps/api/src/auth.ts

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ import { ApiContext } from "./context";
1010
import {
1111
createDatabase,
1212
OrganizationRole,
13-
organizations,
1413
saveUser,
1514
users,
1615
verifyApiKey,
1716
} from "./db";
17+
import { memberships, organizations } from "./db/schema";
1818

1919
// Constants
2020
export const JWT_ACCESS_TOKEN_NAME = "access_token";
@@ -168,7 +168,7 @@ export const jwtMiddleware = async (
168168
c.env.JWT_SECRET
169169
)) as JWTTokenPayload | null;
170170

171-
if (!payload || !payload.organization?.id) {
171+
if (!payload || !payload.sub) {
172172
return c.json({ error: "Invalid or expired token" }, 401);
173173
}
174174

@@ -182,7 +182,38 @@ export const jwtMiddleware = async (
182182
}
183183

184184
c.set("jwtPayload", payload);
185-
c.set("organizationId", payload.organization.id);
185+
186+
const db = createDatabase(c.env.DB);
187+
const organizationIdOrHandleFromUrl = c.req.param("organizationIdOrHandle");
188+
189+
let organizationId: string;
190+
191+
if (organizationIdOrHandleFromUrl) {
192+
// Resolve organization from URL param
193+
const userOrgs = await db
194+
.select({ id: organizations.id, handle: organizations.handle })
195+
.from(organizations)
196+
.innerJoin(memberships, eq(memberships.organizationId, organizations.id))
197+
.where(eq(memberships.userId, payload.sub));
198+
199+
const targetOrg = userOrgs.find(
200+
(org) => org.handle === organizationIdOrHandleFromUrl
201+
);
202+
203+
if (!targetOrg) {
204+
return c.json({ error: "Organization not found or access denied" }, 403);
205+
}
206+
207+
organizationId = targetOrg.id;
208+
} else {
209+
// Fallback to default org from token if no URL param
210+
if (!payload.organization?.id) {
211+
return c.json({ error: "Organization required" }, 400);
212+
}
213+
organizationId = payload.organization.id;
214+
}
215+
216+
c.set("organizationId", organizationId);
186217
await next();
187218
};
188219

@@ -277,8 +308,7 @@ export const apiKeyOrJwtMiddleware = async (
277308
return apiKeyMiddleware(c, next); // apiKeyMiddleware will handle org verification
278309
}
279310

280-
// Otherwise, try JWT auth (which might not need organizationIdOrHandleFromUrl explicitly here,
281-
// as JWT payload should contain organization info if needed by downstream handlers)
311+
// Otherwise, try JWT auth
282312
return jwtMiddleware(c, next);
283313
};
284314

0 commit comments

Comments
 (0)