Skip to content

Commit 9c58e7c

Browse files
authored
fix(plugin-multi-tenant): forbidden error when logging in as a user with no tenant and no access to all tenants (#16047)
Previously, if you logged in as a user without: * Any tenant value * `userHasAccessToAllTenants` is not defined / the condition does not meet for this user You'd see this error (the admin panel crashes): <img width="1904" height="600" alt="image" src="https://github.com/user-attachments/assets/ff4f3358-8697-400c-adae-5e512369f386" /> Why? because the call uses `overrideAccess: false` and that user does not have access to the `tenants` collection. Now we early return `[]` in that case Added an E2E test that previously failed. --- - To see the specific tasks where the Asana app for GitHub is being used, see below: - https://app.asana.com/0/0/1213815640035525
1 parent db4b00e commit 9c58e7c

6 files changed

Lines changed: 52 additions & 1 deletion

File tree

packages/plugin-multi-tenant/src/utilities/getTenantOptions.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ export const getTenantOptions = async ({
3939
})
4040
: undefined
4141

42+
if (userTenantIds !== undefined && userTenantIds.length === 0) {
43+
return tenantOptions
44+
}
45+
4246
const tenants = await payload.find({
4347
collection: tenantsCollectionSlug,
4448
depth: 0,

test/plugin-multi-tenant/collections/Tenants.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,12 @@ const tenantAccess: Access = ({ req }) => {
3333
],
3434
}
3535
}
36+
37+
// authenticated user with no tenants has no access
38+
return false
3639
}
3740

38-
// if the user has no assigned tenants, return a filter that allows access to public tenants
41+
// unauthenticated — allow access to public tenants only
3942
return {
4043
isPublic: {
4144
equals: true,

test/plugin-multi-tenant/credentials.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ export const credentials = {
77
email: 'jane@blue-dog.com',
88
password: 'test',
99
},
10+
noTenant: {
11+
email: 'notenants@example.com',
12+
password: 'test',
13+
},
1014
owner: {
1115
email: 'owner@anchorAndBlueDog.com',
1216
password: 'test',

test/plugin-multi-tenant/e2e.spec.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,24 @@ test.describe('Multi Tenant', () => {
703703
.toEqual(['Blue Dog', 'Anchor Bar'].sort())
704704
})
705705

706+
test('should not throw forbidden error when user has no tenants assigned', async () => {
707+
await loginClientSide({
708+
data: credentials.noTenant,
709+
page,
710+
serverURL,
711+
})
712+
713+
// Navigate to a page that triggers getTenantOptions - previously caused a
714+
// "Runtime Forbidden" error because payload.find() was called with an empty
715+
// userTenantIds array and overrideAccess: false
716+
await page.goto(menuItemsURL.list)
717+
718+
// Ensure the Next.js runtime error overlay is not shown
719+
await expect(page.locator('body')).not.toContainText(
720+
'You are not allowed to perform this action.',
721+
)
722+
})
723+
706724
test('should not show public tenants to users with assigned tenants', async () => {
707725
await loginClientSide({
708726
data: credentials.owner,

test/plugin-multi-tenant/payload-types.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ export interface Config {
106106
globals: {};
107107
globalsSelect: {};
108108
locale: 'en' | 'es' | 'fr';
109+
widgets: {
110+
collections: CollectionsWidget;
111+
};
109112
user: User;
110113
jobs: {
111114
tasks: unknown;
@@ -543,6 +546,16 @@ export interface PayloadMigrationsSelect<T extends boolean = true> {
543546
updatedAt?: T;
544547
createdAt?: T;
545548
}
549+
/**
550+
* This interface was referenced by `Config`'s JSON-Schema
551+
* via the `definition` "collections_widget".
552+
*/
553+
export interface CollectionsWidget {
554+
data?: {
555+
[k: string]: unknown;
556+
};
557+
width: 'full';
558+
}
546559
/**
547560
* This interface was referenced by `Config`'s JSON-Schema
548561
* via the `definition` "auth".

test/plugin-multi-tenant/seed/index.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,4 +227,13 @@ export const seed = async (payload: Payload) => {
227227
],
228228
},
229229
})
230+
231+
await payload.create({
232+
collection: usersSlug,
233+
data: {
234+
...credentials.noTenant,
235+
roles: ['user'],
236+
// tenants: [],
237+
},
238+
})
230239
}

0 commit comments

Comments
 (0)