mirror of
https://github.com/logto-io/logto.git
synced 2024-12-30 20:33:54 -05:00
feat(schemas,cli,core,cloud): add manage tenant self scope (#3865)
This commit is contained in:
parent
7fb5374963
commit
8cbf87bb73
17 changed files with 292 additions and 82 deletions
2
.github/workflows/integration-test.yml
vendored
2
.github/workflows/integration-test.yml
vendored
|
@ -54,7 +54,7 @@ jobs:
|
|||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
target: [api, ui, ui-cloud]
|
||||
target: [api, api-cloud, ui, ui-cloud]
|
||||
|
||||
needs: package
|
||||
runs-on: ubuntu-latest
|
||||
|
|
|
@ -33,10 +33,12 @@ export const seedAdminData = async (
|
|||
data: AdminData | UpdateAdminData,
|
||||
...additionalScopes: CreateScope[]
|
||||
) => {
|
||||
const { resource, scope, role } = data;
|
||||
const { resource, scopes, role } = data;
|
||||
|
||||
assert(
|
||||
resource.tenantId === scope.tenantId && scope.tenantId === role.tenantId,
|
||||
scopes.every(
|
||||
(scope) => resource.tenantId === scope.tenantId && scope.tenantId === role.tenantId
|
||||
),
|
||||
new Error('All data should have the same tenant ID')
|
||||
);
|
||||
|
||||
|
@ -58,19 +60,24 @@ export const seedAdminData = async (
|
|||
};
|
||||
|
||||
await pool.query(insertInto(resource, 'resources'));
|
||||
await pool.query(insertInto(scope, 'scopes'));
|
||||
await Promise.all(additionalScopes.map(async (scope) => pool.query(insertInto(scope, 'scopes'))));
|
||||
await Promise.all(
|
||||
[...scopes, ...additionalScopes].map(async (scope) => pool.query(insertInto(scope, 'scopes')))
|
||||
);
|
||||
|
||||
const roleId = await processRole();
|
||||
await pool.query(
|
||||
insertInto(
|
||||
{
|
||||
id: generateStandardId(),
|
||||
roleId,
|
||||
scopeId: scope.id,
|
||||
tenantId: resource.tenantId,
|
||||
} satisfies CreateRolesScope,
|
||||
'roles_scopes'
|
||||
await Promise.all(
|
||||
scopes.map(async ({ id }) =>
|
||||
pool.query(
|
||||
insertInto(
|
||||
{
|
||||
id: generateStandardId(),
|
||||
roleId,
|
||||
scopeId: id,
|
||||
tenantId: resource.tenantId,
|
||||
} satisfies CreateRolesScope,
|
||||
'roles_scopes'
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
};
|
||||
|
|
|
@ -44,30 +44,38 @@ export const createTenantsQueries = (client: Queryable<PostgreSql>) => {
|
|||
`);
|
||||
|
||||
const insertAdminData = async (data: AdminData) => {
|
||||
const { resource, scope, role } = data;
|
||||
const { resource, scopes, role } = data;
|
||||
|
||||
assert(
|
||||
resource.tenantId && scope.tenantId && role.tenantId,
|
||||
resource.tenantId && scopes.every(({ tenantId }) => tenantId) && role.tenantId,
|
||||
new Error('Tenant ID cannot be empty.')
|
||||
);
|
||||
|
||||
assert(
|
||||
resource.tenantId === scope.tenantId && scope.tenantId === role.tenantId,
|
||||
scopes.every(
|
||||
(scope) => resource.tenantId === scope.tenantId && scope.tenantId === role.tenantId
|
||||
),
|
||||
new Error('All data should have the same tenant ID.')
|
||||
);
|
||||
|
||||
await client.query(insertInto(resource, 'resources'));
|
||||
await client.query(insertInto(scope, 'scopes'));
|
||||
await Promise.all(scopes.map(async (scope) => client.query(insertInto(scope, 'scopes'))));
|
||||
await client.query(insertInto(role, 'roles'));
|
||||
await client.query(
|
||||
insertInto(
|
||||
{
|
||||
id: generateStandardId(),
|
||||
roleId: role.id,
|
||||
scopeId: scope.id,
|
||||
tenantId: resource.tenantId,
|
||||
} satisfies CreateRolesScope,
|
||||
'roles_scopes'
|
||||
|
||||
const { tenantId } = resource;
|
||||
await Promise.all(
|
||||
scopes.map(async ({ id }) =>
|
||||
client.query(
|
||||
insertInto(
|
||||
{
|
||||
id: generateStandardId(),
|
||||
roleId: role.id,
|
||||
scopeId: id,
|
||||
tenantId,
|
||||
} satisfies CreateRolesScope,
|
||||
'roles_scopes'
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
};
|
||||
|
|
|
@ -55,7 +55,8 @@ function Content() {
|
|||
PredefinedScope.All,
|
||||
...conditionalArray(
|
||||
isCloud && cloudApi.scopes.CreateTenant,
|
||||
isCloud && cloudApi.scopes.ManageTenant
|
||||
isCloud && cloudApi.scopes.ManageTenant,
|
||||
isCloud && cloudApi.scopes.ManageTenantSelf
|
||||
),
|
||||
],
|
||||
[]
|
||||
|
|
|
@ -20,9 +20,12 @@ mockEsm('./utils.js', () => ({
|
|||
|
||||
const { jwtVerify } = mockEsm('jose', () => ({
|
||||
createLocalJWKSet: jest.fn(),
|
||||
jwtVerify: jest
|
||||
.fn()
|
||||
.mockReturnValue({ payload: { sub: 'fooUser', scope: defaultManagementApi.scope.name } }),
|
||||
jwtVerify: jest.fn().mockReturnValue({
|
||||
payload: {
|
||||
sub: 'fooUser',
|
||||
scope: defaultManagementApi.scopes.map((scope) => scope.name).join(' '),
|
||||
},
|
||||
}),
|
||||
}));
|
||||
|
||||
const audience = defaultManagementApi.resource.indicator;
|
||||
|
|
|
@ -60,7 +60,11 @@ export const verifyBearerTokenFromRequest = async (
|
|||
if ((!isProduction || isIntegrationTest) && userId) {
|
||||
consoleLog.warn(`Found dev user ID ${userId}, skip token validation.`);
|
||||
|
||||
return { sub: userId, clientId: undefined, scopes: [defaultManagementApi.scope.name] };
|
||||
return {
|
||||
sub: userId,
|
||||
clientId: undefined,
|
||||
scopes: defaultManagementApi.scopes.map(({ name }) => name),
|
||||
};
|
||||
}
|
||||
|
||||
const getKeysAndIssuer = async (): Promise<[JWK[], string[]]> => {
|
||||
|
|
|
@ -12,8 +12,9 @@
|
|||
"scripts": {
|
||||
"build": "rm -rf lib/ && tsc -p tsconfig.test.json --sourcemap",
|
||||
"test:only": "NODE_OPTIONS=--experimental-vm-modules jest",
|
||||
"test": "pnpm build && pnpm test:api && pnpm test:ui",
|
||||
"test": "pnpm build && pnpm test:api && pnpm test:api-cloud && pnpm test:ui",
|
||||
"test:api": "pnpm test:only -i ./lib/tests/api/",
|
||||
"test:api-cloud": "pnpm test:only -i ./lib/tests/api-cloud/",
|
||||
"test:ui": "pnpm test:only -i --config=jest.config.ui.js ./lib/tests/ui/",
|
||||
"test:ui-cloud": "pnpm test:only -i --config=jest.config.ui.js ./lib/tests/ui-cloud/",
|
||||
"lint": "eslint --ext .ts src",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { got } from 'got';
|
||||
|
||||
import { logtoConsoleUrl, logtoUrl } from '#src/constants.js';
|
||||
import { logtoConsoleUrl, logtoUrl, logtoCloudUrl } from '#src/constants.js';
|
||||
|
||||
const api = got.extend({
|
||||
prefixUrl: new URL('/api', logtoUrl),
|
||||
|
@ -24,3 +24,7 @@ export const authedAdminTenantApi = adminTenantApi.extend({
|
|||
'development-user-id': 'integration-test-admin-user',
|
||||
},
|
||||
});
|
||||
|
||||
export const cloudApi = got.extend({
|
||||
prefixUrl: new URL('/api', logtoCloudUrl),
|
||||
});
|
||||
|
|
21
packages/integration-tests/src/api/tenant.ts
Normal file
21
packages/integration-tests/src/api/tenant.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import type { TenantInfo } from '@logto/schemas';
|
||||
|
||||
import { cloudApi } from './api.js';
|
||||
|
||||
export const createTenant = async (accessToken: string) => {
|
||||
return cloudApi
|
||||
.extend({
|
||||
headers: { authorization: `Bearer ${accessToken}` },
|
||||
})
|
||||
.post('tenants')
|
||||
.json<TenantInfo>();
|
||||
};
|
||||
|
||||
export const getTenants = async (accessToken: string) => {
|
||||
return cloudApi
|
||||
.extend({
|
||||
headers: { authorization: `Bearer ${accessToken}` },
|
||||
})
|
||||
.get('tenants')
|
||||
.json<TenantInfo[]>();
|
||||
};
|
|
@ -2,15 +2,21 @@
|
|||
// Since they are just different in URLs
|
||||
|
||||
import type { LogtoConfig } from '@logto/node';
|
||||
import type { Role, User } from '@logto/schemas';
|
||||
import {
|
||||
cloudApiIndicator,
|
||||
CloudScope,
|
||||
PredefinedScope,
|
||||
adminTenantId,
|
||||
defaultTenantId,
|
||||
getManagementApiResourceIndicator,
|
||||
getManagementApiAdminName,
|
||||
adminConsoleApplicationId,
|
||||
InteractionEvent,
|
||||
AdminTenantRole,
|
||||
type Role,
|
||||
type User,
|
||||
} from '@logto/schemas';
|
||||
import { conditionalArray } from '@silverhand/essentials';
|
||||
|
||||
import { authedAdminTenantApi as api, adminTenantApi } from '#src/api/api.js';
|
||||
import type { InteractionPayload } from '#src/api/interaction.js';
|
||||
|
@ -25,7 +31,7 @@ export const createResponseWithCode = (statusCode: number) => ({
|
|||
response: { statusCode },
|
||||
});
|
||||
|
||||
export const createUserWithAllRoles = async () => {
|
||||
const createUserWithRoles = async (roleNames: string[]) => {
|
||||
const username = generateUsername();
|
||||
const password = generatePassword();
|
||||
const user = await api
|
||||
|
@ -37,16 +43,24 @@ export const createUserWithAllRoles = async () => {
|
|||
// Should have roles for default tenant Management API and admin tenant Me API
|
||||
const roles = await api.get('roles').json<Role[]>();
|
||||
await Promise.all(
|
||||
roles.map(async ({ id }) =>
|
||||
api.post(`roles/${id}/users`, {
|
||||
json: { userIds: [user.id] },
|
||||
})
|
||||
)
|
||||
roles
|
||||
.filter(({ name }) => roleNames.includes(name))
|
||||
.map(async ({ id }) =>
|
||||
api.post(`roles/${id}/users`, {
|
||||
json: { userIds: [user.id] },
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
return [user, { username, password }] as const;
|
||||
};
|
||||
|
||||
export const createUserWithAllRoles = async () => {
|
||||
const allRoles = await api.get('roles').json<Role[]>();
|
||||
const allRoleNames = allRoles.map(({ name }) => name);
|
||||
return createUserWithRoles(allRoleNames);
|
||||
};
|
||||
|
||||
export const deleteUser = async (id: string) => {
|
||||
await api.delete(`users/${id}`);
|
||||
};
|
||||
|
@ -86,7 +100,7 @@ export const initClientAndSignIn = async (
|
|||
return client;
|
||||
};
|
||||
|
||||
export const createUserAndSignInWithClient = async () => {
|
||||
export const createUserWithAllRolesAndSignInToClient = async () => {
|
||||
const [{ id }, { username, password }] = await createUserWithAllRoles();
|
||||
const client = await initClientAndSignIn(username, password, {
|
||||
resources: [resourceDefault, resourceMe],
|
||||
|
@ -95,3 +109,20 @@ export const createUserAndSignInWithClient = async () => {
|
|||
|
||||
return { id, client };
|
||||
};
|
||||
|
||||
export const createUserAndSignInToCloudClient = async (
|
||||
userRoleType: AdminTenantRole.User | AdminTenantRole.Admin
|
||||
) => {
|
||||
const [{ id }, { username, password }] = await createUserWithRoles(
|
||||
conditionalArray<string>(
|
||||
AdminTenantRole.User,
|
||||
userRoleType === AdminTenantRole.Admin && getManagementApiAdminName(adminTenantId)
|
||||
)
|
||||
);
|
||||
const client = await initClientAndSignIn(username, password, {
|
||||
resources: [cloudApiIndicator],
|
||||
scopes: Object.values(CloudScope),
|
||||
});
|
||||
|
||||
return { id, client };
|
||||
};
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
import {
|
||||
cloudApiIndicator,
|
||||
CloudScope,
|
||||
AdminTenantRole,
|
||||
type Resource,
|
||||
type Scope,
|
||||
type Role,
|
||||
} from '@logto/schemas';
|
||||
|
||||
import { authedAdminTenantApi } from '#src/api/api.js';
|
||||
import { createTenant, getTenants } from '#src/api/tenant.js';
|
||||
import { createUserAndSignInToCloudClient } from '#src/helpers/admin-tenant.js';
|
||||
|
||||
describe('Tenant APIs', () => {
|
||||
it('should be able to create multiple tenants for `admin` role', async () => {
|
||||
const { client } = await createUserAndSignInToCloudClient(AdminTenantRole.Admin);
|
||||
const accessToken = await client.getAccessToken(cloudApiIndicator);
|
||||
const tenant1 = await createTenant(accessToken);
|
||||
const tenant2 = await createTenant(accessToken);
|
||||
expect(tenant1).toHaveProperty('id');
|
||||
expect(tenant2).toHaveProperty('id');
|
||||
const tenants = await getTenants(accessToken);
|
||||
expect(tenants.length).toBeGreaterThan(2);
|
||||
expect(tenants.find((tenant) => tenant.id === tenant1.id)).toBeDefined();
|
||||
expect(tenants.find((tenant) => tenant.id === tenant2.id)).toBeDefined();
|
||||
});
|
||||
|
||||
it('should create only one tenant for `user` role', async () => {
|
||||
const { client } = await createUserAndSignInToCloudClient(AdminTenantRole.User);
|
||||
const accessToken = await client.getAccessToken(cloudApiIndicator);
|
||||
const tenant1 = await createTenant(accessToken);
|
||||
await expect(createTenant(accessToken)).rejects.toThrow();
|
||||
expect(tenant1).toHaveProperty('id');
|
||||
const tenants = await getTenants(accessToken);
|
||||
expect(tenants.length).toEqual(1);
|
||||
expect(tenants.find((tenant) => tenant.id === tenant1.id)).toBeDefined();
|
||||
});
|
||||
|
||||
it('`user` role should have `CloudScope.ManageTenantSelf` scope', async () => {
|
||||
const resources = await authedAdminTenantApi.get('resources').json<Resource[]>();
|
||||
const cloudApiResource = resources.find(({ indicator }) => indicator === cloudApiIndicator);
|
||||
expect(cloudApiResource).toBeDefined();
|
||||
const scopes = await authedAdminTenantApi
|
||||
.get(`resources/${cloudApiResource!.id}/scopes`)
|
||||
.json<Scope[]>();
|
||||
const manageOwnTenantScope = scopes.find((scope) => scope.name === CloudScope.ManageTenantSelf);
|
||||
expect(manageOwnTenantScope).toBeDefined();
|
||||
const roles = await authedAdminTenantApi.get('roles').json<Role[]>();
|
||||
const userRole = roles.find(({ name }) => name === 'user');
|
||||
expect(userRole).toBeDefined();
|
||||
const roleScopes = await authedAdminTenantApi
|
||||
.get(`roles/${userRole!.id}/scopes`)
|
||||
.json<Scope[]>();
|
||||
expect(roleScopes.find(({ id }) => id === manageOwnTenantScope!.id)).toBeDefined();
|
||||
});
|
||||
});
|
|
@ -3,7 +3,7 @@ import { got } from 'got';
|
|||
import { logtoConsoleUrl, logtoUrl } from '#src/constants.js';
|
||||
import {
|
||||
createResponseWithCode,
|
||||
createUserAndSignInWithClient,
|
||||
createUserWithAllRolesAndSignInToClient,
|
||||
deleteUser,
|
||||
resourceDefault,
|
||||
resourceMe,
|
||||
|
@ -22,7 +22,7 @@ describe('me', () => {
|
|||
});
|
||||
|
||||
it('should only recognize the access token with correct resource and scope', async () => {
|
||||
const { id, client } = await createUserAndSignInWithClient();
|
||||
const { id, client } = await createUserWithAllRolesAndSignInToClient();
|
||||
|
||||
await expect(
|
||||
got.get(logtoConsoleUrl + '/me/custom-data', {
|
||||
|
@ -40,7 +40,7 @@ describe('me', () => {
|
|||
});
|
||||
|
||||
it('should be able to update custom data', async () => {
|
||||
const { id, client } = await createUserAndSignInWithClient();
|
||||
const { id, client } = await createUserWithAllRolesAndSignInToClient();
|
||||
const headers = { authorization: `Bearer ${await client.getAccessToken(resourceMe)}` };
|
||||
|
||||
const data = await got
|
||||
|
|
|
@ -29,7 +29,7 @@ describe('get access token', () => {
|
|||
it('can sign in and getAccessToken with admin user', async () => {
|
||||
const client = new MockClient({
|
||||
resources: [defaultManagementApi.resource.indicator],
|
||||
scopes: [defaultManagementApi.scope.name],
|
||||
scopes: defaultManagementApi.scopes.map(({ name }) => name),
|
||||
});
|
||||
await client.initSession();
|
||||
await client.successSend(putInteraction, {
|
||||
|
@ -42,7 +42,7 @@ describe('get access token', () => {
|
|||
expect(accessToken).not.toBeNull();
|
||||
expect(getAccessTokenPayload(accessToken)).toHaveProperty(
|
||||
'scope',
|
||||
defaultManagementApi.scope.name
|
||||
defaultManagementApi.scopes.map(({ name }) => name).join(' ')
|
||||
);
|
||||
|
||||
// Request for invalid resource should throw
|
||||
|
@ -52,7 +52,7 @@ describe('get access token', () => {
|
|||
it('can sign in and getAccessToken with guest user', async () => {
|
||||
const client = new MockClient({
|
||||
resources: [defaultManagementApi.resource.indicator],
|
||||
scopes: [defaultManagementApi.scope.name],
|
||||
scopes: defaultManagementApi.scopes.map(({ name }) => name),
|
||||
});
|
||||
await client.initSession();
|
||||
await client.successSend(putInteraction, {
|
||||
|
@ -65,7 +65,7 @@ describe('get access token', () => {
|
|||
|
||||
expect(getAccessTokenPayload(accessToken)).not.toHaveProperty(
|
||||
'scope',
|
||||
defaultManagementApi.scope.name
|
||||
defaultManagementApi.scopes.map(({ name }) => name).join(' ')
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ describe('scopes', () => {
|
|||
it('should get management api resource scopes successfully', async () => {
|
||||
const scopes = await getScopes(defaultManagementApi.resource.id);
|
||||
|
||||
expect(scopes[0]).toMatchObject(defaultManagementApi.scope);
|
||||
expect(scopes[0]).toMatchObject(expect.objectContaining(defaultManagementApi.scopes[0]));
|
||||
});
|
||||
|
||||
it('should create scope successfully', async () => {
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
import { generateStandardId } from '@logto/shared/universal';
|
||||
import { sql } from 'slonik';
|
||||
|
||||
import type { AlterationScript } from '../lib/types/alteration.js';
|
||||
|
||||
const adminTenantId = 'admin';
|
||||
|
||||
const alteration: AlterationScript = {
|
||||
up: async (pool) => {
|
||||
// Get `resourceId` of the admin tenant's resource whose indicator is `https://cloud.logto.io/api`.
|
||||
const { id: resourceId } = await pool.one<{ id: string }>(sql`
|
||||
select id from resources
|
||||
where tenant_id = ${adminTenantId}
|
||||
and indicator = 'https://cloud.logto.io/api'
|
||||
`);
|
||||
|
||||
// Get `roleId` of the admin tenant's role whose name is `user`.
|
||||
const { id: roleId } = await pool.one<{ id: string }>(sql`
|
||||
select id from roles
|
||||
where tenant_id = ${adminTenantId}
|
||||
and name = 'user';
|
||||
`);
|
||||
|
||||
// Insert `manage:tenant:self` scope.
|
||||
const scopeId = generateStandardId();
|
||||
await pool.query(sql`
|
||||
insert into scopes (tenant_id, id, name, description, resource_id)
|
||||
values (
|
||||
${adminTenantId},
|
||||
${scopeId},
|
||||
'manage:tenant:self',
|
||||
'Allow managing tenant itself, including update and delete.',
|
||||
${resourceId}
|
||||
);
|
||||
`);
|
||||
// Assign `manage:tenant:self` scope to `user` role.
|
||||
await pool.query(sql`
|
||||
insert into roles_scopes (tenant_id, id, role_id, scope_id)
|
||||
values (
|
||||
${adminTenantId},
|
||||
${generateStandardId()},
|
||||
${roleId},
|
||||
${scopeId}
|
||||
);
|
||||
`);
|
||||
},
|
||||
down: async (pool) => {
|
||||
// Delete `manage:tenant:self` scope.
|
||||
// No need to delete `roles_scopes` because it will be cascade deleted.
|
||||
await pool.query(sql`
|
||||
delete from scopes
|
||||
where tenant_id = ${adminTenantId} and name = 'manage:tenant:self';
|
||||
`);
|
||||
},
|
||||
};
|
||||
export default alteration;
|
|
@ -10,8 +10,12 @@ import { adminTenantId } from './tenant.js';
|
|||
export const cloudApiIndicator = 'https://cloud.logto.io/api';
|
||||
|
||||
export enum CloudScope {
|
||||
/** The user can create a user tenant. */
|
||||
CreateTenant = 'create:tenant',
|
||||
/** The user can perform arbitrary operations on any tenant. */
|
||||
ManageTenant = 'manage:tenant',
|
||||
/** The user can update or delete its own tenants. */
|
||||
ManageTenantSelf = 'manage:tenant:self',
|
||||
SendSms = 'send:sms',
|
||||
SendEmail = 'send:email',
|
||||
}
|
||||
|
@ -34,7 +38,13 @@ export const createCloudApi = (): Readonly<[UpdateAdminData, ...CreateScope[]]>
|
|||
indicator: cloudApiIndicator,
|
||||
name: `Logto Cloud API`,
|
||||
},
|
||||
scope: buildScope(CloudScope.CreateTenant, 'Allow creating new tenants.'),
|
||||
scopes: [
|
||||
buildScope(CloudScope.CreateTenant, 'Allow creating new tenants.'),
|
||||
buildScope(
|
||||
CloudScope.ManageTenantSelf,
|
||||
'Allow managing tenant itself, including update and delete.'
|
||||
),
|
||||
],
|
||||
role: {
|
||||
tenantId: adminTenantId,
|
||||
name: AdminTenantRole.User,
|
||||
|
|
|
@ -7,7 +7,7 @@ import { adminTenantId, defaultTenantId } from './tenant.js';
|
|||
|
||||
export type AdminData = {
|
||||
resource: CreateResource;
|
||||
scope: CreateScope;
|
||||
scopes: CreateScope[];
|
||||
role: CreateRole;
|
||||
};
|
||||
|
||||
|
@ -35,15 +35,17 @@ export const defaultManagementApi = Object.freeze({
|
|||
indicator: `https://${defaultTenantId}.logto.app/api`,
|
||||
name: 'Logto Management API',
|
||||
},
|
||||
scope: {
|
||||
tenantId: defaultTenantId,
|
||||
/** @deprecated You should not rely on this constant. Change to something else. */
|
||||
id: defaultScopeAllId,
|
||||
name: PredefinedScope.All,
|
||||
description: 'Default scope for Management API, allows all permissions.',
|
||||
/** @deprecated You should not rely on this constant. Change to something else. */
|
||||
resourceId: defaultResourceId,
|
||||
},
|
||||
scopes: [
|
||||
{
|
||||
tenantId: defaultTenantId,
|
||||
/** @deprecated You should not rely on this constant. Change to something else. */
|
||||
id: defaultScopeAllId,
|
||||
name: PredefinedScope.All,
|
||||
description: 'Default scope for Management API, allows all permissions.',
|
||||
/** @deprecated You should not rely on this constant. Change to something else. */
|
||||
resourceId: defaultResourceId,
|
||||
},
|
||||
],
|
||||
role: {
|
||||
tenantId: defaultTenantId,
|
||||
/** @deprecated You should not rely on this constant. Change to something else. */
|
||||
|
@ -79,13 +81,15 @@ export const createAdminData = (tenantId: string): AdminData => {
|
|||
indicator: getManagementApiResourceIndicator(tenantId),
|
||||
name: `Logto Management API`,
|
||||
},
|
||||
scope: {
|
||||
tenantId,
|
||||
id: generateStandardId(),
|
||||
name: PredefinedScope.All,
|
||||
description: 'Default scope for Management API, allows all permissions.',
|
||||
resourceId,
|
||||
},
|
||||
scopes: [
|
||||
{
|
||||
tenantId,
|
||||
id: generateStandardId(),
|
||||
name: PredefinedScope.All,
|
||||
description: 'Default scope for Management API, allows all permissions.',
|
||||
resourceId,
|
||||
},
|
||||
],
|
||||
role: {
|
||||
tenantId,
|
||||
id: generateStandardId(),
|
||||
|
@ -106,13 +110,15 @@ export const createAdminDataInAdminTenant = (tenantId: string): AdminData => {
|
|||
indicator: getManagementApiResourceIndicator(tenantId),
|
||||
name: `Logto Management API for tenant ${tenantId}`,
|
||||
},
|
||||
scope: {
|
||||
tenantId: adminTenantId,
|
||||
id: generateStandardId(),
|
||||
name: PredefinedScope.All,
|
||||
description: 'Default scope for Management API, allows all permissions.',
|
||||
resourceId,
|
||||
},
|
||||
scopes: [
|
||||
{
|
||||
tenantId: adminTenantId,
|
||||
id: generateStandardId(),
|
||||
name: PredefinedScope.All,
|
||||
description: 'Default scope for Management API, allows all permissions.',
|
||||
resourceId,
|
||||
},
|
||||
],
|
||||
role: {
|
||||
tenantId: adminTenantId,
|
||||
id: generateStandardId(),
|
||||
|
@ -132,13 +138,15 @@ export const createMeApiInAdminTenant = (): AdminData => {
|
|||
indicator: getManagementApiResourceIndicator(adminTenantId, 'me'),
|
||||
name: `Logto Me API`,
|
||||
},
|
||||
scope: {
|
||||
tenantId: adminTenantId,
|
||||
id: generateStandardId(),
|
||||
name: PredefinedScope.All,
|
||||
description: 'Default scope for Me API, allows all permissions.',
|
||||
resourceId,
|
||||
},
|
||||
scopes: [
|
||||
{
|
||||
tenantId: adminTenantId,
|
||||
id: generateStandardId(),
|
||||
name: PredefinedScope.All,
|
||||
description: 'Default scope for Me API, allows all permissions.',
|
||||
resourceId,
|
||||
},
|
||||
],
|
||||
role: {
|
||||
tenantId: adminTenantId,
|
||||
id: generateStandardId(),
|
||||
|
|
Loading…
Reference in a new issue