Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
7bc5ed9
Add organization to dashboard page
bchapuis Sep 22, 2025
9976666
feat(api): implement organization management functions including crea…
bchapuis Sep 22, 2025
cb2df9c
feat(api): add organization routes and query for listing organization…
bchapuis Sep 22, 2025
d1e7a54
feat(api): add organization membership query endpoint for improved da…
bchapuis Sep 22, 2025
534bd26
refactor(api, web): add organizations settings page and format code
bchapuis Sep 22, 2025
0b42408
refactor(api, web): remove organization handle from creation process …
bchapuis Sep 22, 2025
b5809ef
refactor(api, web): remove membership-related functionality and simpl…
bchapuis Sep 22, 2025
de5181d
feat(web): update sidebar to include organizations section and add na…
bchapuis Sep 22, 2025
c43d93f
refactor(web): streamline organization switcher component and clean u…
bchapuis Sep 22, 2025
275482c
refactor(web): update routing and sidebar structure for organization …
bchapuis Sep 22, 2025
6f37942
refactor(web): update dashboard routing to organization-specific path…
bchapuis Sep 22, 2025
a65809a
refactor(web): remove UsagePage and integrate usage credits into the …
bchapuis Sep 22, 2025
134df10
refactor(web): update routing structure for organization dashboard, w…
bchapuis Sep 22, 2025
8f6b7a8
refactor(web): reorganize sidebar items and clean up component import…
bchapuis Sep 22, 2025
489071c
refactor(web): consolidate dataset and deployment page imports, strea…
bchapuis Sep 22, 2025
ecdb900
refactor(web): update routing paths for datasets and workflows to org…
bchapuis Sep 22, 2025
78e67a4
refactor(web): reorganize sidebar items and enhance breadcrumb functi…
bchapuis Sep 22, 2025
8dd8125
refactor(web): move the collapse button at the bottom of the sidebar
bchapuis Sep 22, 2025
457479d
feat(web): add org handle to url
leonardcser Sep 23, 2025
f954778
feat(web): update organization switcher
leonardcser Sep 23, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 35 additions & 5 deletions apps/api/src/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ import { ApiContext } from "./context";
import {
createDatabase,
OrganizationRole,
organizations,
saveUser,
users,
verifyApiKey,
} from "./db";
import { memberships, organizations } from "./db/schema";

// Constants
export const JWT_ACCESS_TOKEN_NAME = "access_token";
Expand Down Expand Up @@ -168,7 +168,7 @@ export const jwtMiddleware = async (
c.env.JWT_SECRET
)) as JWTTokenPayload | null;

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

Expand All @@ -182,7 +182,38 @@ export const jwtMiddleware = async (
}

c.set("jwtPayload", payload);
c.set("organizationId", payload.organization.id);

const db = createDatabase(c.env.DB);
const organizationIdOrHandleFromUrl = c.req.param("organizationIdOrHandle");

let organizationId: string;

if (organizationIdOrHandleFromUrl) {
// Resolve organization from URL param
const userOrgs = await db
.select({ id: organizations.id, handle: organizations.handle })
.from(organizations)
.innerJoin(memberships, eq(memberships.organizationId, organizations.id))
.where(eq(memberships.userId, payload.sub));

const targetOrg = userOrgs.find(
(org) => org.handle === organizationIdOrHandleFromUrl
);

if (!targetOrg) {
return c.json({ error: "Organization not found or access denied" }, 403);
}

organizationId = targetOrg.id;
} else {
// Fallback to default org from token if no URL param
if (!payload.organization?.id) {
return c.json({ error: "Organization required" }, 400);
}
organizationId = payload.organization.id;
}

c.set("organizationId", organizationId);
await next();
};

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

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

Expand Down
Loading
Loading